[LineEndings] Fix them all

This commit is contained in:
momo5502
2017-01-19 22:23:59 +01:00
parent 07b0a42f45
commit 74b34f2a6d
150 changed files with 28075 additions and 28072 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,70 +1,70 @@
#ifndef DEBUG #ifndef DEBUG
// Hide AntiCheat in embeded symbol names // Hide AntiCheat in embeded symbol names
#define AntiCheat SubComponent #define AntiCheat SubComponent
#endif #endif
namespace Components namespace Components
{ {
class AntiCheat : public Component class AntiCheat : public Component
{ {
public: public:
AntiCheat(); AntiCheat();
~AntiCheat(); ~AntiCheat();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "AntiCheat"; }; const char* getName() { return "AntiCheat"; };
#endif #endif
static void CrashClient(); static void CrashClient();
static void InitLoadLibHook(); static void InitLoadLibHook();
static void ReadIntegrityCheck(); static void ReadIntegrityCheck();
static void ScanIntegrityCheck(); static void ScanIntegrityCheck();
static void FlagIntegrityCheck(); static void FlagIntegrityCheck();
private: private:
enum IntergrityFlag enum IntergrityFlag
{ {
NO_FLAG = (0), NO_FLAG = (0),
INITIALIZATION = (1 << 0), INITIALIZATION = (1 << 0),
MEMORY_SCAN = (1 << 1), MEMORY_SCAN = (1 << 1),
SCAN_INTEGRITY_CHECK = (1 << 2), SCAN_INTEGRITY_CHECK = (1 << 2),
READ_INTEGRITY_CHECK = (1 << 3), READ_INTEGRITY_CHECK = (1 << 3),
MAX_FLAG, MAX_FLAG,
}; };
static Utils::Time::Interval LastCheck; static Utils::Time::Interval LastCheck;
static std::string Hash; static std::string Hash;
static unsigned long Flags; static unsigned long Flags;
static void PerformScan(); static void PerformScan();
static void PatchWinAPI(); static void PatchWinAPI();
static unsigned long ProtectProcess(); static unsigned long ProtectProcess();
static void NullSub(); static void NullSub();
static void AssertCalleeModule(void* callee); static void AssertCalleeModule(void* callee);
static void UninstallLibHook(); static void UninstallLibHook();
static void InstallLibHook(); static void InstallLibHook();
#ifdef DEBUG_LOAD_LIBRARY #ifdef DEBUG_LOAD_LIBRARY
static HANDLE LoadLibary(std::wstring library, void* callee); static HANDLE LoadLibary(std::wstring library, void* callee);
static HANDLE WINAPI LoadLibaryAStub(const char* library); static HANDLE WINAPI LoadLibaryAStub(const char* library);
static HANDLE WINAPI LoadLibaryWStub(const wchar_t* library); static HANDLE WINAPI LoadLibaryWStub(const wchar_t* library);
#endif #endif
static void LostD3DStub(); static void LostD3DStub();
static void CinematicStub(); static void CinematicStub();
static void SoundInitStub(int a1, int a2, int a3); static void SoundInitStub(int a1, int a2, int a3);
static void SoundInitDriverStub(); static void SoundInitDriverStub();
static void DObjGetWorldTagPosStub(); static void DObjGetWorldTagPosStub();
static void AimTargetGetTagPosStub(); static void AimTargetGetTagPosStub();
static Utils::Hook LoadLibHook[4]; static Utils::Hook LoadLibHook[4];
}; };
} }

View File

@ -1,116 +1,116 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Game::newMapArena_t ArenaLength::NewArenas[128]; Game::newMapArena_t ArenaLength::NewArenas[128];
__declspec(naked) void ArenaLength::ArenaMapOffsetHook1() __declspec(naked) void ArenaLength::ArenaMapOffsetHook1()
{ {
__asm __asm
{ {
lea eax, [esi + Game::newMapArena_t::mapName] lea eax, [esi + Game::newMapArena_t::mapName]
push eax push eax
push ebx push ebx
push 420725h push 420725h
retn retn
} }
} }
__declspec(naked) void ArenaLength::ArenaMapOffsetHook2() __declspec(naked) void ArenaLength::ArenaMapOffsetHook2()
{ {
__asm __asm
{ {
lea eax, [edi + Game::newMapArena_t::mapName] lea eax, [edi + Game::newMapArena_t::mapName]
push eax push eax
push edx push edx
push 49BD3Eh push 49BD3Eh
retn retn
} }
} }
__declspec(naked) void ArenaLength::ArenaMapOffsetHook3() __declspec(naked) void ArenaLength::ArenaMapOffsetHook3()
{ {
__asm __asm
{ {
lea eax, [esi + Game::newMapArena_t::mapName] lea eax, [esi + Game::newMapArena_t::mapName]
push eax push eax
push edx push edx
push 63279Eh push 63279Eh
retn retn
} }
} }
__declspec(naked) void ArenaLength::ArenaMapOffsetHook4() __declspec(naked) void ArenaLength::ArenaMapOffsetHook4()
{ {
__asm __asm
{ {
lea edi, [esi - Game::newMapArena_t::mapName] lea edi, [esi - Game::newMapArena_t::mapName]
lea edx, [eax + 1] lea edx, [eax + 1]
push 4064B8h push 4064B8h
retn retn
} }
} }
ArenaLength::ArenaLength() ArenaLength::ArenaLength()
{ {
// Reallocate array // Reallocate array
Utils::Hook::Set<Game::newMapArena_t*>(0x417807, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x417807, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x420717, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x420717, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x632782, &ArenaLength::NewArenas[0]); Utils::Hook::Set<Game::newMapArena_t*>(0x632782, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<char*>(0x4A967A, ArenaLength::NewArenas[0].description); Utils::Hook::Set<char*>(0x4A967A, ArenaLength::NewArenas[0].description);
Utils::Hook::Set<char*>(0x4A96AD, ArenaLength::NewArenas[0].mapimage); Utils::Hook::Set<char*>(0x4A96AD, ArenaLength::NewArenas[0].mapimage);
Utils::Hook::Set<char*>(0x4A9616, ArenaLength::NewArenas[0].mapName); Utils::Hook::Set<char*>(0x4A9616, ArenaLength::NewArenas[0].mapName);
Utils::Hook::Set<char*>(0x4A9703, ArenaLength::NewArenas[0].mapName); Utils::Hook::Set<char*>(0x4A9703, ArenaLength::NewArenas[0].mapName);
Utils::Hook::Set<char*>(0x4064A8, ArenaLength::NewArenas[0].mapName); Utils::Hook::Set<char*>(0x4064A8, ArenaLength::NewArenas[0].mapName);
Utils::Hook::Set<char*>(0x42F214, &ArenaLength::NewArenas[0].other[0]); Utils::Hook::Set<char*>(0x42F214, &ArenaLength::NewArenas[0].other[0]);
Utils::Hook::Set<char*>(0x4A96ED, &ArenaLength::NewArenas[0].other[0x8]); Utils::Hook::Set<char*>(0x4A96ED, &ArenaLength::NewArenas[0].other[0x8]);
Utils::Hook::Set<char*>(0x4A9769, &ArenaLength::NewArenas[0].other[0x8]); Utils::Hook::Set<char*>(0x4A9769, &ArenaLength::NewArenas[0].other[0x8]);
Utils::Hook::Set<char*>(0x4A97A5, &ArenaLength::NewArenas[0].other[0x8]); Utils::Hook::Set<char*>(0x4A97A5, &ArenaLength::NewArenas[0].other[0x8]);
Utils::Hook::Set<char*>(0x631E92, &ArenaLength::NewArenas[0].other[0x8C]); Utils::Hook::Set<char*>(0x631E92, &ArenaLength::NewArenas[0].other[0x8C]);
// Resize the array // Resize the array
Utils::Hook::Set<int>(0x4064DE, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4064DE, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x417802, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x417802, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x420736, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x420736, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x42F271, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x42F271, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x49BD4F, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x49BD4F, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A960C, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A960C, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A963F, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A963F, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A9675, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A9675, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A96A3, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A96A3, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A96E7, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A96E7, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A96FD, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A96FD, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A975A, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A975A, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A979F, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A979F, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4A97BC, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4A97BC, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x4D0779, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x4D0779, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x630B29, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x630B29, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x630B81, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x630B81, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x631EBC, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x631EBC, sizeof(Game::newMapArena_t));
Utils::Hook::Set<int>(0x6327AF, sizeof(Game::newMapArena_t)); Utils::Hook::Set<int>(0x6327AF, sizeof(Game::newMapArena_t));
Utils::Hook(0x420720, ArenaLength::ArenaMapOffsetHook1, HOOK_JUMP).install()->quick(); Utils::Hook(0x420720, ArenaLength::ArenaMapOffsetHook1, HOOK_JUMP).install()->quick();
Utils::Hook(0x49BD39, ArenaLength::ArenaMapOffsetHook2, HOOK_JUMP).install()->quick(); Utils::Hook(0x49BD39, ArenaLength::ArenaMapOffsetHook2, HOOK_JUMP).install()->quick();
Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick(); Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick();
Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick(); Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick();
Utils::Hook::Set<BYTE>(0x4A95F8, 32); Utils::Hook::Set<BYTE>(0x4A95F8, 32);
Utils::Hook::Set<int>(0x42F22B, offsetof(Game::newMapArena_t, mapName) - offsetof(Game::newMapArena_t, other)); Utils::Hook::Set<int>(0x42F22B, offsetof(Game::newMapArena_t, mapName) - offsetof(Game::newMapArena_t, other));
} }
} }

View File

@ -1,20 +1,20 @@
namespace Components namespace Components
{ {
class ArenaLength : public Component class ArenaLength : public Component
{ {
public: public:
ArenaLength(); ArenaLength();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "ArenaLength"; }; const char* getName() { return "ArenaLength"; };
#endif #endif
static Game::newMapArena_t NewArenas[128]; static Game::newMapArena_t NewArenas[128];
private: private:
static void ArenaMapOffsetHook1(); static void ArenaMapOffsetHook1();
static void ArenaMapOffsetHook2(); static void ArenaMapOffsetHook2();
static void ArenaMapOffsetHook3(); static void ArenaMapOffsetHook3();
static void ArenaMapOffsetHook4(); static void ArenaMapOffsetHook4();
}; };
} }

View File

@ -1,439 +1,439 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
thread_local bool AssetHandler::BypassState; thread_local bool AssetHandler::BypassState;
std::map<Game::XAssetType, AssetHandler::IAsset*> AssetHandler::AssetInterfaces; std::map<Game::XAssetType, AssetHandler::IAsset*> AssetHandler::AssetInterfaces;
std::map<Game::XAssetType, Utils::Slot<AssetHandler::Callback>> AssetHandler::TypeCallbacks; std::map<Game::XAssetType, Utils::Slot<AssetHandler::Callback>> AssetHandler::TypeCallbacks;
Utils::Signal<AssetHandler::RestrictCallback> AssetHandler::RestrictSignal; Utils::Signal<AssetHandler::RestrictCallback> AssetHandler::RestrictSignal;
std::map<void*, void*> AssetHandler::Relocations; std::map<void*, void*> AssetHandler::Relocations;
std::vector<std::pair<Game::XAssetType, std::string>> AssetHandler::EmptyAssets; std::vector<std::pair<Game::XAssetType, std::string>> AssetHandler::EmptyAssets;
std::map<std::string, Game::XAssetHeader> AssetHandler::TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT]; std::map<std::string, Game::XAssetHeader> AssetHandler::TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT];
void AssetHandler::RegisterInterface(IAsset* iAsset) void AssetHandler::RegisterInterface(IAsset* iAsset)
{ {
if (!iAsset) return; if (!iAsset) return;
if (iAsset->getType() == Game::XAssetType::ASSET_TYPE_INVALID) if (iAsset->getType() == Game::XAssetType::ASSET_TYPE_INVALID)
{ {
delete iAsset; delete iAsset;
return; return;
} }
if (AssetHandler::AssetInterfaces.find(iAsset->getType()) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.find(iAsset->getType()) != AssetHandler::AssetInterfaces.end())
{ {
Logger::Print("Duplicate asset interface: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType())); Logger::Print("Duplicate asset interface: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
delete AssetHandler::AssetInterfaces[iAsset->getType()]; delete AssetHandler::AssetInterfaces[iAsset->getType()];
} }
else else
{ {
Logger::Print("Asset interface registered: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType())); Logger::Print("Asset interface registered: %s\n", Game::DB_GetXAssetTypeName(iAsset->getType()));
} }
AssetHandler::AssetInterfaces[iAsset->getType()] = iAsset; AssetHandler::AssetInterfaces[iAsset->getType()] = iAsset;
} }
void AssetHandler::ClearTemporaryAssets() void AssetHandler::ClearTemporaryAssets()
{ {
for (int i = 0; i < Game::XAssetType::ASSET_TYPE_COUNT; ++i) for (int i = 0; i < Game::XAssetType::ASSET_TYPE_COUNT; ++i)
{ {
AssetHandler::TemporaryAssets[i].clear(); AssetHandler::TemporaryAssets[i].clear();
} }
} }
void AssetHandler::StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset) void AssetHandler::StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset)
{ {
AssetHandler::TemporaryAssets[type][Game::DB_GetXAssetNameHandlers[type](&asset)] = asset; AssetHandler::TemporaryAssets[type][Game::DB_GetXAssetNameHandlers[type](&asset)] = asset;
} }
Game::XAssetHeader AssetHandler::FindAsset(Game::XAssetType type, const char* filename) Game::XAssetHeader AssetHandler::FindAsset(Game::XAssetType type, const char* filename)
{ {
Game::XAssetHeader header = { 0 }; Game::XAssetHeader header = { 0 };
if (filename) if (filename)
{ {
// Allow call DB_FindXAssetHeader within the hook // Allow call DB_FindXAssetHeader within the hook
AssetHandler::BypassState = true; AssetHandler::BypassState = true;
if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end()) if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end())
{ {
header = AssetHandler::TypeCallbacks[type](type, filename); header = AssetHandler::TypeCallbacks[type](type, filename);
} }
// Disallow calling DB_FindXAssetHeader ;) // Disallow calling DB_FindXAssetHeader ;)
AssetHandler::BypassState = false; AssetHandler::BypassState = false;
} }
return header; return header;
} }
int AssetHandler::HasThreadBypass() int AssetHandler::HasThreadBypass()
{ {
return AssetHandler::BypassState & 1; return AssetHandler::BypassState & 1;
} }
__declspec(naked) void AssetHandler::FindAssetStub() __declspec(naked) void AssetHandler::FindAssetStub()
{ {
__asm __asm
{ {
push ecx push ecx
push ebx push ebx
push ebp push ebp
push esi push esi
push edi push edi
// Check if custom handler should be bypassed // Check if custom handler should be bypassed
call AssetHandler::HasThreadBypass call AssetHandler::HasThreadBypass
test al, al test al, al
jnz finishOriginal jnz finishOriginal
mov ecx, [esp + 18h] // Asset type mov ecx, [esp + 18h] // Asset type
mov ebx, [esp + 1Ch] // Filename mov ebx, [esp + 1Ch] // Filename
push ebx push ebx
push ecx push ecx
call AssetHandler::FindAsset call AssetHandler::FindAsset
add esp, 8h add esp, 8h
test eax, eax test eax, eax
jnz finishFound jnz finishFound
finishOriginal: finishOriginal:
// Asset not found using custom handlers, redirect to DB_FindXAssetHeader // Asset not found using custom handlers, redirect to DB_FindXAssetHeader
mov ebx, ds:6D7190h // InterlockedDecrement mov ebx, ds:6D7190h // InterlockedDecrement
mov eax, 40793Bh mov eax, 40793Bh
jmp eax jmp eax
finishFound: finishFound:
pop edi pop edi
pop esi pop esi
pop ebp pop ebp
pop ebx pop ebx
pop ecx pop ecx
retn retn
} }
} }
void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, std::string name) void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, std::string name)
{ {
if (type == Game::XAssetType::ASSET_TYPE_MATERIAL && (name == "wc/codo_ui_viewer_black_decal3" || name == "wc/codo_ui_viewer_black_decal2" || name == "wc/hint_arrows01" || name == "wc/hint_arrows02")) if (type == Game::XAssetType::ASSET_TYPE_MATERIAL && (name == "wc/codo_ui_viewer_black_decal3" || name == "wc/codo_ui_viewer_black_decal2" || name == "wc/hint_arrows01" || name == "wc/hint_arrows02"))
{ {
asset.material->sortKey = 0xE; asset.material->sortKey = 0xE;
} }
if (type == Game::XAssetType::ASSET_TYPE_VEHICLE && Zones::Version() >= VERSION_ALPHA2) if (type == Game::XAssetType::ASSET_TYPE_VEHICLE && Zones::Version() >= VERSION_ALPHA2)
{ {
asset.vehicle->weaponDef = nullptr; asset.vehicle->weaponDef = nullptr;
} }
// Fix shader const stuff // Fix shader const stuff
if (type == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 359) if (type == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 359)
{ {
for (int i = 0; i < 48; ++i) for (int i = 0; i < 48; ++i)
{ {
if (asset.techniqueSet->techniques[i]) if (asset.techniqueSet->techniques[i])
{ {
for (int j = 0; j < asset.techniqueSet->techniques[i]->numPasses; ++j) for (int j = 0; j < asset.techniqueSet->techniques[i]->numPasses; ++j)
{ {
Game::MaterialPass* pass = &asset.techniqueSet->techniques[i]->passes[j]; Game::MaterialPass* pass = &asset.techniqueSet->techniques[i]->passes[j];
for (int k = 0; k < (pass->argCount1 + pass->argCount2 + pass->argCount3); ++k) for (int k = 0; k < (pass->argCount1 + pass->argCount2 + pass->argCount3); ++k)
{ {
if (pass->argumentDef[k].type == D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_CONSTINT) if (pass->argumentDef[k].type == D3DSHADER_PARAM_REGISTER_TYPE::D3DSPR_CONSTINT)
{ {
if (pass->argumentDef[k].paramID == -28132) if (pass->argumentDef[k].paramID == -28132)
{ {
pass->argumentDef[k].paramID = 2644; pass->argumentDef[k].paramID = 2644;
} }
} }
} }
} }
} }
} }
} }
} }
bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader *asset) bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader *asset)
{ {
const char* name = Game::DB_GetXAssetNameHandlers[type](asset); const char* name = Game::DB_GetXAssetNameHandlers[type](asset);
if (!name) return false; if (!name) return false;
for (auto i = AssetHandler::EmptyAssets.begin(); i != AssetHandler::EmptyAssets.end();) for (auto i = AssetHandler::EmptyAssets.begin(); i != AssetHandler::EmptyAssets.end();)
{ {
if (i->first == type && i->second == name) if (i->first == type && i->second == name)
{ {
i = AssetHandler::EmptyAssets.erase(i); i = AssetHandler::EmptyAssets.erase(i);
} }
else else
{ {
++i; ++i;
} }
} }
if (Flags::HasFlag("entries")) if (Flags::HasFlag("entries"))
{ {
OutputDebugStringA(Utils::String::VA("%s: %d: %s\n", FastFiles::Current().data(), type, name)); OutputDebugStringA(Utils::String::VA("%s: %d: %s\n", FastFiles::Current().data(), type, name));
} }
bool restrict = false; bool restrict = false;
AssetHandler::RestrictSignal(type, *asset, name, &restrict); AssetHandler::RestrictSignal(type, *asset, name, &restrict);
if (!restrict) if (!restrict)
{ {
AssetHandler::ModifyAsset(type, *asset, name); AssetHandler::ModifyAsset(type, *asset, name);
} }
// If no slot restricts the loading, we can load the asset // If no slot restricts the loading, we can load the asset
return (!restrict); return (!restrict);
} }
__declspec(naked) void AssetHandler::AddAssetStub() __declspec(naked) void AssetHandler::AddAssetStub()
{ {
__asm __asm
{ {
push [esp + 8] push [esp + 8]
push [esp + 8] push [esp + 8]
call AssetHandler::IsAssetEligible call AssetHandler::IsAssetEligible
add esp, 08h add esp, 08h
test al, al test al, al
jz doNotLoad jz doNotLoad
mov eax, [esp + 8] mov eax, [esp + 8]
sub esp, 14h sub esp, 14h
mov ecx, 5BB657h mov ecx, 5BB657h
jmp ecx jmp ecx
doNotLoad: doNotLoad:
mov eax, [esp + 8] mov eax, [esp + 8]
retn retn
} }
} }
void AssetHandler::OnFind(Game::XAssetType type, Utils::Slot<AssetHandler::Callback> callback) void AssetHandler::OnFind(Game::XAssetType type, Utils::Slot<AssetHandler::Callback> callback)
{ {
AssetHandler::TypeCallbacks[type] = callback; AssetHandler::TypeCallbacks[type] = callback;
} }
void AssetHandler::OnLoad(Utils::Slot<AssetHandler::RestrictCallback> callback) void AssetHandler::OnLoad(Utils::Slot<AssetHandler::RestrictCallback> callback)
{ {
AssetHandler::RestrictSignal.connect(callback); AssetHandler::RestrictSignal.connect(callback);
} }
void AssetHandler::ClearRelocations() void AssetHandler::ClearRelocations()
{ {
AssetHandler::Relocations.clear(); AssetHandler::Relocations.clear();
} }
void AssetHandler::Relocate(void* start, void* to, DWORD size) void AssetHandler::Relocate(void* start, void* to, DWORD size)
{ {
for (DWORD i = 0; i < size; i += 4) for (DWORD i = 0; i < size; i += 4)
{ {
AssetHandler::Relocations[reinterpret_cast<char*>(start) + i] = reinterpret_cast<char*>(to) + i; AssetHandler::Relocations[reinterpret_cast<char*>(start) + i] = reinterpret_cast<char*>(to) + i;
} }
} }
void AssetHandler::OffsetToAlias(Utils::Stream::Offset* offset) void AssetHandler::OffsetToAlias(Utils::Stream::Offset* offset)
{ {
void* pointer = (*Game::g_streamBlocks)[offset->getUnpackedBlock()].data + offset->getUnpackedOffset(); void* pointer = (*Game::g_streamBlocks)[offset->getUnpackedBlock()].data + offset->getUnpackedOffset();
if (AssetHandler::Relocations.find(pointer) != AssetHandler::Relocations.end()) if (AssetHandler::Relocations.find(pointer) != AssetHandler::Relocations.end())
{ {
pointer = AssetHandler::Relocations[pointer]; pointer = AssetHandler::Relocations[pointer];
} }
offset->pointer = *reinterpret_cast<void**>(pointer); offset->pointer = *reinterpret_cast<void**>(pointer);
} }
void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder) void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder)
{ {
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end())
{ {
AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder); AssetHandler::AssetInterfaces[asset.type]->save(asset.header, builder);
} }
else else
{ {
Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type)); Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type));
} }
} }
void AssetHandler::ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder) void AssetHandler::ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder)
{ {
if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.find(asset.type) != AssetHandler::AssetInterfaces.end())
{ {
AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder); AssetHandler::AssetInterfaces[asset.type]->mark(asset.header, builder);
} }
else else
{ {
Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type)); Logger::Error("No interface for type '%s'!", Game::DB_GetXAssetTypeName(asset.type));
} }
} }
Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset) Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset)
{ {
Game::XAssetHeader header = { 0 }; Game::XAssetHeader header = { 0 };
if (type >= Game::XAssetType::ASSET_TYPE_COUNT) return header; if (type >= Game::XAssetType::ASSET_TYPE_COUNT) return header;
auto tempPool = &AssetHandler::TemporaryAssets[type]; auto tempPool = &AssetHandler::TemporaryAssets[type];
auto entry = tempPool->find(filename); auto entry = tempPool->find(filename);
if (entry != tempPool->end()) if (entry != tempPool->end())
{ {
return { entry->second }; return { entry->second };
} }
if (AssetHandler::AssetInterfaces.find(type) != AssetHandler::AssetInterfaces.end()) if (AssetHandler::AssetInterfaces.find(type) != AssetHandler::AssetInterfaces.end())
{ {
AssetHandler::AssetInterfaces[type]->load(&header, filename, builder); AssetHandler::AssetInterfaces[type]->load(&header, filename, builder);
if (header.data) if (header.data)
{ {
Components::AssetHandler::StoreTemporaryAsset(type, header); Components::AssetHandler::StoreTemporaryAsset(type, header);
} }
} }
if (!header.data && isSubAsset) if (!header.data && isSubAsset)
{ {
header = ZoneBuilder::GetEmptyAssetIfCommon(type, filename, builder); header = ZoneBuilder::GetEmptyAssetIfCommon(type, filename, builder);
} }
if (!header.data) if (!header.data)
{ {
header = Game::DB_FindXAssetHeader(type, filename.data()); header = Game::DB_FindXAssetHeader(type, filename.data());
if(header.data) Components::AssetHandler::StoreTemporaryAsset(type, header); // Might increase efficiency... if(header.data) Components::AssetHandler::StoreTemporaryAsset(type, header); // Might increase efficiency...
} }
return header; return header;
} }
Game::XAssetHeader AssetHandler::FindOriginalAsset(Game::XAssetType type, const char* filename) Game::XAssetHeader AssetHandler::FindOriginalAsset(Game::XAssetType type, const char* filename)
{ {
int originalState = AssetHandler::HasThreadBypass(); int originalState = AssetHandler::HasThreadBypass();
AssetHandler::BypassState = true; AssetHandler::BypassState = true;
Game::XAssetHeader header = Game::DB_FindXAssetHeader(type, filename); Game::XAssetHeader header = Game::DB_FindXAssetHeader(type, filename);
if (!originalState) AssetHandler::BypassState = false; if (!originalState) AssetHandler::BypassState = false;
return header; return header;
} }
void AssetHandler::StoreEmptyAsset(Game::XAssetType type, const char* name) void AssetHandler::StoreEmptyAsset(Game::XAssetType type, const char* name)
{ {
AssetHandler::EmptyAssets.push_back({ type, name }); AssetHandler::EmptyAssets.push_back({ type, name });
} }
__declspec(naked) void AssetHandler::StoreEmptyAssetStub() __declspec(naked) void AssetHandler::StoreEmptyAssetStub()
{ {
__asm __asm
{ {
pushad pushad
push ebx push ebx
push eax push eax
call AssetHandler::StoreEmptyAsset call AssetHandler::StoreEmptyAsset
pop eax pop eax
pop ebx pop ebx
popad popad
push 5BB290h push 5BB290h
retn retn
} }
} }
AssetHandler::AssetHandler() AssetHandler::AssetHandler()
{ {
Dvar::Register<bool>("r_noVoid", false, Game::DVAR_FLAG_SAVED, "Disable void model (red fx)"); Dvar::Register<bool>("r_noVoid", false, Game::DVAR_FLAG_SAVED, "Disable void model (red fx)");
AssetHandler::ClearTemporaryAssets(); AssetHandler::ClearTemporaryAssets();
// DB_FindXAssetHeader // DB_FindXAssetHeader
Utils::Hook(Game::DB_FindXAssetHeader, AssetHandler::FindAssetStub).install()->quick(); Utils::Hook(Game::DB_FindXAssetHeader, AssetHandler::FindAssetStub).install()->quick();
// DB_ConvertOffsetToAlias // DB_ConvertOffsetToAlias
Utils::Hook(0x4FDFA0, AssetHandler::OffsetToAlias, HOOK_JUMP).install()->quick(); Utils::Hook(0x4FDFA0, AssetHandler::OffsetToAlias, HOOK_JUMP).install()->quick();
// DB_AddXAsset // DB_AddXAsset
Utils::Hook(0x5BB650, AssetHandler::AddAssetStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x5BB650, AssetHandler::AddAssetStub, HOOK_JUMP).install()->quick();
// Store empty assets // Store empty assets
Utils::Hook(0x5BB6EC, AssetHandler::StoreEmptyAssetStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5BB6EC, AssetHandler::StoreEmptyAssetStub, HOOK_CALL).install()->quick();
// Log missing empty assets // Log missing empty assets
QuickPatch::OnFrame([] () QuickPatch::OnFrame([] ()
{ {
if (FastFiles::Ready() && !AssetHandler::EmptyAssets.empty()) if (FastFiles::Ready() && !AssetHandler::EmptyAssets.empty())
{ {
for (auto& asset : AssetHandler::EmptyAssets) for (auto& asset : AssetHandler::EmptyAssets)
{ {
Game::Sys_Error(25, reinterpret_cast<char*>(0x724428), Game::DB_GetXAssetTypeName(asset.first), asset.second.data()); Game::Sys_Error(25, reinterpret_cast<char*>(0x724428), Game::DB_GetXAssetTypeName(asset.first), asset.second.data());
} }
AssetHandler::EmptyAssets.clear(); AssetHandler::EmptyAssets.clear();
} }
}); });
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*) AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*)
{ {
if (Dvar::Var("r_noVoid").get<bool>() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void") if (Dvar::Var("r_noVoid").get<bool>() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void")
{ {
asset.model->numLods = 0; asset.model->numLods = 0;
} }
}); });
// Register asset interfaces // Register asset interfaces
if (ZoneBuilder::IsEnabled()) if (ZoneBuilder::IsEnabled())
{ {
AssetHandler::RegisterInterface(new Assets::IXModel()); AssetHandler::RegisterInterface(new Assets::IXModel());
AssetHandler::RegisterInterface(new Assets::IFxWorld()); AssetHandler::RegisterInterface(new Assets::IFxWorld());
AssetHandler::RegisterInterface(new Assets::IMapEnts()); AssetHandler::RegisterInterface(new Assets::IMapEnts());
AssetHandler::RegisterInterface(new Assets::IRawFile()); AssetHandler::RegisterInterface(new Assets::IRawFile());
AssetHandler::RegisterInterface(new Assets::IComWorld()); AssetHandler::RegisterInterface(new Assets::IComWorld());
AssetHandler::RegisterInterface(new Assets::IGfxImage()); AssetHandler::RegisterInterface(new Assets::IGfxImage());
#ifdef ENABLE_EXPERIMENTAL_MAP_CODE #ifdef ENABLE_EXPERIMENTAL_MAP_CODE
AssetHandler::RegisterInterface(new Assets::IGfxWorld()); AssetHandler::RegisterInterface(new Assets::IGfxWorld());
#endif #endif
AssetHandler::RegisterInterface(new Assets::ISndCurve()); AssetHandler::RegisterInterface(new Assets::ISndCurve());
AssetHandler::RegisterInterface(new Assets::IMaterial()); AssetHandler::RegisterInterface(new Assets::IMaterial());
#ifdef ENABLE_EXPERIMENTAL_MAP_CODE #ifdef ENABLE_EXPERIMENTAL_MAP_CODE
AssetHandler::RegisterInterface(new Assets::IclipMap_t()); AssetHandler::RegisterInterface(new Assets::IclipMap_t());
#endif #endif
AssetHandler::RegisterInterface(new Assets::IPhysPreset()); AssetHandler::RegisterInterface(new Assets::IPhysPreset());
AssetHandler::RegisterInterface(new Assets::IXAnimParts()); AssetHandler::RegisterInterface(new Assets::IXAnimParts());
AssetHandler::RegisterInterface(new Assets::IFxEffectDef()); AssetHandler::RegisterInterface(new Assets::IFxEffectDef());
AssetHandler::RegisterInterface(new Assets::IGameWorldMp()); AssetHandler::RegisterInterface(new Assets::IGameWorldMp());
AssetHandler::RegisterInterface(new Assets::IGameWorldSp()); AssetHandler::RegisterInterface(new Assets::IGameWorldSp());
AssetHandler::RegisterInterface(new Assets::IGfxLightDef()); AssetHandler::RegisterInterface(new Assets::IGfxLightDef());
AssetHandler::RegisterInterface(new Assets::ILoadedSound()); AssetHandler::RegisterInterface(new Assets::ILoadedSound());
AssetHandler::RegisterInterface(new Assets::IPhysCollmap()); AssetHandler::RegisterInterface(new Assets::IPhysCollmap());
AssetHandler::RegisterInterface(new Assets::IStringTable()); AssetHandler::RegisterInterface(new Assets::IStringTable());
AssetHandler::RegisterInterface(new Assets::IXModelSurfs()); AssetHandler::RegisterInterface(new Assets::IXModelSurfs());
AssetHandler::RegisterInterface(new Assets::ILocalizeEntry()); AssetHandler::RegisterInterface(new Assets::ILocalizeEntry());
AssetHandler::RegisterInterface(new Assets::Isnd_alias_list_t()); AssetHandler::RegisterInterface(new Assets::Isnd_alias_list_t());
AssetHandler::RegisterInterface(new Assets::IMaterialPixelShader()); AssetHandler::RegisterInterface(new Assets::IMaterialPixelShader());
AssetHandler::RegisterInterface(new Assets::IMaterialTechniqueSet()); AssetHandler::RegisterInterface(new Assets::IMaterialTechniqueSet());
AssetHandler::RegisterInterface(new Assets::IMaterialVertexShader()); AssetHandler::RegisterInterface(new Assets::IMaterialVertexShader());
AssetHandler::RegisterInterface(new Assets::IStructuredDataDefSet()); AssetHandler::RegisterInterface(new Assets::IStructuredDataDefSet());
AssetHandler::RegisterInterface(new Assets::IMaterialVertexDeclaration()); AssetHandler::RegisterInterface(new Assets::IMaterialVertexDeclaration());
} }
} }
AssetHandler::~AssetHandler() AssetHandler::~AssetHandler()
{ {
AssetHandler::ClearTemporaryAssets(); AssetHandler::ClearTemporaryAssets();
for (auto i = AssetHandler::AssetInterfaces.begin(); i != AssetHandler::AssetInterfaces.end(); ++i) for (auto i = AssetHandler::AssetInterfaces.begin(); i != AssetHandler::AssetInterfaces.end(); ++i)
{ {
delete i->second; delete i->second;
} }
AssetHandler::Relocations.clear(); AssetHandler::Relocations.clear();
AssetHandler::AssetInterfaces.clear(); AssetHandler::AssetInterfaces.clear();
AssetHandler::RestrictSignal.clear(); AssetHandler::RestrictSignal.clear();
AssetHandler::TypeCallbacks.clear(); AssetHandler::TypeCallbacks.clear();
} }
} }

View File

@ -1,99 +1,99 @@
namespace Components namespace Components
{ {
class AssetHandler : public Component class AssetHandler : public Component
{ {
public: public:
class IAsset class IAsset
{ {
public: public:
virtual ~IAsset() {}; virtual ~IAsset() {};
virtual Game::XAssetType getType() { return Game::XAssetType::ASSET_TYPE_INVALID; }; virtual Game::XAssetType getType() { return Game::XAssetType::ASSET_TYPE_INVALID; };
virtual void mark(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ }; virtual void mark(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ };
virtual void save(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ }; virtual void save(Game::XAssetHeader /*header*/, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ };
virtual void dump(Game::XAssetHeader /*header*/) { /*ErrorTypeNotSupported(this);*/ }; virtual void dump(Game::XAssetHeader /*header*/) { /*ErrorTypeNotSupported(this);*/ };
virtual void load(Game::XAssetHeader* /*header*/, std::string name, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ }; virtual void load(Game::XAssetHeader* /*header*/, std::string name, ZoneBuilder::Zone* /*builder*/) { /*ErrorTypeNotSupported(this);*/ };
}; };
typedef Game::XAssetHeader(Callback)(Game::XAssetType type, std::string name); typedef Game::XAssetHeader(Callback)(Game::XAssetType type, std::string name);
typedef void(RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict); typedef void(RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict);
AssetHandler(); AssetHandler();
~AssetHandler(); ~AssetHandler();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "AssetHandler"; }; const char* getName() { return "AssetHandler"; };
#endif #endif
static void OnFind(Game::XAssetType type, Utils::Slot<Callback> callback); static void OnFind(Game::XAssetType type, Utils::Slot<Callback> callback);
static void OnLoad(Utils::Slot<RestrictCallback> callback); static void OnLoad(Utils::Slot<RestrictCallback> callback);
static void ClearRelocations(); static void ClearRelocations();
static void Relocate(void* start, void* to, DWORD size = 4); static void Relocate(void* start, void* to, DWORD size = 4);
static void ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder); static void ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder);
static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder); static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder);
static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename); static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename);
static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset = true); static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset = true);
static void ClearTemporaryAssets(); static void ClearTemporaryAssets();
static void StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset); static void StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset);
private: private:
static thread_local bool BypassState; static thread_local bool BypassState;
static std::map<std::string, Game::XAssetHeader> TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT]; static std::map<std::string, Game::XAssetHeader> TemporaryAssets[Game::XAssetType::ASSET_TYPE_COUNT];
static std::map<Game::XAssetType, IAsset*> AssetInterfaces; static std::map<Game::XAssetType, IAsset*> AssetInterfaces;
static std::map<Game::XAssetType, Utils::Slot<Callback>> TypeCallbacks; static std::map<Game::XAssetType, Utils::Slot<Callback>> TypeCallbacks;
static Utils::Signal<RestrictCallback> RestrictSignal; static Utils::Signal<RestrictCallback> RestrictSignal;
static std::map<void*, void*> Relocations; static std::map<void*, void*> Relocations;
static std::vector<std::pair<Game::XAssetType, std::string>> EmptyAssets; static std::vector<std::pair<Game::XAssetType, std::string>> EmptyAssets;
static void RegisterInterface(IAsset* iAsset); static void RegisterInterface(IAsset* iAsset);
static Game::XAssetHeader FindAsset(Game::XAssetType type, const char* filename); static Game::XAssetHeader FindAsset(Game::XAssetType type, const char* filename);
static bool IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset); static bool IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset);
static void FindAssetStub(); static void FindAssetStub();
static void AddAssetStub(); static void AddAssetStub();
static void OffsetToAlias(Utils::Stream::Offset* offset); static void OffsetToAlias(Utils::Stream::Offset* offset);
static void StoreEmptyAsset(Game::XAssetType type, const char* name); static void StoreEmptyAsset(Game::XAssetType type, const char* name);
static void StoreEmptyAssetStub(); static void StoreEmptyAssetStub();
static void ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, std::string name); static void ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, std::string name);
static int HasThreadBypass(); static int HasThreadBypass();
}; };
} }
#include "AssetInterfaces\IXModel.hpp" #include "AssetInterfaces\IXModel.hpp"
#include "AssetInterfaces\IFxWorld.hpp" #include "AssetInterfaces\IFxWorld.hpp"
#include "AssetInterfaces\IMapEnts.hpp" #include "AssetInterfaces\IMapEnts.hpp"
#include "AssetInterfaces\IRawFile.hpp" #include "AssetInterfaces\IRawFile.hpp"
#include "AssetInterfaces\IComWorld.hpp" #include "AssetInterfaces\IComWorld.hpp"
#include "AssetInterfaces\IGfxImage.hpp" #include "AssetInterfaces\IGfxImage.hpp"
#include "AssetInterfaces\IGfxWorld.hpp" #include "AssetInterfaces\IGfxWorld.hpp"
#include "AssetInterfaces\IMaterial.hpp" #include "AssetInterfaces\IMaterial.hpp"
#include "AssetInterfaces\ISndCurve.hpp" #include "AssetInterfaces\ISndCurve.hpp"
#include "AssetInterfaces\IclipMap_t.hpp" #include "AssetInterfaces\IclipMap_t.hpp"
#include "AssetInterfaces\IPhysPreset.hpp" #include "AssetInterfaces\IPhysPreset.hpp"
#include "AssetInterfaces\IXAnimParts.hpp" #include "AssetInterfaces\IXAnimParts.hpp"
#include "AssetInterfaces\IFxEffectDef.hpp" #include "AssetInterfaces\IFxEffectDef.hpp"
#include "AssetInterfaces\IGameWorldMp.hpp" #include "AssetInterfaces\IGameWorldMp.hpp"
#include "AssetInterfaces\IGameWorldSp.hpp" #include "AssetInterfaces\IGameWorldSp.hpp"
#include "AssetInterfaces\IGfxLightDef.hpp" #include "AssetInterfaces\IGfxLightDef.hpp"
#include "AssetInterfaces\ILoadedSound.hpp" #include "AssetInterfaces\ILoadedSound.hpp"
#include "AssetInterfaces\IPhysCollmap.hpp" #include "AssetInterfaces\IPhysCollmap.hpp"
#include "AssetInterfaces\IStringTable.hpp" #include "AssetInterfaces\IStringTable.hpp"
#include "AssetInterfaces\IXModelSurfs.hpp" #include "AssetInterfaces\IXModelSurfs.hpp"
#include "AssetInterfaces\ILocalizeEntry.hpp" #include "AssetInterfaces\ILocalizeEntry.hpp"
#include "AssetInterfaces\Isnd_alias_list_t.hpp" #include "AssetInterfaces\Isnd_alias_list_t.hpp"
#include "AssetInterfaces\IMaterialPixelShader.hpp" #include "AssetInterfaces\IMaterialPixelShader.hpp"
#include "AssetInterfaces\IMaterialTechniqueSet.hpp" #include "AssetInterfaces\IMaterialTechniqueSet.hpp"
#include "AssetInterfaces\IMaterialVertexShader.hpp" #include "AssetInterfaces\IMaterialVertexShader.hpp"
#include "AssetInterfaces\IStructuredDataDefSet.hpp" #include "AssetInterfaces\IStructuredDataDefSet.hpp"
#include "AssetInterfaces\IMaterialVertexDeclaration.hpp" #include "AssetInterfaces\IMaterialVertexDeclaration.hpp"

View File

@ -1,62 +1,62 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void IComWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IComWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::ComWorld* asset = header.comWorld; Game::ComWorld* asset = header.comWorld;
if (asset->lights) if (asset->lights)
{ {
for (int i = 0; i < asset->lightCount; ++i) for (int i = 0; i < asset->lightCount; ++i)
{ {
if (asset->lights[i].name) if (asset->lights[i].name)
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_LIGHT_DEF, std::string(asset->lights[i].name), false); builder->loadAsset(Game::XAssetType::ASSET_TYPE_LIGHT_DEF, std::string(asset->lights[i].name), false);
} }
} }
} }
} }
void IComWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IComWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::ComWorld, 16); AssertSize(Game::ComWorld, 16);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::ComWorld* asset = header.comWorld; Game::ComWorld* asset = header.comWorld;
Game::ComWorld* dest = buffer->dest<Game::ComWorld>(); Game::ComWorld* dest = buffer->dest<Game::ComWorld>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->lights) if (asset->lights)
{ {
AssertSize(Game::ComPrimaryLight, 68); AssertSize(Game::ComPrimaryLight, 68);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::ComPrimaryLight* destLights = buffer->dest<Game::ComPrimaryLight>(); Game::ComPrimaryLight* destLights = buffer->dest<Game::ComPrimaryLight>();
buffer->saveArray(asset->lights, asset->lightCount); buffer->saveArray(asset->lights, asset->lightCount);
for (int i = 0; i < asset->lightCount; ++i) for (int i = 0; i < asset->lightCount; ++i)
{ {
Game::ComPrimaryLight* destLight = &destLights[i]; Game::ComPrimaryLight* destLight = &destLights[i];
Game::ComPrimaryLight* light = &asset->lights[i]; Game::ComPrimaryLight* light = &asset->lights[i];
if (light->name) if (light->name)
{ {
buffer->saveString(light->name); buffer->saveString(light->name);
Utils::Stream::ClearPointer(&destLight->name); Utils::Stream::ClearPointer(&destLight->name);
} }
} }
Utils::Stream::ClearPointer(&dest->lights); Utils::Stream::ClearPointer(&dest->lights);
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,181 +1,181 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#define IW4X_IMG_VERSION "0" #define IW4X_IMG_VERSION "0"
namespace Assets namespace Assets
{ {
void IGfxImage::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IGfxImage::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image; Game::GfxImage* image = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_IMAGE, name.data()).image;
if (image && name[0] != '*') return; if (image && name[0] != '*') return;
image = builder->getAllocator()->allocate<Game::GfxImage>(); image = builder->getAllocator()->allocate<Game::GfxImage>();
if (!image) if (!image)
{ {
Components::Logger::Error("Failed to allocate GfxImage structure!"); Components::Logger::Error("Failed to allocate GfxImage structure!");
return; return;
} }
image->name = builder->getAllocator()->duplicateString(name); image->name = builder->getAllocator()->duplicateString(name);
image->semantic = 2; image->semantic = 2;
image->category = 0; image->category = 0;
image->cardMemory = 0; image->cardMemory = 0;
const char* tempName = image->name; const char* tempName = image->name;
if (tempName[0] == '*') tempName++; if (tempName[0] == '*') tempName++;
Components::FileSystem::File imageFile(Utils::String::VA("images/%s.iw4xImage", tempName)); Components::FileSystem::File imageFile(Utils::String::VA("images/%s.iw4xImage", tempName));
if (imageFile.exists()) if (imageFile.exists())
{ {
Utils::Stream::Reader reader(builder->getAllocator(), imageFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), imageFile.getBuffer());
if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xImg" IW4X_IMG_VERSION)) if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xImg" IW4X_IMG_VERSION))
{ {
Components::Logger::Error(0, "Reading image '%s' failed, header is invalid!", name.data()); Components::Logger::Error(0, "Reading image '%s' failed, header is invalid!", name.data());
} }
AssertSize(Game::MapType, 1); AssertSize(Game::MapType, 1);
image->mapType = reader.read<Game::MapType>(); image->mapType = reader.read<Game::MapType>();
image->semantic = reader.read<char>(); image->semantic = reader.read<char>();
image->category = reader.read<char>(); image->category = reader.read<char>();
image->dataLen1 = reader.read<int>(); image->dataLen1 = reader.read<int>();
image->dataLen2 = image->dataLen1; image->dataLen2 = image->dataLen1;
image->loadDef = reinterpret_cast<Game::GfxImageLoadDef*>(reader.readArray<char>(image->dataLen1 + 16)); image->loadDef = reinterpret_cast<Game::GfxImageLoadDef*>(reader.readArray<char>(image->dataLen1 + 16));
image->height = image->loadDef->dimensions[0]; image->height = image->loadDef->dimensions[0];
image->width = image->loadDef->dimensions[1]; image->width = image->loadDef->dimensions[1];
image->depth = image->loadDef->dimensions[2]; image->depth = image->loadDef->dimensions[2];
image->loaded = true; image->loaded = true;
image->loadDef->flags = 0; image->loadDef->flags = 0;
if (Utils::String::StartsWith(name, "*lightmap")) if (Utils::String::StartsWith(name, "*lightmap"))
{ {
image->loadDef->dimensions[0] = 0; image->loadDef->dimensions[0] = 0;
image->loadDef->dimensions[1] = 2; image->loadDef->dimensions[1] = 2;
image->loadDef->dimensions[2] = 0; image->loadDef->dimensions[2] = 0;
} }
header->image = image; header->image = image;
} }
else if(name[0] != '*') else if(name[0] != '*')
{ {
char nameBuffer[MAX_PATH] = { 0 }; char nameBuffer[MAX_PATH] = { 0 };
Components::Materials::FormatImagePath(nameBuffer, sizeof(nameBuffer), 0, 0, name.data()); Components::Materials::FormatImagePath(nameBuffer, sizeof(nameBuffer), 0, 0, name.data());
Components::FileSystem::File iwi(nameBuffer); Components::FileSystem::File iwi(nameBuffer);
if (!iwi.exists()) if (!iwi.exists())
{ {
Components::Logger::Error("Loading image '%s' failed!", iwi.getName().data()); Components::Logger::Error("Loading image '%s' failed!", iwi.getName().data());
return; return;
} }
auto iwiBuffer = iwi.getBuffer(); auto iwiBuffer = iwi.getBuffer();
const Game::GfxImageFileHeader* iwiHeader = reinterpret_cast<const Game::GfxImageFileHeader*>(iwiBuffer.data()); const Game::GfxImageFileHeader* iwiHeader = reinterpret_cast<const Game::GfxImageFileHeader*>(iwiBuffer.data());
if (std::memcmp(iwiHeader->tag, "IWi", 3) && iwiHeader->version == 8) if (std::memcmp(iwiHeader->tag, "IWi", 3) && iwiHeader->version == 8)
{ {
Components::Logger::Error("Image is not a valid IWi!"); Components::Logger::Error("Image is not a valid IWi!");
return; return;
} }
image->mapType = Game::MAPTYPE_2D; image->mapType = Game::MAPTYPE_2D;
image->dataLen1 = iwiHeader->fileSizeForPicmip[0] - 32; image->dataLen1 = iwiHeader->fileSizeForPicmip[0] - 32;
image->dataLen2 = iwiHeader->fileSizeForPicmip[0] - 32; image->dataLen2 = iwiHeader->fileSizeForPicmip[0] - 32;
image->loadDef = builder->getAllocator()->allocate<Game::GfxImageLoadDef>(); image->loadDef = builder->getAllocator()->allocate<Game::GfxImageLoadDef>();
if (!image->loadDef) if (!image->loadDef)
{ {
Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!"); Components::Logger::Error("Failed to allocate GfxImageLoadDef structure!");
return; return;
} }
std::memcpy(image->loadDef->dimensions, iwiHeader->dimensions, 6); std::memcpy(image->loadDef->dimensions, iwiHeader->dimensions, 6);
image->loadDef->flags = 0; image->loadDef->flags = 0;
image->loadDef->levelCount = 0; image->loadDef->levelCount = 0;
image->height = image->loadDef->dimensions[0]; image->height = image->loadDef->dimensions[0];
image->width = image->loadDef->dimensions[1]; image->width = image->loadDef->dimensions[1];
image->depth = image->loadDef->dimensions[2]; image->depth = image->loadDef->dimensions[2];
switch (iwiHeader->format) switch (iwiHeader->format)
{ {
case Game::IWI_COMPRESSION::IWI_ARGB: case Game::IWI_COMPRESSION::IWI_ARGB:
{ {
image->loadDef->format = 21; image->loadDef->format = 21;
break; break;
} }
case Game::IWI_COMPRESSION::IWI_RGB8: case Game::IWI_COMPRESSION::IWI_RGB8:
{ {
image->loadDef->format = 20; image->loadDef->format = 20;
break; break;
} }
case Game::IWI_COMPRESSION::IWI_DXT1: case Game::IWI_COMPRESSION::IWI_DXT1:
{ {
image->loadDef->format = 0x31545844; image->loadDef->format = 0x31545844;
break; break;
} }
case Game::IWI_COMPRESSION::IWI_DXT3: case Game::IWI_COMPRESSION::IWI_DXT3:
{ {
image->loadDef->format = 0x33545844; image->loadDef->format = 0x33545844;
break; break;
} }
case Game::IWI_COMPRESSION::IWI_DXT5: case Game::IWI_COMPRESSION::IWI_DXT5:
{ {
image->loadDef->format = 0x35545844; image->loadDef->format = 0x35545844;
break; break;
} }
} }
header->image = image; header->image = image;
} }
} }
void IGfxImage::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IGfxImage::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::GfxImage, 32); AssertSize(Game::GfxImage, 32);
AssertSize(Game::MapType, 1); AssertSize(Game::MapType, 1);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::GfxImage* asset = header.image; Game::GfxImage* asset = header.image;
Game::GfxImage* dest = buffer->dest<Game::GfxImage>(); Game::GfxImage* dest = buffer->dest<Game::GfxImage>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
buffer->pushBlock(Game::XFILE_BLOCK_TEMP); buffer->pushBlock(Game::XFILE_BLOCK_TEMP);
if (asset->loadDef) if (asset->loadDef)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::GfxImageLoadDef* destTexture = buffer->dest<Game::GfxImageLoadDef>(); Game::GfxImageLoadDef* destTexture = buffer->dest<Game::GfxImageLoadDef>();
buffer->save(asset->loadDef, 16, 1); buffer->save(asset->loadDef, 16, 1);
builder->incrementExternalSize(asset->loadDef->resourceSize); builder->incrementExternalSize(asset->loadDef->resourceSize);
if (destTexture->resourceSize > 0) if (destTexture->resourceSize > 0)
{ {
buffer->save(asset->loadDef->data, asset->loadDef->resourceSize); buffer->save(asset->loadDef->data, asset->loadDef->resourceSize);
} }
Utils::Stream::ClearPointer(&dest->loadDef); Utils::Stream::ClearPointer(&dest->loadDef);
} }
buffer->popBlock(); buffer->popBlock();
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,40 +1,40 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void IGfxLightDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IGfxLightDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::GfxLightDef* asset = header.lightDef; Game::GfxLightDef* asset = header.lightDef;
if (asset->attenuation.image) if (asset->attenuation.image)
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image); builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image);
} }
} }
void IGfxLightDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IGfxLightDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::GfxLightDef, 16); AssertSize(Game::GfxLightDef, 16);
AssertSize(Game::GfxLightImage, 8); AssertSize(Game::GfxLightImage, 8);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::GfxLightDef* asset = header.lightDef; Game::GfxLightDef* asset = header.lightDef;
Game::GfxLightDef* dest = buffer->dest<Game::GfxLightDef>(); Game::GfxLightDef* dest = buffer->dest<Game::GfxLightDef>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->attenuation.image) if (asset->attenuation.image)
{ {
dest->attenuation.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image).image; dest->attenuation.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->attenuation.image).image;
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,22 @@
namespace Assets namespace Assets
{ {
class IGfxWorld : public Components::AssetHandler::IAsset class IGfxWorld : public Components::AssetHandler::IAsset
{ {
public: public:
virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GFXWORLD; }; virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_GFXWORLD; };
virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override;
virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override; virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override;
private: private:
void saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDpvsPlanes(Game::GfxWorld* world, Game::GfxWorldDpvsPlanes* asset, Game::GfxWorldDpvsPlanes* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDraw(Game::GfxWorldDraw* asset, Game::GfxWorldDraw* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxLightGrid(Game::GfxLightGrid* asset, Game::GfxLightGrid* dest, Components::ZoneBuilder::Zone* builder); void saveGfxLightGrid(Game::GfxLightGrid* asset, Game::GfxLightGrid* dest, Components::ZoneBuilder::Zone* builder);
void savesunflare_t(Game::sunflare_t* asset, Game::sunflare_t* dest, Components::ZoneBuilder::Zone* builder); void savesunflare_t(Game::sunflare_t* asset, Game::sunflare_t* dest, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Game::GfxWorldDpvsStatic* dest, int planeCount, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Game::GfxWorldDpvsStatic* dest, int planeCount, Components::ZoneBuilder::Zone* builder);
void saveGfxWorldDpvsDynamic(Game::GfxWorldDpvsDynamic* asset, Game::GfxWorldDpvsDynamic* dest, Components::ZoneBuilder::Zone* builder); void saveGfxWorldDpvsDynamic(Game::GfxWorldDpvsDynamic* asset, Game::GfxWorldDpvsDynamic* dest, Components::ZoneBuilder::Zone* builder);
void loadGfxWorldDraw(Game::GfxWorldDraw* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader); void loadGfxWorldDraw(Game::GfxWorldDraw* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader);
void loadGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader); void loadGfxWorldDpvsStatic(Game::GfxWorld* world, Game::GfxWorldDpvsStatic* asset, Components::ZoneBuilder::Zone* builder, Utils::Stream::Reader* reader);
}; };
} }

View File

@ -1,45 +1,45 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void ILoadedSound::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void ILoadedSound::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::LoadedSound, 44); AssertSize(Game::LoadedSound, 44);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::LoadedSound* asset = header.loadSnd; Game::LoadedSound* asset = header.loadSnd;
Game::LoadedSound* dest = buffer->dest<Game::LoadedSound>(); Game::LoadedSound* dest = buffer->dest<Game::LoadedSound>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
{ {
buffer->pushBlock(Game::XFILE_BLOCK_TEMP); buffer->pushBlock(Game::XFILE_BLOCK_TEMP);
if (asset->mssSound.data) if (asset->mssSound.data)
{ {
if (builder->hasPointer(asset->mssSound.data)) if (builder->hasPointer(asset->mssSound.data))
{ {
dest->mssSound.data = builder->getPointer(asset->mssSound.data); dest->mssSound.data = builder->getPointer(asset->mssSound.data);
} }
else else
{ {
builder->storePointer(asset->mssSound.data); builder->storePointer(asset->mssSound.data);
buffer->saveArray(asset->mssSound.data, asset->mssSound.size); buffer->saveArray(asset->mssSound.data, asset->mssSound.size);
Utils::Stream::ClearPointer(&dest->mssSound.data); Utils::Stream::ClearPointer(&dest->mssSound.data);
} }
} }
buffer->popBlock(); buffer->popBlock();
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,132 +1,132 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void IMapEnts::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IMapEnts::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Utils::String::Replace(name, "maps/", ""); Utils::String::Replace(name, "maps/", "");
Utils::String::Replace(name, "mp/", ""); Utils::String::Replace(name, "mp/", "");
Utils::String::Replace(name, ".d3dbsp", ""); Utils::String::Replace(name, ".d3dbsp", "");
Components::FileSystem::File ents(Utils::String::VA("mapents/%s.ents", name.c_str())); Components::FileSystem::File ents(Utils::String::VA("mapents/%s.ents", name.c_str()));
if (ents.exists()) if (ents.exists())
{ {
Game::MapEnts* entites = builder->getAllocator()->allocate<Game::MapEnts>(); Game::MapEnts* entites = builder->getAllocator()->allocate<Game::MapEnts>();
Game::MapEnts* orgEnts = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).mapEnts; Game::MapEnts* orgEnts = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).mapEnts;
// TODO: Get rid of that // TODO: Get rid of that
if (!orgEnts) if (!orgEnts)
{ {
orgEnts = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, "maps/iw4_credits.d3dbsp").mapEnts; orgEnts = Components::AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, "maps/iw4_credits.d3dbsp").mapEnts;
if (!orgEnts) if (!orgEnts)
{ {
Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_MAP_ENTS, [](Game::XAssetHeader header, void* mapEnts) Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_MAP_ENTS, [](Game::XAssetHeader header, void* mapEnts)
{ {
if (!*reinterpret_cast<void**>(mapEnts)) if (!*reinterpret_cast<void**>(mapEnts))
{ {
*reinterpret_cast<Game::MapEnts**>(mapEnts) = header.mapEnts; *reinterpret_cast<Game::MapEnts**>(mapEnts) = header.mapEnts;
} }
}, &orgEnts, false); }, &orgEnts, false);
} }
} }
if (orgEnts) if (orgEnts)
{ {
std::memcpy(entites, orgEnts, sizeof Game::MapEnts); std::memcpy(entites, orgEnts, sizeof Game::MapEnts);
} }
else else
{ {
entites->name = builder->getAllocator()->duplicateString(Utils::String::VA("maps/mp/%s.d3dbsp", name)); entites->name = builder->getAllocator()->duplicateString(Utils::String::VA("maps/mp/%s.d3dbsp", name));
entites->stageCount = 1; entites->stageCount = 1;
entites->stages = builder->getAllocator()->allocate<Game::Stage>(); entites->stages = builder->getAllocator()->allocate<Game::Stage>();
entites->stages[0].stageName = "stage 0"; entites->stages[0].stageName = "stage 0";
entites->stages[0].flags = 0x10400; entites->stages[0].flags = 0x10400;
} }
entites->entityString = builder->getAllocator()->duplicateString(ents.getBuffer()); entites->entityString = builder->getAllocator()->duplicateString(ents.getBuffer());
entites->numEntityChars = ents.getBuffer().size() + 1; entites->numEntityChars = ents.getBuffer().size() + 1;
header->mapEnts = entites; header->mapEnts = entites;
} }
} }
void IMapEnts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMapEnts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::MapEnts, 44); AssertSize(Game::MapEnts, 44);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::MapEnts* asset = header.mapEnts; Game::MapEnts* asset = header.mapEnts;
Game::MapEnts* dest = buffer->dest<Game::MapEnts>(); Game::MapEnts* dest = buffer->dest<Game::MapEnts>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->entityString) if (asset->entityString)
{ {
buffer->save(asset->entityString, asset->numEntityChars); buffer->save(asset->entityString, asset->numEntityChars);
Utils::Stream::ClearPointer(&dest->entityString); Utils::Stream::ClearPointer(&dest->entityString);
} }
AssertSize(Game::MapTriggers, 24); AssertSize(Game::MapTriggers, 24);
if (asset->trigger.models) if (asset->trigger.models)
{ {
AssertSize(Game::TriggerModel, 8); AssertSize(Game::TriggerModel, 8);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.models, asset->trigger.modelCount); buffer->saveArray(asset->trigger.models, asset->trigger.modelCount);
Utils::Stream::ClearPointer(&dest->trigger.models); Utils::Stream::ClearPointer(&dest->trigger.models);
} }
if (asset->trigger.hulls) if (asset->trigger.hulls)
{ {
AssertSize(Game::TriggerHull, 32); AssertSize(Game::TriggerHull, 32);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.hulls, asset->trigger.hullCount); buffer->saveArray(asset->trigger.hulls, asset->trigger.hullCount);
Utils::Stream::ClearPointer(&dest->trigger.hulls); Utils::Stream::ClearPointer(&dest->trigger.hulls);
} }
if (asset->trigger.slabs) if (asset->trigger.slabs)
{ {
AssertSize(Game::TriggerSlab, 20); AssertSize(Game::TriggerSlab, 20);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->trigger.slabs, asset->trigger.slabCount); buffer->saveArray(asset->trigger.slabs, asset->trigger.slabCount);
Utils::Stream::ClearPointer(&dest->trigger.slabs); Utils::Stream::ClearPointer(&dest->trigger.slabs);
} }
if (asset->stages) if (asset->stages)
{ {
AssertSize(Game::Stage, 20); AssertSize(Game::Stage, 20);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::Stage* destStages = buffer->dest<Game::Stage>(); Game::Stage* destStages = buffer->dest<Game::Stage>();
buffer->saveArray(asset->stages, asset->stageCount); buffer->saveArray(asset->stages, asset->stageCount);
for (char i = 0; i < asset->stageCount; ++i) for (char i = 0; i < asset->stageCount; ++i)
{ {
Game::Stage* destStage = &destStages[i]; Game::Stage* destStage = &destStages[i];
Game::Stage* stage = &asset->stages[i]; Game::Stage* stage = &asset->stages[i];
if (stage->stageName) if (stage->stageName)
{ {
buffer->saveString(stage->stageName); buffer->saveString(stage->stageName);
Utils::Stream::ClearPointer(&destStage->stageName); Utils::Stream::ClearPointer(&destStage->stageName);
} }
} }
Utils::Stream::ClearPointer(&dest->stages); Utils::Stream::ClearPointer(&dest->stages);
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,465 +1,465 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#define IW4X_MAT_VERSION "0" #define IW4X_MAT_VERSION "0"
namespace Assets namespace Assets
{ {
void IMaterial::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IMaterial::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
if (!header->data) this->loadJson(header, name, builder); // Check if we want to override materials if (!header->data) this->loadJson(header, name, builder); // Check if we want to override materials
if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one if (!header->data) this->loadNative(header, name, builder); // Check if there is a native one
if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game if (!header->data) this->loadBinary(header, name, builder); // Check if we need to import a new one into the game
} }
void IMaterial::loadBinary(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IMaterial::loadBinary(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File materialFile(Utils::String::VA("materials/%s.iw4xMaterial", name.data())); Components::FileSystem::File materialFile(Utils::String::VA("materials/%s.iw4xMaterial", name.data()));
if (!materialFile.exists()) return; if (!materialFile.exists()) return;
Game::Material* material = builder->getAllocator()->allocate<Game::Material>(); Game::Material* material = builder->getAllocator()->allocate<Game::Material>();
if (!material) if (!material)
{ {
Components::Logger::Print("Error allocating memory for material structure!\n"); Components::Logger::Print("Error allocating memory for material structure!\n");
return; return;
} }
Utils::Stream::Reader reader(builder->getAllocator(), materialFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), materialFile.getBuffer());
if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xMat" IW4X_MAT_VERSION)) if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xMat" IW4X_MAT_VERSION))
{ {
Components::Logger::Error(0, "Reading material '%s' failed, header is invalid!", name.data()); Components::Logger::Error(0, "Reading material '%s' failed, header is invalid!", name.data());
} }
material->name = reader.readCString(); material->name = reader.readCString();
material->gameFlags = reader.readByte(); material->gameFlags = reader.readByte();
material->sortKey = reader.readByte(); material->sortKey = reader.readByte();
material->textureAtlasRowCount = reader.readByte(); material->textureAtlasRowCount = reader.readByte();
material->textureAtlasColumnCount = reader.readByte(); material->textureAtlasColumnCount = reader.readByte();
material->drawSurf.packed = reader.read<__int64>(); material->drawSurf.packed = reader.read<__int64>();
material->surfaceTypeBits = reader.read<int>(); material->surfaceTypeBits = reader.read<int>();
material->hashIndex = reader.read<unsigned __int16>(); material->hashIndex = reader.read<unsigned __int16>();
char* stateBitsEntry = reader.readArray<char>(48); char* stateBitsEntry = reader.readArray<char>(48);
memcpy(material->stateBitsEntry, stateBitsEntry, 48); memcpy(material->stateBitsEntry, stateBitsEntry, 48);
material->textureCount = reader.readByte(); material->textureCount = reader.readByte();
material->constantCount = reader.readByte(); material->constantCount = reader.readByte();
material->stateBitsCount = reader.readByte(); material->stateBitsCount = reader.readByte();
material->stateFlags = reader.readByte(); material->stateFlags = reader.readByte();
material->cameraRegion = reader.readByte(); material->cameraRegion = reader.readByte();
std::string techset = reader.readString(); std::string techset = reader.readString();
material->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet; material->techniqueSet = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, techset.data(), builder).techniqueSet;
if (!material->techniqueSet) if (!material->techniqueSet)
{ {
Components::Logger::Error("Techset '%s' not found!", techset.data()); Components::Logger::Error("Techset '%s' not found!", techset.data());
} }
material->textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(material->textureCount & 0xFF); material->textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(material->textureCount & 0xFF);
material->constantTable = builder->getAllocator()->allocateArray<Game::MaterialConstantDef>(material->constantCount & 0xFF); material->constantTable = builder->getAllocator()->allocateArray<Game::MaterialConstantDef>(material->constantCount & 0xFF);
material->stateBitTable = builder->getAllocator()->allocateArray<Game::GfxStateBits>(material->stateBitsCount & 0xFF); material->stateBitTable = builder->getAllocator()->allocateArray<Game::GfxStateBits>(material->stateBitsCount & 0xFF);
if (!material->textureTable || !material->constantTable || !material->stateBitTable) if (!material->textureTable || !material->constantTable || !material->stateBitTable)
{ {
Components::Logger::Print("Error allocating memory for material structure!\n"); Components::Logger::Print("Error allocating memory for material structure!\n");
return; return;
} }
for (char i = 0; i < material->textureCount; ++i) for (char i = 0; i < material->textureCount; ++i)
{ {
std::string mapName = reader.readString(); std::string mapName = reader.readString();
material->textureTable[i].nameStart = mapName.front(); material->textureTable[i].nameStart = mapName.front();
material->textureTable[i].nameEnd = mapName.back(); material->textureTable[i].nameEnd = mapName.back();
material->textureTable[i].nameHash = Game::R_HashString(mapName.data()); material->textureTable[i].nameHash = Game::R_HashString(mapName.data());
material->textureTable[i].sampleState = reader.readByte(); material->textureTable[i].sampleState = reader.readByte();
material->textureTable[i].semantic = reader.readByte(); material->textureTable[i].semantic = reader.readByte();
if (material->textureTable[i].semantic == SEMANTIC_WATER_MAP) if (material->textureTable[i].semantic == SEMANTIC_WATER_MAP)
{ {
material->textureTable[i].info.water = builder->getAllocator()->allocate<Game::water_t>(); material->textureTable[i].info.water = builder->getAllocator()->allocate<Game::water_t>();
material->textureTable[i].info.water->writable.floatTime = reader.read<float>(); material->textureTable[i].info.water->writable.floatTime = reader.read<float>();
material->textureTable[i].info.water->M = reader.read<int>(); material->textureTable[i].info.water->M = reader.read<int>();
material->textureTable[i].info.water->N = reader.read<int>(); material->textureTable[i].info.water->N = reader.read<int>();
int count = material->textureTable[i].info.water->M * material->textureTable[i].info.water->N; int count = material->textureTable[i].info.water->M * material->textureTable[i].info.water->N;
material->textureTable[i].info.water->H0 = reader.readArray<Game::complex_s>(count); material->textureTable[i].info.water->H0 = reader.readArray<Game::complex_s>(count);
material->textureTable[i].info.water->wTerm = reader.readArray<float>(count); material->textureTable[i].info.water->wTerm = reader.readArray<float>(count);
material->textureTable[i].info.water->Lx = reader.read<float>(); material->textureTable[i].info.water->Lx = reader.read<float>();
material->textureTable[i].info.water->Lz = reader.read<float>(); material->textureTable[i].info.water->Lz = reader.read<float>();
material->textureTable[i].info.water->gravity = reader.read<float>(); material->textureTable[i].info.water->gravity = reader.read<float>();
material->textureTable[i].info.water->windvel = reader.read<float>(); material->textureTable[i].info.water->windvel = reader.read<float>();
material->textureTable[i].info.water->winddir[0] = reader.read<float>(); material->textureTable[i].info.water->winddir[0] = reader.read<float>();
material->textureTable[i].info.water->winddir[1] = reader.read<float>(); material->textureTable[i].info.water->winddir[1] = reader.read<float>();
material->textureTable[i].info.water->amplitude = reader.read<float>(); material->textureTable[i].info.water->amplitude = reader.read<float>();
material->textureTable[i].info.water->codeConstant[0] = reader.read<float>(); material->textureTable[i].info.water->codeConstant[0] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[1] = reader.read<float>(); material->textureTable[i].info.water->codeConstant[1] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[2] = reader.read<float>(); material->textureTable[i].info.water->codeConstant[2] = reader.read<float>();
material->textureTable[i].info.water->codeConstant[3] = reader.read<float>(); material->textureTable[i].info.water->codeConstant[3] = reader.read<float>();
material->textureTable[i].info.water->image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image; material->textureTable[i].info.water->image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
} }
else else
{ {
material->textureTable[i].info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image; material->textureTable[i].info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, reader.readString().data(), builder).image;
} }
} }
for (char i = 0; i < material->constantCount; ++i) for (char i = 0; i < material->constantCount; ++i)
{ {
for (int j = 0; j < 12; ++j) for (int j = 0; j < 12; ++j)
{ {
material->constantTable[i].name[j] = reader.readByte(); material->constantTable[i].name[j] = reader.readByte();
} }
std::string constName(material->constantTable[i].name, 12); std::string constName(material->constantTable[i].name, 12);
constName.push_back('0'); constName.push_back('0');
material->constantTable[i].nameHash = Game::R_HashString(constName.data()); material->constantTable[i].nameHash = Game::R_HashString(constName.data());
material->constantTable[i].literal[0] = reader.read<float>(); material->constantTable[i].literal[0] = reader.read<float>();
material->constantTable[i].literal[1] = reader.read<float>(); material->constantTable[i].literal[1] = reader.read<float>();
material->constantTable[i].literal[2] = reader.read<float>(); material->constantTable[i].literal[2] = reader.read<float>();
material->constantTable[i].literal[3] = reader.read<float>(); material->constantTable[i].literal[3] = reader.read<float>();
} }
material->stateBitTable = reader.readArray<Game::GfxStateBits>(material->stateBitsCount); material->stateBitTable = reader.readArray<Game::GfxStateBits>(material->stateBitsCount);
header->material = material; header->material = material;
// Find correct sortkey by comparing techsets // Find correct sortkey by comparing techsets
Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void* data) Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void* data)
{ {
Game::Material* material = reinterpret_cast<Game::Material*>(data); Game::Material* material = reinterpret_cast<Game::Material*>(data);
const char* name = material->techniqueSet->name; const char* name = material->techniqueSet->name;
if (name[0] == ',') ++name; if (name[0] == ',') ++name;
if (std::string(name) == header.material->techniqueSet->name) if (std::string(name) == header.material->techniqueSet->name)
{ {
material->sortKey = header.material->sortKey; material->sortKey = header.material->sortKey;
// This is temp, as nobody has time to fix materials // This is temp, as nobody has time to fix materials
material->stateBitsCount = header.material->stateBitsCount; material->stateBitsCount = header.material->stateBitsCount;
material->stateBitTable = header.material->stateBitTable; material->stateBitTable = header.material->stateBitTable;
std::memcpy(material->stateBitsEntry, header.material->stateBitsEntry, 48); std::memcpy(material->stateBitsEntry, header.material->stateBitsEntry, 48);
material->constantCount = header.material->constantCount; material->constantCount = header.material->constantCount;
material->constantTable = header.material->constantTable; material->constantTable = header.material->constantTable;
} }
}, material, false); }, material, false);
} }
void IMaterial::loadNative(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* /*builder*/) void IMaterial::loadNative(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* /*builder*/)
{ {
header->material = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).material; header->material = Components::AssetHandler::FindOriginalAsset(this->getType(), name.data()).material;
} }
void IMaterial::loadJson(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IMaterial::loadJson(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File materialInfo(Utils::String::VA("materials/%s.json", name.data())); Components::FileSystem::File materialInfo(Utils::String::VA("materials/%s.json", name.data()));
if (!materialInfo.exists()) return; if (!materialInfo.exists()) return;
std::string errors; std::string errors;
json11::Json infoData = json11::Json::parse(materialInfo.getBuffer(), errors); json11::Json infoData = json11::Json::parse(materialInfo.getBuffer(), errors);
if (!infoData.is_object()) if (!infoData.is_object())
{ {
Components::Logger::Error("Failed to load material information for %s!", name.data()); Components::Logger::Error("Failed to load material information for %s!", name.data());
return; return;
} }
auto base = infoData["base"]; auto base = infoData["base"];
if (!base.is_string()) if (!base.is_string())
{ {
Components::Logger::Error("No valid material base provided for %s!", name.data()); Components::Logger::Error("No valid material base provided for %s!", name.data());
return; return;
} }
Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material; Game::Material* baseMaterial = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, base.string_value().data()).material;
if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!? if (!baseMaterial) // TODO: Maybe check if default asset? Maybe not? You could still want to use the default one as base!?
{ {
Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data()); Components::Logger::Error("Basematerial '%s' not found for %s!", base.string_value().data(), name.data());
return; return;
} }
Game::Material* material = builder->getAllocator()->allocate<Game::Material>(); Game::Material* material = builder->getAllocator()->allocate<Game::Material>();
if (!material) if (!material)
{ {
Components::Logger::Error("Failed to allocate material structure!"); Components::Logger::Error("Failed to allocate material structure!");
return; return;
} }
// Copy base material to our structure // Copy base material to our structure
std::memcpy(material, baseMaterial, sizeof(Game::Material)); std::memcpy(material, baseMaterial, sizeof(Game::Material));
material->name = builder->getAllocator()->duplicateString(name); material->name = builder->getAllocator()->duplicateString(name);
material->textureAtlasRowCount = 1; material->textureAtlasRowCount = 1;
material->textureAtlasColumnCount = 1; material->textureAtlasColumnCount = 1;
// Load animation frames // Load animation frames
auto anims = infoData["anims"]; auto anims = infoData["anims"];
if (anims.is_array()) if (anims.is_array())
{ {
auto animCoords = anims.array_items(); auto animCoords = anims.array_items();
if (animCoords.size() >= 2) if (animCoords.size() >= 2)
{ {
auto animCoordX = animCoords[0]; auto animCoordX = animCoords[0];
auto animCoordY = animCoords[1]; auto animCoordY = animCoords[1];
if (animCoordX.is_number()) if (animCoordX.is_number())
{ {
material->textureAtlasColumnCount = static_cast<char>(animCoordX.number_value()) & 0xFF; material->textureAtlasColumnCount = static_cast<char>(animCoordX.number_value()) & 0xFF;
} }
if (animCoordY.is_number()) if (animCoordY.is_number())
{ {
material->textureAtlasRowCount = static_cast<char>(animCoordY.number_value()) & 0xFF; material->textureAtlasRowCount = static_cast<char>(animCoordY.number_value()) & 0xFF;
} }
} }
} }
// Model surface textures are special, they need a special order and whatnot // Model surface textures are special, they need a special order and whatnot
bool replaceTexture = Utils::String::StartsWith(name, "mc/"); bool replaceTexture = Utils::String::StartsWith(name, "mc/");
if (replaceTexture) if (replaceTexture)
{ {
Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(baseMaterial->textureCount); Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(baseMaterial->textureCount);
std::memcpy(textureTable, baseMaterial->textureTable, sizeof(Game::MaterialTextureDef) * baseMaterial->textureCount); std::memcpy(textureTable, baseMaterial->textureTable, sizeof(Game::MaterialTextureDef) * baseMaterial->textureCount);
material->textureTable = textureTable; material->textureTable = textureTable;
material->textureCount = baseMaterial->textureCount; material->textureCount = baseMaterial->textureCount;
} }
// Load referenced textures // Load referenced textures
auto textures = infoData["textures"]; auto textures = infoData["textures"];
if (textures.is_array()) if (textures.is_array())
{ {
std::vector<Game::MaterialTextureDef> textureList; std::vector<Game::MaterialTextureDef> textureList;
for (auto texture : textures.array_items()) for (auto texture : textures.array_items())
{ {
if (!texture.is_array()) continue; if (!texture.is_array()) continue;
if (textureList.size() >= 0xFF) break; if (textureList.size() >= 0xFF) break;
auto textureInfo = texture.array_items(); auto textureInfo = texture.array_items();
if (textureInfo.size() < 2) continue; if (textureInfo.size() < 2) continue;
auto map = textureInfo[0]; auto map = textureInfo[0];
auto image = textureInfo[1]; auto image = textureInfo[1];
if (!map.is_string() || !image.is_string()) continue; if (!map.is_string() || !image.is_string()) continue;
Game::MaterialTextureDef textureDef; Game::MaterialTextureDef textureDef;
textureDef.semantic = 0; // No water image textureDef.semantic = 0; // No water image
textureDef.sampleState = -30; textureDef.sampleState = -30;
textureDef.nameEnd = map.string_value().back(); textureDef.nameEnd = map.string_value().back();
textureDef.nameStart = map.string_value().front(); textureDef.nameStart = map.string_value().front();
textureDef.nameHash = Game::R_HashString(map.string_value().data()); textureDef.nameHash = Game::R_HashString(map.string_value().data());
textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image; textureDef.info.image = Components::AssetHandler::FindAssetForZone(Game::XAssetType::ASSET_TYPE_IMAGE, image.string_value(), builder).image;
if (replaceTexture) if (replaceTexture)
{ {
bool applied = false; bool applied = false;
for (char i = 0; i < baseMaterial->textureCount; ++i) for (char i = 0; i < baseMaterial->textureCount; ++i)
{ {
if (material->textureTable[i].nameHash == textureDef.nameHash) if (material->textureTable[i].nameHash == textureDef.nameHash)
{ {
applied = true; applied = true;
material->textureTable[i].info.image = textureDef.info.image; material->textureTable[i].info.image = textureDef.info.image;
break; break;
} }
} }
if (!applied) if (!applied)
{ {
Components::Logger::Error(0, "Unable to find texture for map '%s' in %s!", map.string_value().data(), baseMaterial->name); Components::Logger::Error(0, "Unable to find texture for map '%s' in %s!", map.string_value().data(), baseMaterial->name);
} }
} }
else else
{ {
textureList.push_back(textureDef); textureList.push_back(textureDef);
} }
} }
if(!replaceTexture) if(!replaceTexture)
{ {
if (!textureList.empty()) if (!textureList.empty())
{ {
Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(textureList.size()); Game::MaterialTextureDef* textureTable = builder->getAllocator()->allocateArray<Game::MaterialTextureDef>(textureList.size());
if (!textureTable) if (!textureTable)
{ {
Components::Logger::Error("Failed to allocate texture table!"); Components::Logger::Error("Failed to allocate texture table!");
return; return;
} }
std::memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size()); std::memcpy(textureTable, textureList.data(), sizeof(Game::MaterialTextureDef) * textureList.size());
material->textureTable = textureTable; material->textureTable = textureTable;
} }
else else
{ {
material->textureTable = 0; material->textureTable = 0;
} }
material->textureCount = static_cast<char>(textureList.size()) & 0xFF; material->textureCount = static_cast<char>(textureList.size()) & 0xFF;
} }
} }
header->material = material; header->material = material;
} }
void IMaterial::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterial::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::Material* asset = header.material; Game::Material* asset = header.material;
if (asset->techniqueSet) if (asset->techniqueSet)
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet); builder->loadAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet);
} }
if (asset->textureTable) if (asset->textureTable)
{ {
for (char i = 0; i < asset->textureCount; ++i) for (char i = 0; i < asset->textureCount; ++i)
{ {
if (asset->textureTable[i].info.image) if (asset->textureTable[i].info.image)
{ {
if (asset->textureTable[i].semantic == SEMANTIC_WATER_MAP) if (asset->textureTable[i].semantic == SEMANTIC_WATER_MAP)
{ {
if (asset->textureTable[i].info.water->image) if (asset->textureTable[i].info.water->image)
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.water->image); builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.water->image);
} }
} }
else else
{ {
builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.image); builder->loadAsset(Game::XAssetType::ASSET_TYPE_IMAGE, asset->textureTable[i].info.image);
} }
} }
} }
} }
} }
void IMaterial::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IMaterial::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::Material, 96); AssertSize(Game::Material, 96);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::Material* asset = header.material; Game::Material* asset = header.material;
Game::Material* dest = buffer->dest<Game::Material>(); Game::Material* dest = buffer->dest<Game::Material>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->techniqueSet) if (asset->techniqueSet)
{ {
dest->techniqueSet = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet).techniqueSet; dest->techniqueSet = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, asset->techniqueSet).techniqueSet;
} }
if (asset->textureTable) if (asset->textureTable)
{ {
AssertSize(Game::MaterialTextureDef, 12); AssertSize(Game::MaterialTextureDef, 12);
// Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine // Pointer/Offset insertion is untested, but it worked in T6, so I think it's fine
if (builder->hasPointer(asset->textureTable)) if (builder->hasPointer(asset->textureTable))
{ {
dest->textureTable = builder->getPointer(asset->textureTable); dest->textureTable = builder->getPointer(asset->textureTable);
} }
else else
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->textureTable); builder->storePointer(asset->textureTable);
Game::MaterialTextureDef* destTextureTable = buffer->dest<Game::MaterialTextureDef>(); Game::MaterialTextureDef* destTextureTable = buffer->dest<Game::MaterialTextureDef>();
buffer->saveArray(asset->textureTable, asset->textureCount); buffer->saveArray(asset->textureTable, asset->textureCount);
for (char i = 0; i < asset->textureCount; ++i) for (char i = 0; i < asset->textureCount; ++i)
{ {
Game::MaterialTextureDef* destTextureDef = &destTextureTable[i]; Game::MaterialTextureDef* destTextureDef = &destTextureTable[i];
Game::MaterialTextureDef* textureDef = &asset->textureTable[i]; Game::MaterialTextureDef* textureDef = &asset->textureTable[i];
if (textureDef->semantic == SEMANTIC_WATER_MAP) if (textureDef->semantic == SEMANTIC_WATER_MAP)
{ {
AssertSize(Game::water_t, 68); AssertSize(Game::water_t, 68);
Game::water_t* destWater = buffer->dest<Game::water_t>(); Game::water_t* destWater = buffer->dest<Game::water_t>();
Game::water_t* water = textureDef->info.water; Game::water_t* water = textureDef->info.water;
if (water) if (water)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water); buffer->save(water);
Utils::Stream::ClearPointer(&destTextureDef->info.water); Utils::Stream::ClearPointer(&destTextureDef->info.water);
// Save_water_t // Save_water_t
if (water->H0) if (water->H0)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water->H0, 8, water->M * water->N); buffer->save(water->H0, 8, water->M * water->N);
Utils::Stream::ClearPointer(&destWater->H0); Utils::Stream::ClearPointer(&destWater->H0);
} }
if (water->wTerm) if (water->wTerm)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(water->wTerm, 4, water->M * water->N); buffer->save(water->wTerm, 4, water->M * water->N);
Utils::Stream::ClearPointer(&destWater->wTerm); Utils::Stream::ClearPointer(&destWater->wTerm);
} }
if (water->image) if (water->image)
{ {
destWater->image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, water->image).image; destWater->image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, water->image).image;
} }
} }
} }
else if (textureDef->info.image) else if (textureDef->info.image)
{ {
destTextureDef->info.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, textureDef->info.image).image; destTextureDef->info.image = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_IMAGE, textureDef->info.image).image;
} }
} }
Utils::Stream::ClearPointer(&dest->textureTable); Utils::Stream::ClearPointer(&dest->textureTable);
} }
} }
if (asset->constantTable) if (asset->constantTable)
{ {
AssertSize(Game::MaterialConstantDef, 32); AssertSize(Game::MaterialConstantDef, 32);
if (builder->hasPointer(asset->constantTable)) if (builder->hasPointer(asset->constantTable))
{ {
dest->constantTable = builder->getPointer(asset->constantTable); dest->constantTable = builder->getPointer(asset->constantTable);
} }
else else
{ {
buffer->align(Utils::Stream::ALIGN_16); buffer->align(Utils::Stream::ALIGN_16);
builder->storePointer(asset->constantTable); builder->storePointer(asset->constantTable);
buffer->saveArray(asset->constantTable, asset->constantCount); buffer->saveArray(asset->constantTable, asset->constantCount);
Utils::Stream::ClearPointer(&dest->constantTable); Utils::Stream::ClearPointer(&dest->constantTable);
} }
} }
if (asset->stateBitTable) if (asset->stateBitTable)
{ {
if (builder->hasPointer(asset->stateBitTable)) if (builder->hasPointer(asset->stateBitTable))
{ {
dest->stateBitTable = builder->getPointer(asset->stateBitTable); dest->stateBitTable = builder->getPointer(asset->stateBitTable);
} }
else else
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
builder->storePointer(asset->stateBitTable); builder->storePointer(asset->stateBitTable);
buffer->save(asset->stateBitTable, 8, asset->stateBitsCount); buffer->save(asset->stateBitTable, 8, asset->stateBitsCount);
Utils::Stream::ClearPointer(&dest->stateBitTable); Utils::Stream::ClearPointer(&dest->stateBitTable);
} }
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,60 +1,60 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void IRawFile::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IRawFile::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File rawFile(name); Components::FileSystem::File rawFile(name);
if (rawFile.exists()) if (rawFile.exists())
{ {
Game::RawFile* asset = builder->getAllocator()->allocate<Game::RawFile>(); Game::RawFile* asset = builder->getAllocator()->allocate<Game::RawFile>();
if (asset) if (asset)
{ {
//std::string data = Utils::Compression::ZLib::Compress(rawFile.getBuffer()); //std::string data = Utils::Compression::ZLib::Compress(rawFile.getBuffer());
asset->name = builder->getAllocator()->duplicateString(name); asset->name = builder->getAllocator()->duplicateString(name);
asset->compressedData = builder->getAllocator()->duplicateString(rawFile.getBuffer()); asset->compressedData = builder->getAllocator()->duplicateString(rawFile.getBuffer());
asset->sizeCompressed = 0;//data.size(); asset->sizeCompressed = 0;//data.size();
asset->sizeUnCompressed = rawFile.getBuffer().size(); asset->sizeUnCompressed = rawFile.getBuffer().size();
header->rawfile = asset; header->rawfile = asset;
} }
} }
} }
void IRawFile::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IRawFile::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::RawFile, 16); AssertSize(Game::RawFile, 16);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::RawFile* asset = header.rawfile; Game::RawFile* asset = header.rawfile;
Game::RawFile* dest = buffer->dest<Game::RawFile>(); Game::RawFile* dest = buffer->dest<Game::RawFile>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->compressedData) if (asset->compressedData)
{ {
if (asset->sizeCompressed) if (asset->sizeCompressed)
{ {
buffer->save(asset->compressedData, asset->sizeCompressed); buffer->save(asset->compressedData, asset->sizeCompressed);
} }
else else
{ {
buffer->save(asset->compressedData, asset->sizeUnCompressed + 1); buffer->save(asset->compressedData, asset->sizeUnCompressed + 1);
} }
Utils::Stream::ClearPointer(&dest->compressedData); Utils::Stream::ClearPointer(&dest->compressedData);
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,24 +1,24 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
namespace Assets namespace Assets
{ {
void ISndCurve::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void ISndCurve::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::SndCurve, 136); AssertSize(Game::SndCurve, 136);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::SndCurve* asset = header.sndCurve; Game::SndCurve* asset = header.sndCurve;
Game::SndCurve* dest = buffer->dest<Game::SndCurve>(); Game::SndCurve* dest = buffer->dest<Game::SndCurve>();
buffer->save(asset); buffer->save(asset);
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->filename) if (asset->filename)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->filename)); buffer->saveString(builder->getAssetName(this->getType(), asset->filename));
Utils::Stream::ClearPointer(&dest->filename); Utils::Stream::ClearPointer(&dest->filename);
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -1,354 +1,354 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#define IW4X_ANIM_VERSION 1 #define IW4X_ANIM_VERSION 1
namespace Assets namespace Assets
{ {
void IXAnimParts::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) void IXAnimParts::load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder)
{ {
Components::FileSystem::File animFile(Utils::String::VA("xanim/%s.iw4xAnim", name.data())); Components::FileSystem::File animFile(Utils::String::VA("xanim/%s.iw4xAnim", name.data()));
if (animFile.exists()) if (animFile.exists())
{ {
Utils::Stream::Reader reader(builder->getAllocator(), animFile.getBuffer()); Utils::Stream::Reader reader(builder->getAllocator(), animFile.getBuffer());
if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xAnim")) if (reader.read<__int64>() != *reinterpret_cast<__int64*>("IW4xAnim"))
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, header is invalid!", name.data()); Components::Logger::Error(0, "Reading animation '%s' failed, header is invalid!", name.data());
} }
int version = reader.read<int>(); int version = reader.read<int>();
if (version != IW4X_ANIM_VERSION) if (version != IW4X_ANIM_VERSION)
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_ANIM_VERSION, version); Components::Logger::Error(0, "Reading animation '%s' failed, expected version is %d, but it was %d!", name.data(), IW4X_ANIM_VERSION, version);
} }
Game::XAnimParts* xanim = reader.readArray<Game::XAnimParts>(); Game::XAnimParts* xanim = reader.readArray<Game::XAnimParts>();
if (xanim) if (xanim)
{ {
if (xanim->name) if (xanim->name)
{ {
xanim->name = reader.readCString(); xanim->name = reader.readCString();
} }
if (xanim->tagnames) if (xanim->tagnames)
{ {
xanim->tagnames = builder->getAllocator()->allocateArray<short>(xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]); xanim->tagnames = builder->getAllocator()->allocateArray<short>(xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
for (int i = 0; i < xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i) for (int i = 0; i < xanim->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
{ {
xanim->tagnames[i] = Game::SL_GetString(reader.readCString(), 0); xanim->tagnames[i] = Game::SL_GetString(reader.readCString(), 0);
} }
} }
if (xanim->notetracks) if (xanim->notetracks)
{ {
xanim->notetracks = reader.readArray<Game::XAnimNotifyInfo>(xanim->notetrackCount); xanim->notetracks = reader.readArray<Game::XAnimNotifyInfo>(xanim->notetrackCount);
for (int i = 0; i < xanim->notetrackCount; ++i) for (int i = 0; i < xanim->notetrackCount; ++i)
{ {
xanim->notetracks[i].name = Game::SL_GetString(reader.readCString(), 0); xanim->notetracks[i].name = Game::SL_GetString(reader.readCString(), 0);
} }
} }
if (xanim->dataByte) if (xanim->dataByte)
{ {
xanim->dataByte = reader.readArray<char>(xanim->dataByteCount); xanim->dataByte = reader.readArray<char>(xanim->dataByteCount);
} }
if (xanim->dataShort) if (xanim->dataShort)
{ {
xanim->dataShort = reader.readArray<short>(xanim->dataShortCount); xanim->dataShort = reader.readArray<short>(xanim->dataShortCount);
} }
if (xanim->dataInt) if (xanim->dataInt)
{ {
xanim->dataInt = reader.readArray<int>(xanim->dataIntCount); xanim->dataInt = reader.readArray<int>(xanim->dataIntCount);
} }
if (xanim->randomDataByte) if (xanim->randomDataByte)
{ {
xanim->randomDataByte = reader.readArray<char>(xanim->randomDataByteCount); xanim->randomDataByte = reader.readArray<char>(xanim->randomDataByteCount);
} }
if (xanim->randomDataShort) if (xanim->randomDataShort)
{ {
xanim->randomDataShort = reader.readArray<short>(xanim->randomDataShortCount); xanim->randomDataShort = reader.readArray<short>(xanim->randomDataShortCount);
} }
if (xanim->randomDataInt) if (xanim->randomDataInt)
{ {
xanim->randomDataInt = reader.readArray<int>(xanim->randomDataIntCount); xanim->randomDataInt = reader.readArray<int>(xanim->randomDataIntCount);
} }
if (xanim->indices.data) if (xanim->indices.data)
{ {
if (xanim->framecount < 256) if (xanim->framecount < 256)
{ {
xanim->indices._1 = reader.readArray<char>(xanim->indexcount); xanim->indices._1 = reader.readArray<char>(xanim->indexcount);
} }
else else
{ {
xanim->indices._2 = reader.readArray<unsigned short>(xanim->indexcount); xanim->indices._2 = reader.readArray<unsigned short>(xanim->indexcount);
} }
} }
if (!reader.end()) if (!reader.end())
{ {
Components::Logger::Error(0, "Reading animation '%s' failed, remaining raw data found!", name.data()); Components::Logger::Error(0, "Reading animation '%s' failed, remaining raw data found!", name.data());
} }
header->parts = xanim; header->parts = xanim;
} }
} }
} }
void IXAnimParts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IXAnimParts::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
Game::XAnimParts* asset = header.parts; Game::XAnimParts* asset = header.parts;
if (asset->tagnames) if (asset->tagnames)
{ {
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i) for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
{ {
builder->addScriptString(asset->tagnames[i]); builder->addScriptString(asset->tagnames[i]);
} }
} }
if (asset->notetracks) if (asset->notetracks)
{ {
for (char i = 0; i < asset->notetrackCount; ++i) for (char i = 0; i < asset->notetrackCount; ++i)
{ {
builder->addScriptString(asset->notetracks[i].name); builder->addScriptString(asset->notetracks[i].name);
} }
} }
} }
void IXAnimParts::saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder) void IXAnimParts::saveXAnimDeltaPart(Game::XAnimDeltaPart* delta, unsigned short framecount, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::XAnimDeltaPart, 12); AssertSize(Game::XAnimDeltaPart, 12);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::XAnimDeltaPart* destDelta = buffer->dest<Game::XAnimDeltaPart>(); Game::XAnimDeltaPart* destDelta = buffer->dest<Game::XAnimDeltaPart>();
buffer->save(delta); buffer->save(delta);
if (delta->trans) if (delta->trans)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->trans, 4); buffer->save(delta->trans, 4);
if (delta->trans->size) if (delta->trans->size)
{ {
buffer->save(&delta->trans->u.frames, 28); buffer->save(&delta->trans->u.frames, 28);
if (framecount > 0xFF) if (framecount > 0xFF)
{ {
buffer->saveArray(delta->trans->u.frames.indices._2, delta->trans->size + 1); buffer->saveArray(delta->trans->u.frames.indices._2, delta->trans->size + 1);
} }
else else
{ {
buffer->saveArray(delta->trans->u.frames.indices._1, delta->trans->size + 1); buffer->saveArray(delta->trans->u.frames.indices._1, delta->trans->size + 1);
} }
if (delta->trans->u.frames.frames._1) if (delta->trans->u.frames.frames._1)
{ {
if (delta->trans->smallTrans) if (delta->trans->smallTrans)
{ {
buffer->save(delta->trans->u.frames.frames._1, 3, delta->trans->size + 1); buffer->save(delta->trans->u.frames.frames._1, 3, delta->trans->size + 1);
} }
else else
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->trans->u.frames.frames._1, 6, delta->trans->size + 1); buffer->save(delta->trans->u.frames.frames._1, 6, delta->trans->size + 1);
} }
} }
} }
else else
{ {
buffer->save(delta->trans->u.frame0, 12); buffer->save(delta->trans->u.frame0, 12);
} }
Utils::Stream::ClearPointer(&destDelta->trans); Utils::Stream::ClearPointer(&destDelta->trans);
} }
if (delta->quat2) if (delta->quat2)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat2, 4); buffer->save(delta->quat2, 4);
if (delta->quat2->size) if (delta->quat2->size)
{ {
buffer->save(&delta->quat2->u.frames, 4); buffer->save(&delta->quat2->u.frames, 4);
if (framecount > 0xFF) if (framecount > 0xFF)
{ {
buffer->save(delta->quat2->u.frames.indices, 2, delta->quat2->size + 1); buffer->save(delta->quat2->u.frames.indices, 2, delta->quat2->size + 1);
} }
else else
{ {
buffer->save(delta->quat2->u.frames.indices, 1, delta->quat2->size + 1); buffer->save(delta->quat2->u.frames.indices, 1, delta->quat2->size + 1);
} }
if (delta->quat2->u.frames.frames) if (delta->quat2->u.frames.frames)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat2->u.frames.frames, 4, delta->quat2->size + 1); buffer->save(delta->quat2->u.frames.frames, 4, delta->quat2->size + 1);
} }
} }
else else
{ {
buffer->save(delta->quat2->u.frame0, 4); buffer->save(delta->quat2->u.frame0, 4);
} }
Utils::Stream::ClearPointer(&destDelta->quat2); Utils::Stream::ClearPointer(&destDelta->quat2);
} }
if (delta->quat) if (delta->quat)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat, 4); buffer->save(delta->quat, 4);
if (delta->quat->size) if (delta->quat->size)
{ {
buffer->save(&delta->quat->u.frames, 4); buffer->save(&delta->quat->u.frames, 4);
if (framecount > 0xFF) if (framecount > 0xFF)
{ {
buffer->save(delta->quat->u.frames.indices, 2, delta->quat->size + 1); buffer->save(delta->quat->u.frames.indices, 2, delta->quat->size + 1);
} }
else else
{ {
buffer->save(delta->quat->u.frames.indices, 1, delta->quat->size + 1); buffer->save(delta->quat->u.frames.indices, 1, delta->quat->size + 1);
} }
if (delta->quat->u.frames.frames) if (delta->quat->u.frames.frames)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->save(delta->quat->u.frames.frames, 4, delta->quat->size + 1); buffer->save(delta->quat->u.frames.frames, 4, delta->quat->size + 1);
} }
} }
else else
{ {
buffer->save(delta->quat->u.frame0, 4); buffer->save(delta->quat->u.frame0, 4);
} }
Utils::Stream::ClearPointer(&destDelta->quat); Utils::Stream::ClearPointer(&destDelta->quat);
} }
} }
void IXAnimParts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) void IXAnimParts::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder)
{ {
AssertSize(Game::XAnimParts, 88); AssertSize(Game::XAnimParts, 88);
Utils::Stream* buffer = builder->getBuffer(); Utils::Stream* buffer = builder->getBuffer();
Game::XAnimParts* asset = header.parts; Game::XAnimParts* asset = header.parts;
Game::XAnimParts* dest = buffer->dest<Game::XAnimParts>(); Game::XAnimParts* dest = buffer->dest<Game::XAnimParts>();
buffer->save(asset, sizeof(Game::XAnimParts)); buffer->save(asset, sizeof(Game::XAnimParts));
buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL);
if (asset->name) if (asset->name)
{ {
buffer->saveString(builder->getAssetName(this->getType(), asset->name)); buffer->saveString(builder->getAssetName(this->getType(), asset->name));
Utils::Stream::ClearPointer(&dest->name); Utils::Stream::ClearPointer(&dest->name);
} }
if (asset->tagnames) if (asset->tagnames)
{ {
buffer->align(Utils::Stream::ALIGN_2); buffer->align(Utils::Stream::ALIGN_2);
unsigned short* destTagnames = buffer->dest<unsigned short>(); unsigned short* destTagnames = buffer->dest<unsigned short>();
buffer->saveArray(asset->tagnames, asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]); buffer->saveArray(asset->tagnames, asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]);
for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i) for (char i = 0; i < asset->boneCount[Game::XAnimPartType::PART_TYPE_ALL]; ++i)
{ {
builder->mapScriptString(&destTagnames[i]); builder->mapScriptString(&destTagnames[i]);
} }
Utils::Stream::ClearPointer(&dest->tagnames); Utils::Stream::ClearPointer(&dest->tagnames);
} }
if (asset->notetracks) if (asset->notetracks)
{ {
AssertSize(Game::XAnimNotifyInfo, 8); AssertSize(Game::XAnimNotifyInfo, 8);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
Game::XAnimNotifyInfo* destNotetracks = buffer->dest<Game::XAnimNotifyInfo>(); Game::XAnimNotifyInfo* destNotetracks = buffer->dest<Game::XAnimNotifyInfo>();
buffer->saveArray(asset->notetracks, asset->notetrackCount); buffer->saveArray(asset->notetracks, asset->notetrackCount);
for (char i = 0; i < asset->notetrackCount; ++i) for (char i = 0; i < asset->notetrackCount; ++i)
{ {
builder->mapScriptString(&destNotetracks[i].name); builder->mapScriptString(&destNotetracks[i].name);
} }
Utils::Stream::ClearPointer(&dest->notetracks); Utils::Stream::ClearPointer(&dest->notetracks);
} }
if (asset->delta) if (asset->delta)
{ {
AssertSize(Game::XAnimDeltaPart, 12); AssertSize(Game::XAnimDeltaPart, 12);
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
this->saveXAnimDeltaPart(asset->delta, asset->framecount, builder); this->saveXAnimDeltaPart(asset->delta, asset->framecount, builder);
Utils::Stream::ClearPointer(&dest->delta); Utils::Stream::ClearPointer(&dest->delta);
} }
if (asset->dataByte) if (asset->dataByte)
{ {
buffer->saveArray(asset->dataByte, asset->dataByteCount); buffer->saveArray(asset->dataByte, asset->dataByteCount);
Utils::Stream::ClearPointer(&dest->dataByte); Utils::Stream::ClearPointer(&dest->dataByte);
} }
if (asset->dataShort) if (asset->dataShort)
{ {
buffer->align(Utils::Stream::ALIGN_2); buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->dataShort, asset->dataShortCount); buffer->saveArray(asset->dataShort, asset->dataShortCount);
Utils::Stream::ClearPointer(&dest->dataShort); Utils::Stream::ClearPointer(&dest->dataShort);
} }
if (asset->dataInt) if (asset->dataInt)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->dataInt, asset->dataIntCount); buffer->saveArray(asset->dataInt, asset->dataIntCount);
Utils::Stream::ClearPointer(&dest->dataInt); Utils::Stream::ClearPointer(&dest->dataInt);
} }
if (asset->randomDataShort) if (asset->randomDataShort)
{ {
buffer->align(Utils::Stream::ALIGN_2); buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->randomDataShort, asset->randomDataShortCount); buffer->saveArray(asset->randomDataShort, asset->randomDataShortCount);
Utils::Stream::ClearPointer(&dest->randomDataShort); Utils::Stream::ClearPointer(&dest->randomDataShort);
} }
if (asset->randomDataByte) if (asset->randomDataByte)
{ {
buffer->saveArray(asset->randomDataByte, asset->randomDataByteCount); buffer->saveArray(asset->randomDataByte, asset->randomDataByteCount);
Utils::Stream::ClearPointer(&dest->randomDataByte); Utils::Stream::ClearPointer(&dest->randomDataByte);
} }
if (asset->randomDataInt) if (asset->randomDataInt)
{ {
buffer->align(Utils::Stream::ALIGN_4); buffer->align(Utils::Stream::ALIGN_4);
buffer->saveArray(asset->randomDataInt, asset->randomDataIntCount); buffer->saveArray(asset->randomDataInt, asset->randomDataIntCount);
Utils::Stream::ClearPointer(&dest->randomDataInt); Utils::Stream::ClearPointer(&dest->randomDataInt);
} }
if (asset->indices.data) if (asset->indices.data)
{ {
if (asset->framecount > 0xFF) if (asset->framecount > 0xFF)
{ {
buffer->align(Utils::Stream::ALIGN_2); buffer->align(Utils::Stream::ALIGN_2);
buffer->saveArray(asset->indices._2, asset->indexcount); buffer->saveArray(asset->indices._2, asset->indexcount);
} }
else else
{ {
buffer->saveArray(asset->indices._1, asset->indexcount); buffer->saveArray(asset->indices._1, asset->indexcount);
} }
Utils::Stream::ClearPointer(&dest->indices.data); Utils::Stream::ClearPointer(&dest->indices.data);
} }
buffer->popBlock(); buffer->popBlock();
} }
} }

View File

@ -883,4 +883,4 @@ namespace Assets
} }
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,52 +1,52 @@
namespace Components namespace Components
{ {
class Auth : public Component class Auth : public Component
{ {
public: public:
Auth(); Auth();
~Auth(); ~Auth();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Auth"; }; const char* getName() { return "Auth"; };
#endif #endif
bool unitTest(); bool unitTest();
static void StoreKey(); static void StoreKey();
static void LoadKey(bool force = false); static void LoadKey(bool force = false);
static unsigned __int64 GetKeyHash(); static unsigned __int64 GetKeyHash();
static unsigned __int64 GetKeyHash(std::string key); static unsigned __int64 GetKeyHash(std::string key);
static uint32_t GetSecurityLevel(); static uint32_t GetSecurityLevel();
static void IncreaseSecurityLevel(uint32_t level, std::string command = ""); static void IncreaseSecurityLevel(uint32_t level, std::string command = "");
static uint32_t GetZeroBits(Utils::Cryptography::Token token, std::string publicKey); static uint32_t GetZeroBits(Utils::Cryptography::Token token, std::string publicKey);
static void IncrementToken(Utils::Cryptography::Token& token, Utils::Cryptography::Token& computeToken, std::string publicKey, uint32_t zeroBits, bool* cancel = nullptr, uint64_t* count = nullptr); static void IncrementToken(Utils::Cryptography::Token& token, Utils::Cryptography::Token& computeToken, std::string publicKey, uint32_t zeroBits, bool* cancel = nullptr, uint64_t* count = nullptr);
private: private:
class TokenIncrementing class TokenIncrementing
{ {
public: public:
bool cancel; bool cancel;
bool generating; bool generating;
std::thread thread; std::thread thread;
uint32_t targetLevel; uint32_t targetLevel;
int startTime; int startTime;
std::string command; std::string command;
uint64_t hashes; uint64_t hashes;
}; };
static TokenIncrementing TokenContainer; static TokenIncrementing TokenContainer;
static Utils::Cryptography::Token GuidToken; static Utils::Cryptography::Token GuidToken;
static Utils::Cryptography::Token ComputeToken; static Utils::Cryptography::Token ComputeToken;
static Utils::Cryptography::ECC::Key GuidKey; static Utils::Cryptography::ECC::Key GuidKey;
static void SendConnectDataStub(Game::netsrc_t sock, Game::netadr_t adr, const char *format, int len); static void SendConnectDataStub(Game::netsrc_t sock, Game::netadr_t adr, const char *format, int len);
static void ParseConnectData(Game::msg_t* msg, Game::netadr_t addr); static void ParseConnectData(Game::msg_t* msg, Game::netadr_t addr);
static void DirectConnectStub(); static void DirectConnectStub();
static void Frame(); static void Frame();
}; };
} }

View File

@ -1,212 +1,212 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::mutex Bans::AccessMutex; std::mutex Bans::AccessMutex;
bool Bans::IsBanned(Bans::Entry entry) bool Bans::IsBanned(Bans::Entry entry)
{ {
Bans::BanList list; Bans::BanList list;
Bans::LoadBans(&list); Bans::LoadBans(&list);
if (entry.first.Bits) if (entry.first.Bits)
{ {
for (auto& idEntry : list.idList) for (auto& idEntry : list.idList)
{ {
if (idEntry.Bits == entry.first.Bits) if (idEntry.Bits == entry.first.Bits)
{ {
return true; return true;
} }
} }
} }
if (entry.second.full) if (entry.second.full)
{ {
for (auto& ipEntry : list.ipList) for (auto& ipEntry : list.ipList)
{ {
if (ipEntry.full == entry.second.full) if (ipEntry.full == entry.second.full)
{ {
return true; return true;
} }
} }
} }
return false; return false;
} }
void Bans::InsertBan(Bans::Entry entry) void Bans::InsertBan(Bans::Entry entry)
{ {
Bans::BanList list; Bans::BanList list;
Bans::LoadBans(&list); Bans::LoadBans(&list);
std::lock_guard<std::mutex> _(Bans::AccessMutex); std::lock_guard<std::mutex> _(Bans::AccessMutex);
if (entry.first.Bits) if (entry.first.Bits)
{ {
bool found = false; bool found = false;
for (auto& idEntry : list.idList) for (auto& idEntry : list.idList)
{ {
if (idEntry.Bits == entry.first.Bits) if (idEntry.Bits == entry.first.Bits)
{ {
found = true; found = true;
break; break;
} }
} }
if (!found) if (!found)
{ {
list.idList.push_back(entry.first); list.idList.push_back(entry.first);
} }
} }
if (entry.second.full) if (entry.second.full)
{ {
bool found = false; bool found = false;
for (auto& ipEntry : list.ipList) for (auto& ipEntry : list.ipList)
{ {
if (ipEntry.full == entry.second.full) if (ipEntry.full == entry.second.full)
{ {
found = true; found = true;
break; break;
} }
} }
if (!found) if (!found)
{ {
list.ipList.push_back(entry.second); list.ipList.push_back(entry.second);
} }
} }
std::vector<std::string> idVector; std::vector<std::string> idVector;
std::vector<std::string> ipVector; std::vector<std::string> ipVector;
for (auto& idEntry : list.idList) for (auto& idEntry : list.idList)
{ {
idVector.push_back(Utils::String::VA("%llX", idEntry.Bits)); idVector.push_back(Utils::String::VA("%llX", idEntry.Bits));
} }
for (auto& ipEntry : list.ipList) for (auto& ipEntry : list.ipList)
{ {
ipVector.push_back(Utils::String::VA("%u.%u.%u.%u", ipVector.push_back(Utils::String::VA("%u.%u.%u.%u",
ipEntry.bytes[0] & 0xFF, ipEntry.bytes[0] & 0xFF,
ipEntry.bytes[1] & 0xFF, ipEntry.bytes[1] & 0xFF,
ipEntry.bytes[2] & 0xFF, ipEntry.bytes[2] & 0xFF,
ipEntry.bytes[3] & 0xFF)); ipEntry.bytes[3] & 0xFF));
} }
json11::Json bans = json11::Json::object json11::Json bans = json11::Json::object
{ {
{ "ip", ipVector }, { "ip", ipVector },
{ "id", idVector }, { "id", idVector },
}; };
FileSystem::FileWriter ban("bans.json"); FileSystem::FileWriter ban("bans.json");
ban.write(bans.dump()); ban.write(bans.dump());
} }
void Bans::LoadBans(Bans::BanList* list) void Bans::LoadBans(Bans::BanList* list)
{ {
std::lock_guard<std::mutex> _(Bans::AccessMutex); std::lock_guard<std::mutex> _(Bans::AccessMutex);
FileSystem::File bans("bans.json"); FileSystem::File bans("bans.json");
if (bans.exists()) if (bans.exists())
{ {
std::string error; std::string error;
json11::Json banData = json11::Json::parse(bans.getBuffer(), error); json11::Json banData = json11::Json::parse(bans.getBuffer(), error);
if (!error.empty()) if (!error.empty())
{ {
Logger::Error("Failed to parse bans (bans.json): %s", error.data()); Logger::Error("Failed to parse bans (bans.json): %s", error.data());
} }
if (!list) if (!list)
{ {
Bans::AccessMutex.unlock(); Bans::AccessMutex.unlock();
return; return;
} }
if (banData.is_object()) if (banData.is_object())
{ {
auto idList = banData["id"]; auto idList = banData["id"];
auto ipList = banData["ip"]; auto ipList = banData["ip"];
if (idList.is_array()) if (idList.is_array())
{ {
for (auto &idEntry : idList.array_items()) for (auto &idEntry : idList.array_items())
{ {
if (idEntry.is_string()) if (idEntry.is_string())
{ {
SteamID id; SteamID id;
id.Bits = strtoull(idEntry.string_value().data(), nullptr, 16); id.Bits = strtoull(idEntry.string_value().data(), nullptr, 16);
list->idList.push_back(id); list->idList.push_back(id);
} }
} }
} }
if (ipList.is_array()) if (ipList.is_array())
{ {
for (auto &ipEntry : ipList.array_items()) for (auto &ipEntry : ipList.array_items())
{ {
if (ipEntry.is_string()) if (ipEntry.is_string())
{ {
Network::Address addr(ipEntry.string_value()); Network::Address addr(ipEntry.string_value());
list->ipList.push_back(addr.getIP()); list->ipList.push_back(addr.getIP());
} }
} }
} }
} }
} }
} }
void Bans::BanClientNum(int num, std::string reason) void Bans::BanClientNum(int num, std::string reason)
{ {
if (!Dvar::Var("sv_running").get<bool>()) if (!Dvar::Var("sv_running").get<bool>())
{ {
Logger::Print("Server is not running.\n"); Logger::Print("Server is not running.\n");
return; return;
} }
if (*Game::svs_numclients <= num) if (*Game::svs_numclients <= num)
{ {
Logger::Print("Player %d is not on the server\n", num); Logger::Print("Player %d is not on the server\n", num);
return; return;
} }
Game::client_t* client = &Game::svs_clients[num]; Game::client_t* client = &Game::svs_clients[num];
SteamID guid; SteamID guid;
guid.Bits = client->steamid; guid.Bits = client->steamid;
Bans::InsertBan({ guid, client->addr.ip }); Bans::InsertBan({ guid, client->addr.ip });
Game::SV_KickClientError(client, reason); Game::SV_KickClientError(client, reason);
} }
Bans::Bans() Bans::Bans()
{ {
Command::Add("banclient", [] (Command::Params* params) Command::Add("banclient", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
std::string reason = "EXE_ERR_BANNED_PERM"; std::string reason = "EXE_ERR_BANNED_PERM";
if (params->length() >= 3) reason = params->get(2); if (params->length() >= 3) reason = params->get(2);
Bans::BanClientNum(atoi(params->get(1)), reason); Bans::BanClientNum(atoi(params->get(1)), reason);
}); });
// Verify the list on startup // Verify the list on startup
QuickPatch::Once([] () QuickPatch::Once([] ()
{ {
Bans::BanList list; Bans::BanList list;
Bans::LoadBans(&list); Bans::LoadBans(&list);
}); });
} }
Bans::~Bans() Bans::~Bans()
{ {
} }
} }

View File

@ -1,31 +1,31 @@
namespace Components namespace Components
{ {
class Bans : public Component class Bans : public Component
{ {
public: public:
typedef std::pair<SteamID, Game::netIP_t> Entry; typedef std::pair<SteamID, Game::netIP_t> Entry;
Bans(); Bans();
~Bans(); ~Bans();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Bans"; }; const char* getName() { return "Bans"; };
#endif #endif
static void BanClientNum(int num, std::string reason); static void BanClientNum(int num, std::string reason);
static bool IsBanned(Entry entry); static bool IsBanned(Entry entry);
static void InsertBan(Entry entry); static void InsertBan(Entry entry);
private: private:
class BanList class BanList
{ {
public: public:
std::vector<SteamID> idList; std::vector<SteamID> idList;
std::vector<Game::netIP_t> ipList; std::vector<Game::netIP_t> ipList;
}; };
static std::mutex AccessMutex; static std::mutex AccessMutex;
static void LoadBans(BanList* list); static void LoadBans(BanList* list);
}; };
} }

View File

@ -37,4 +37,4 @@ namespace Components
}; };
} }
#endif #endif

View File

@ -1,54 +1,54 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::vector<std::string> Bots::BotNames; std::vector<std::string> Bots::BotNames;
void Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port) void Bots::BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port)
{ {
static int botId = 0; static int botId = 0;
if (Bots::BotNames.empty()) if (Bots::BotNames.empty())
{ {
FileSystem::File bots("bots.txt"); FileSystem::File bots("bots.txt");
if (bots.exists()) if (bots.exists())
{ {
std::vector<std::string> names = Utils::String::Explode(bots.getBuffer(), '\n'); std::vector<std::string> names = Utils::String::Explode(bots.getBuffer(), '\n');
for (auto name : names) for (auto name : names)
{ {
Utils::String::Replace(name, "\r", ""); Utils::String::Replace(name, "\r", "");
name = Utils::String::Trim(name); name = Utils::String::Trim(name);
if (!name.empty()) if (!name.empty())
{ {
Bots::BotNames.push_back(name); Bots::BotNames.push_back(name);
} }
} }
} }
if (Bots::BotNames.empty()) if (Bots::BotNames.empty())
{ {
Bots::BotNames.push_back("bot"); Bots::BotNames.push_back("bot");
} }
} }
botId %= Bots::BotNames.size(); botId %= Bots::BotNames.size();
strncpy_s(buffer, 0x400, Utils::String::VA(connectString, num, Bots::BotNames[botId++].data(), protocol, checksum, statVer, statStuff, port), 0x400); strncpy_s(buffer, 0x400, Utils::String::VA(connectString, num, Bots::BotNames[botId++].data(), protocol, checksum, statVer, statStuff, port), 0x400);
} }
Bots::Bots() Bots::Bots()
{ {
// Replace connect string // Replace connect string
Utils::Hook::Set<const char*>(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\""); Utils::Hook::Set<const char*>(0x48ADA6, "connect bot%d \"\\cg_predictItems\\1\\cl_anonymous\\0\\color\\4\\head\\default\\model\\multi\\snaps\\20\\rate\\5000\\name\\%s\\protocol\\%d\\checksum\\%d\\statver\\%d %u\\qport\\%d\"");
// Intercept sprintf for the connect string // Intercept sprintf for the connect string
Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick(); Utils::Hook(0x48ADAB, Bots::BuildConnectString, HOOK_CALL).install()->quick();
} }
Bots::~Bots() Bots::~Bots()
{ {
Bots::BotNames.clear(); Bots::BotNames.clear();
} }
} }

View File

@ -1,18 +1,18 @@
namespace Components namespace Components
{ {
class Bots : public Component class Bots : public Component
{ {
public: public:
Bots(); Bots();
~Bots(); ~Bots();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Bots"; }; const char* getName() { return "Bots"; };
#endif #endif
private: private:
static std::vector<std::string> BotNames; static std::vector<std::string> BotNames;
static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port); static void BuildConnectString(char* buffer, const char* connectString, int num, int, int protocol, int checksum, int statVer, int statStuff, int port);
}; };
} }

View File

@ -1,254 +1,254 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Dvar::Var Colors::NewColors; Dvar::Var Colors::NewColors;
std::vector<DWORD> Colors::ColorTable; std::vector<DWORD> Colors::ColorTable;
DWORD Colors::HsvToRgb(Colors::HsvColor hsv) DWORD Colors::HsvToRgb(Colors::HsvColor hsv)
{ {
DWORD rgb; DWORD rgb;
unsigned char region, p, q, t; unsigned char region, p, q, t;
unsigned int h, s, v, remainder; unsigned int h, s, v, remainder;
if (hsv.s == 0) if (hsv.s == 0)
{ {
rgb = RGB(hsv.v, hsv.v, hsv.v); rgb = RGB(hsv.v, hsv.v, hsv.v);
return rgb; return rgb;
} }
// converting to 16 bit to prevent overflow // converting to 16 bit to prevent overflow
h = hsv.h; h = hsv.h;
s = hsv.s; s = hsv.s;
v = hsv.v; v = hsv.v;
region = static_cast<uint8_t>(h / 43); region = static_cast<uint8_t>(h / 43);
remainder = (h - (region * 43)) * 6; remainder = (h - (region * 43)) * 6;
p = static_cast<uint8_t>((v * (255 - s)) >> 8); p = static_cast<uint8_t>((v * (255 - s)) >> 8);
q = static_cast<uint8_t>((v * (255 - ((s * remainder) >> 8))) >> 8); q = static_cast<uint8_t>((v * (255 - ((s * remainder) >> 8))) >> 8);
t = static_cast<uint8_t>((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8); t = static_cast<uint8_t>((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8);
switch (region) switch (region)
{ {
case 0: case 0:
rgb = RGB(v, t, p); rgb = RGB(v, t, p);
break; break;
case 1: case 1:
rgb = RGB(q, v, p); rgb = RGB(q, v, p);
break; break;
case 2: case 2:
rgb = RGB(p, v, t); rgb = RGB(p, v, t);
break; break;
case 3: case 3:
rgb = RGB(p, q, v); rgb = RGB(p, q, v);
break; break;
case 4: case 4:
rgb = RGB(t, p, v); rgb = RGB(t, p, v);
break; break;
default: default:
rgb = RGB(v, p, q); rgb = RGB(v, p, q);
break; break;
} }
return rgb; return rgb;
} }
void Colors::Strip(const char* in, char* out, int max) void Colors::Strip(const char* in, char* out, int max)
{ {
if (!in || !out) return; if (!in || !out) return;
max--; max--;
int current = 0; int current = 0;
while (*in != 0 && current < max) while (*in != 0 && current < max)
{ {
char index = *(in + 1); char index = *(in + 1);
if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7')) if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7'))
{ {
++in; ++in;
} }
else else
{ {
*out = *in; *out = *in;
++out; ++out;
++current; ++current;
} }
++in; ++in;
} }
*out = '\0'; *out = '\0';
} }
std::string Colors::Strip(std::string in) std::string Colors::Strip(std::string in)
{ {
char buffer[1000] = { 0 }; // Should be more than enough char buffer[1000] = { 0 }; // Should be more than enough
Colors::Strip(in.data(), buffer, sizeof(buffer)); Colors::Strip(in.data(), buffer, sizeof(buffer));
return std::string(buffer); return std::string(buffer);
} }
__declspec(naked) void Colors::ClientUserinfoChanged() __declspec(naked) void Colors::ClientUserinfoChanged()
{ {
__asm __asm
{ {
mov eax, [esp + 4h] // length mov eax, [esp + 4h] // length
sub eax, 1 sub eax, 1
push eax push eax
push ecx // name push ecx // name
push edx // buffer push edx // buffer
call strncpy call strncpy
add esp, 0Ch add esp, 0Ch
retn retn
} }
} }
char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size) char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size)
{ {
Game::CL_GetClientName(localClientNum, index, buf, size); Game::CL_GetClientName(localClientNum, index, buf, size);
// Remove the colors // Remove the colors
strncpy_s(buf, size, Colors::Strip(buf).data(), size); strncpy_s(buf, size, Colors::Strip(buf).data(), size);
return buf; return buf;
} }
void Colors::PatchColorLimit(char limit) void Colors::PatchColorLimit(char limit)
{ {
Utils::Hook::Set<char>(0x535629, limit); // DrawText2d Utils::Hook::Set<char>(0x535629, limit); // DrawText2d
Utils::Hook::Set<char>(0x4C1BE4, limit); // No idea :P Utils::Hook::Set<char>(0x4C1BE4, limit); // No idea :P
Utils::Hook::Set<char>(0x4863DD, limit); // No idea :P Utils::Hook::Set<char>(0x4863DD, limit); // No idea :P
Utils::Hook::Set<char>(0x486429, limit); // No idea :P Utils::Hook::Set<char>(0x486429, limit); // No idea :P
Utils::Hook::Set<char>(0x49A5A8, limit); // No idea :P Utils::Hook::Set<char>(0x49A5A8, limit); // No idea :P
Utils::Hook::Set<char>(0x505721, limit); // R_TextWidth Utils::Hook::Set<char>(0x505721, limit); // R_TextWidth
Utils::Hook::Set<char>(0x505801, limit); // No idea :P Utils::Hook::Set<char>(0x505801, limit); // No idea :P
Utils::Hook::Set<char>(0x50597F, limit); // No idea :P Utils::Hook::Set<char>(0x50597F, limit); // No idea :P
Utils::Hook::Set<char>(0x5815DB, limit); // No idea :P Utils::Hook::Set<char>(0x5815DB, limit); // No idea :P
Utils::Hook::Set<char>(0x592ED0, limit); // No idea :P Utils::Hook::Set<char>(0x592ED0, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2E2E, limit); // No idea :P Utils::Hook::Set<char>(0x5A2E2E, limit); // No idea :P
Utils::Hook::Set<char>(0x5A2733, limit - '0'); // No idea :P Utils::Hook::Set<char>(0x5A2733, limit - '0'); // No idea :P
} }
char Colors::Add(uint8_t r, uint8_t g, uint8_t b) char Colors::Add(uint8_t r, uint8_t g, uint8_t b)
{ {
char index = '0' + static_cast<char>(Colors::ColorTable.size()); char index = '0' + static_cast<char>(Colors::ColorTable.size());
Colors::ColorTable.push_back(RGB(r, g, b)); Colors::ColorTable.push_back(RGB(r, g, b));
Colors::PatchColorLimit(index); Colors::PatchColorLimit(index);
return index; return index;
} }
unsigned int Colors::ColorIndex(unsigned char index) unsigned int Colors::ColorIndex(unsigned char index)
{ {
unsigned int result = index - '0'; unsigned int result = index - '0';
if (result >= Colors::ColorTable.size() || result < 0) result = 7; if (result >= Colors::ColorTable.size() || result < 0) result = 7;
return result; return result;
} }
void Colors::LookupColor(DWORD* color, char index) void Colors::LookupColor(DWORD* color, char index)
{ {
*color = RGB(255, 255, 255); *color = RGB(255, 255, 255);
if (index == '8') // Color 8 if (index == '8') // Color 8
{ {
*color = *reinterpret_cast<DWORD*>(0x66E5F70); *color = *reinterpret_cast<DWORD*>(0x66E5F70);
} }
else if (index == '9') // Color 9 else if (index == '9') // Color 9
{ {
*color = *reinterpret_cast<DWORD*>(0x66E5F74); *color = *reinterpret_cast<DWORD*>(0x66E5F74);
} }
else if (index == ':') else if (index == ':')
{ {
*color = Colors::HsvToRgb({ static_cast<uint8_t>((Game::Sys_Milliseconds() / 200) % 256), 255,255 }); *color = Colors::HsvToRgb({ static_cast<uint8_t>((Game::Sys_Milliseconds() / 200) % 256), 255,255 });
} }
else if (index == ';') else if (index == ';')
{ {
float fltColor[4]; float fltColor[4];
Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor); Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor);
*color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255); *color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255);
} }
else else
{ {
int clrIndex = Colors::ColorIndex(index); int clrIndex = Colors::ColorIndex(index);
// Use native colors // Use native colors
if (clrIndex <= 7 && !Colors::NewColors.get<bool>()) if (clrIndex <= 7 && !Colors::NewColors.get<bool>())
{ {
*color = reinterpret_cast<DWORD*>(0x78DC70)[index - 48]; *color = reinterpret_cast<DWORD*>(0x78DC70)[index - 48];
} }
else else
{ {
*color = Colors::ColorTable[clrIndex]; *color = Colors::ColorTable[clrIndex];
} }
} }
} }
char* Colors::CleanStrStub(char* string) char* Colors::CleanStrStub(char* string)
{ {
Colors::Strip(string, string, strlen(string) + 1); Colors::Strip(string, string, strlen(string) + 1);
return string; return string;
} }
__declspec(naked) void Colors::LookupColorStub() __declspec(naked) void Colors::LookupColorStub()
{ {
__asm __asm
{ {
push ebx push ebx
push [esp + 8h] // Index push[esp + 8h] // Index
push esi // Color ref push esi // Color ref
call Colors::LookupColor call Colors::LookupColor
add esp, 8h add esp, 8h
pop ebx pop ebx
retn retn
} }
} }
Colors::Colors() Colors::Colors()
{ {
// Disable SV_UpdateUserinfo_f, to block changing the name ingame // Disable SV_UpdateUserinfo_f, to block changing the name ingame
Utils::Hook::Set<BYTE>(0x6258D0, 0xC3); Utils::Hook::Set<BYTE>(0x6258D0, 0xC3);
// Allow colored names ingame // Allow colored names ingame
Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).install()->quick(); Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).install()->quick();
// Though, don't apply that to overhead names. // Though, don't apply that to overhead names.
Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).install()->quick(); Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).install()->quick();
// Patch RB_LookupColor // Patch RB_LookupColor
Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).install()->quick();
// Patch ColorIndex // Patch ColorIndex
Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).install()->quick(); Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).install()->quick();
// Patch I_CleanStr // Patch I_CleanStr
Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).install()->quick();
// Register dvar // Register dvar
Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare<72> color code style."); Colors::NewColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare<72> color code style.");
Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code."); Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
// Add our colors // Add our colors
Colors::Add(0, 0, 0); // 0 - Black Colors::Add(0, 0, 0); // 0 - Black
Colors::Add(255, 49, 49); // 1 - Red Colors::Add(255, 49, 49); // 1 - Red
Colors::Add(134, 192, 0); // 2 - Green Colors::Add(134, 192, 0); // 2 - Green
Colors::Add(255, 173, 34); // 3 - Yellow Colors::Add(255, 173, 34); // 3 - Yellow
Colors::Add(0, 135, 193); // 4 - Blue Colors::Add(0, 135, 193); // 4 - Blue
Colors::Add(32, 197, 255); // 5 - Light Blue Colors::Add(32, 197, 255); // 5 - Light Blue
Colors::Add(151, 80, 221); // 6 - Pink Colors::Add(151, 80, 221); // 6 - Pink
Colors::Add(255, 255, 255); // 7 - White Colors::Add(255, 255, 255); // 7 - White
Colors::Add(0, 0, 0); // 8 - Team color (axis?) Colors::Add(0, 0, 0); // 8 - Team color (axis?)
Colors::Add(0, 0, 0); // 9 - Team color (allies?) Colors::Add(0, 0, 0); // 9 - Team color (allies?)
// Custom colors // Custom colors
Colors::Add(0, 0, 0); // 10 - Rainbow (:) Colors::Add(0, 0, 0); // 10 - Rainbow (:)
Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character!
} }
Colors::~Colors() Colors::~Colors()
{ {
Colors::ColorTable.clear(); Colors::ColorTable.clear();
} }
} }

View File

@ -1,40 +1,40 @@
namespace Components namespace Components
{ {
class Colors : public Component class Colors : public Component
{ {
public: public:
Colors(); Colors();
~Colors(); ~Colors();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Colors"; }; const char* getName() { return "Colors"; };
#endif #endif
static void Strip(const char* in, char* out, int max); static void Strip(const char* in, char* out, int max);
static std::string Strip(std::string in); static std::string Strip(std::string in);
static char Add(uint8_t r, uint8_t g, uint8_t b); static char Add(uint8_t r, uint8_t g, uint8_t b);
private: private:
struct HsvColor struct HsvColor
{ {
unsigned char h; unsigned char h;
unsigned char s; unsigned char s;
unsigned char v; unsigned char v;
}; };
static Dvar::Var NewColors; static Dvar::Var NewColors;
static DWORD HsvToRgb(HsvColor hsv); static DWORD HsvToRgb(HsvColor hsv);
static void ClientUserinfoChanged(); static void ClientUserinfoChanged();
static char* GetClientName(int localClientNum, int index, char *buf, size_t size); static char* GetClientName(int localClientNum, int index, char *buf, size_t size);
static void PatchColorLimit(char limit); static void PatchColorLimit(char limit);
static unsigned int ColorIndex(unsigned char); static unsigned int ColorIndex(unsigned char);
static void LookupColor(DWORD* color, char index); static void LookupColor(DWORD* color, char index);
static void LookupColorStub(); static void LookupColorStub();
static char* CleanStrStub(char* string); static char* CleanStrStub(char* string);
static std::vector<DWORD> ColorTable; static std::vector<DWORD> ColorTable;
}; };
} }

View File

@ -1,73 +1,73 @@
namespace Components namespace Components
{ {
class Command : public Component class Command : public Component
{ {
public: public:
class Params class Params
{ {
public: public:
Params() {}; Params() {};
virtual ~Params() {}; virtual ~Params() {};
virtual char* get(size_t index) = 0; virtual char* get(size_t index) = 0;
virtual size_t length() = 0; virtual size_t length() = 0;
virtual std::string join(size_t startIndex); virtual std::string join(size_t startIndex);
virtual char* operator[](size_t index); virtual char* operator[](size_t index);
}; };
class ClientParams : public Params class ClientParams : public Params
{ {
public: public:
ClientParams(unsigned int id) : commandId(id) {}; ClientParams(unsigned int id) : commandId(id) {};
ClientParams(const ClientParams &obj) : commandId(obj.commandId) {}; ClientParams(const ClientParams &obj) : commandId(obj.commandId) {};
ClientParams() : ClientParams(*Game::cmd_id) {}; ClientParams() : ClientParams(*Game::cmd_id) {};
char* get(size_t index) override; char* get(size_t index) override;
size_t length() override; size_t length() override;
private: private:
unsigned int commandId; unsigned int commandId;
}; };
class ServerParams : public Params class ServerParams : public Params
{ {
public: public:
ServerParams(unsigned int id) : commandId(id) {}; ServerParams(unsigned int id) : commandId(id) {};
ServerParams(const ServerParams &obj) : commandId(obj.commandId) {}; ServerParams(const ServerParams &obj) : commandId(obj.commandId) {};
ServerParams() : ServerParams(*Game::cmd_id_sv) {}; ServerParams() : ServerParams(*Game::cmd_id_sv) {};
char* get(size_t index) override; char* get(size_t index) override;
size_t length() override; size_t length() override;
private: private:
unsigned int commandId; unsigned int commandId;
}; };
typedef void(Callback)(Command::Params* params); typedef void(Callback)(Command::Params* params);
Command(); Command();
~Command(); ~Command();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Command"; }; const char* getName() { return "Command"; };
#endif #endif
static Game::cmd_function_t* Allocate(); static Game::cmd_function_t* Allocate();
static void Add(const char* name, Utils::Slot<Callback> callback); static void Add(const char* name, Utils::Slot<Callback> callback);
static void AddSV(const char* name, Utils::Slot<Callback> callback); static void AddSV(const char* name, Utils::Slot<Callback> callback);
static void AddRaw(const char* name, void(*callback)(), bool key = false); static void AddRaw(const char* name, void(*callback)(), bool key = false);
static void AddRawSV(const char* name, void(*callback)()); static void AddRawSV(const char* name, void(*callback)());
static void Execute(std::string command, bool sync = true); static void Execute(std::string command, bool sync = true);
static Game::cmd_function_t* Find(std::string command); static Game::cmd_function_t* Find(std::string command);
private: private:
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMap; static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMap;
static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMapSV; static std::unordered_map<std::string, Utils::Slot<Callback>> FunctionMapSV;
static void MainCallback(); static void MainCallback();
static void MainCallbackSV(); static void MainCallbackSV();
}; };
} }

View File

@ -1,242 +1,242 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
bool ConnectProtocol::Evaluated = false; bool ConnectProtocol::Evaluated = false;
std::string ConnectProtocol::ConnectString; std::string ConnectProtocol::ConnectString;
bool ConnectProtocol::IsEvaluated() bool ConnectProtocol::IsEvaluated()
{ {
return ConnectProtocol::Evaluated; return ConnectProtocol::Evaluated;
} }
bool ConnectProtocol::Used() bool ConnectProtocol::Used()
{ {
if (!ConnectProtocol::IsEvaluated()) if (!ConnectProtocol::IsEvaluated())
{ {
ConnectProtocol::EvaluateProtocol(); ConnectProtocol::EvaluateProtocol();
} }
return (!ConnectProtocol::ConnectString.empty()); return (!ConnectProtocol::ConnectString.empty());
} }
bool ConnectProtocol::InstallProtocol() bool ConnectProtocol::InstallProtocol()
{ {
HKEY hKey = NULL; HKEY hKey = NULL;
std::string data; std::string data;
char ownPth[MAX_PATH] = { 0 }; char ownPth[MAX_PATH] = { 0 };
char workdir[MAX_PATH] = { 0 }; char workdir[MAX_PATH] = { 0 };
DWORD dwsize = MAX_PATH; DWORD dwsize = MAX_PATH;
HMODULE hModule = GetModuleHandle(NULL); HMODULE hModule = GetModuleHandle(NULL);
if (hModule != NULL) if (hModule != NULL)
{ {
if (GetModuleFileNameA(hModule, ownPth, MAX_PATH) == ERROR) if (GetModuleFileNameA(hModule, ownPth, MAX_PATH) == ERROR)
{ {
return false; return false;
} }
if (GetModuleFileNameA(hModule, workdir, MAX_PATH) == ERROR) if (GetModuleFileNameA(hModule, workdir, MAX_PATH) == ERROR)
{ {
return false; return false;
} }
else else
{ {
char* endPtr = strstr(workdir, "iw4x.exe"); char* endPtr = strstr(workdir, "iw4x.exe");
if (endPtr != NULL) if (endPtr != NULL)
{ {
*endPtr = 0; *endPtr = 0;
} }
else else
{ {
return false; return false;
} }
} }
} }
else else
{ {
return false; return false;
} }
SetCurrentDirectoryA(workdir); SetCurrentDirectoryA(workdir);
LONG openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x\\shell\\open\\command", 0, KEY_ALL_ACCESS, &hKey); LONG openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x\\shell\\open\\command", 0, KEY_ALL_ACCESS, &hKey);
if (openRes == ERROR_SUCCESS) if (openRes == ERROR_SUCCESS)
{ {
char regred[MAX_PATH] = { 0 }; char regred[MAX_PATH] = { 0 };
// Check if the game has been moved. // Check if the game has been moved.
openRes = RegQueryValueExA(hKey, 0, 0, 0, reinterpret_cast<BYTE*>(regred), &dwsize); openRes = RegQueryValueExA(hKey, 0, 0, 0, reinterpret_cast<BYTE*>(regred), &dwsize);
if (openRes == ERROR_SUCCESS) if (openRes == ERROR_SUCCESS)
{ {
char* endPtr = strstr(regred, "\" \"%1\""); char* endPtr = strstr(regred, "\" \"%1\"");
if (endPtr != NULL) if (endPtr != NULL)
{ {
*endPtr = 0; *endPtr = 0;
} }
else else
{ {
return false; return false;
} }
RegCloseKey(hKey); RegCloseKey(hKey);
if (strcmp(regred + 1, ownPth)) if (strcmp(regred + 1, ownPth))
{ {
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
} }
else else
{ {
return true; return true;
} }
} }
else else
{ {
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
} }
} }
else else
{ {
openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x"); openRes = RegDeleteKeyA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x");
} }
// Open SOFTWARE\\Classes // Open SOFTWARE\\Classes
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &hKey); openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes", 0, KEY_ALL_ACCESS, &hKey);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
// Create SOFTWARE\\Classes\\iw4x // Create SOFTWARE\\Classes\\iw4x
openRes = RegCreateKeyExA(hKey, "iw4x", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); openRes = RegCreateKeyExA(hKey, "iw4x", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
// Write URL:IW4x Protocol // Write URL:IW4x Protocol
data = "URL:IW4x Protocol"; data = "URL:IW4x Protocol";
openRes = RegSetValueExA(hKey, "URL Protocol", 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1); openRes = RegSetValueExA(hKey, "URL Protocol", 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
RegCloseKey(hKey); RegCloseKey(hKey);
return false; return false;
} }
// Create SOFTWARE\\Classes\\iw4x\\DefaultIcon // Create SOFTWARE\\Classes\\iw4x\\DefaultIcon
openRes = RegCreateKeyExA(hKey, "DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); openRes = RegCreateKeyExA(hKey, "DefaultIcon", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
data = Utils::String::VA("%s,1", ownPth); data = Utils::String::VA("%s,1", ownPth);
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1); openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
RegCloseKey(hKey); RegCloseKey(hKey);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
RegCloseKey(hKey); RegCloseKey(hKey);
return false; return false;
} }
openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x", 0, KEY_ALL_ACCESS, &hKey); openRes = RegOpenKeyExA(HKEY_CURRENT_USER, "SOFTWARE\\Classes\\iw4x", 0, KEY_ALL_ACCESS, &hKey);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
openRes = RegCreateKeyExA(hKey, "shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0); openRes = RegCreateKeyExA(hKey, "shell\\open\\command", 0, 0, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0, &hKey, 0);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
data = Utils::String::VA("\"%s\" \"%s\"", ownPth, "%1"); data = Utils::String::VA("\"%s\" \"%s\"", ownPth, "%1");
openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1); openRes = RegSetValueExA(hKey, 0, 0, REG_SZ, reinterpret_cast<const BYTE*>(data.data()), data.size() + 1);
RegCloseKey(hKey); RegCloseKey(hKey);
if (openRes != ERROR_SUCCESS) if (openRes != ERROR_SUCCESS)
{ {
return false; return false;
} }
return true; return true;
} }
void ConnectProtocol::EvaluateProtocol() void ConnectProtocol::EvaluateProtocol()
{ {
if (ConnectProtocol::Evaluated) return; if (ConnectProtocol::Evaluated) return;
ConnectProtocol::Evaluated = true; ConnectProtocol::Evaluated = true;
std::string cmdLine = GetCommandLineA(); std::string cmdLine = GetCommandLineA();
auto pos = cmdLine.find("iw4x://"); auto pos = cmdLine.find("iw4x://");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
cmdLine = cmdLine.substr(pos + 7); cmdLine = cmdLine.substr(pos + 7);
pos = cmdLine.find_first_of("/"); pos = cmdLine.find_first_of("/");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
cmdLine = cmdLine.substr(0, pos); cmdLine = cmdLine.substr(0, pos);
} }
ConnectProtocol::ConnectString = cmdLine; ConnectProtocol::ConnectString = cmdLine;
} }
} }
void ConnectProtocol::Invocation() void ConnectProtocol::Invocation()
{ {
if (ConnectProtocol::Used()) if (ConnectProtocol::Used())
{ {
if (!FastFiles::Ready()) if (!FastFiles::Ready())
{ {
QuickPatch::Once(ConnectProtocol::Invocation); QuickPatch::Once(ConnectProtocol::Invocation);
} }
else else
{ {
Command::Execute(Utils::String::VA("connect %s", ConnectProtocol::ConnectString.data()), false); Command::Execute(Utils::String::VA("connect %s", ConnectProtocol::ConnectString.data()), false);
} }
} }
} }
ConnectProtocol::ConnectProtocol() ConnectProtocol::ConnectProtocol()
{ {
// IPC handler // IPC handler
IPCPipe::On("connect", [] (std::string data) IPCPipe::On("connect", [] (std::string data)
{ {
Command::Execute(Utils::String::VA("connect %s", data.data()), false); Command::Execute(Utils::String::VA("connect %s", data.data()), false);
}); });
// Invocation handler // Invocation handler
QuickPatch::Once(ConnectProtocol::Invocation); QuickPatch::Once(ConnectProtocol::Invocation);
ConnectProtocol::InstallProtocol(); ConnectProtocol::InstallProtocol();
ConnectProtocol::EvaluateProtocol(); ConnectProtocol::EvaluateProtocol();
// Fire protocol handlers // Fire protocol handlers
// Make sure this happens after the pipe-initialization! // Make sure this happens after the pipe-initialization!
if (ConnectProtocol::Used()) if (ConnectProtocol::Used())
{ {
if (!Singleton::IsFirstInstance()) if (!Singleton::IsFirstInstance())
{ {
IPCPipe::Write("connect", ConnectProtocol::ConnectString); IPCPipe::Write("connect", ConnectProtocol::ConnectString);
ExitProcess(0); ExitProcess(0);
} }
else else
{ {
// Only skip intro here, invocation will be done later. // Only skip intro here, invocation will be done later.
//Utils::Hook::Set<BYTE>(0x60BECF, 0xEB); //Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
} }
} }
} }
} }

View File

@ -1,24 +1,24 @@
namespace Components namespace Components
{ {
class ConnectProtocol : public Component class ConnectProtocol : public Component
{ {
public: public:
ConnectProtocol(); ConnectProtocol();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "ConnectProtocol"; }; const char* getName() { return "ConnectProtocol"; };
#endif #endif
static bool IsEvaluated(); static bool IsEvaluated();
static bool Used(); static bool Used();
private: private:
static bool Evaluated; static bool Evaluated;
static std::string ConnectString; static std::string ConnectString;
static void EvaluateProtocol(); static void EvaluateProtocol();
static bool InstallProtocol(); static bool InstallProtocol();
static void Invocation(); static void Invocation();
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,69 +1,69 @@
#define OUTPUT_HEIGHT 250 #define OUTPUT_HEIGHT 250
#define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2)) #define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2))
namespace Components namespace Components
{ {
class Console : public Component class Console : public Component
{ {
public: public:
Console(); Console();
~Console(); ~Console();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Console"; }; const char* getName() { return "Console"; };
#endif #endif
static void SetSkipShutdown(); static void SetSkipShutdown();
static void FreeNativeConsole(); static void FreeNativeConsole();
private: private:
// Text-based console stuff // Text-based console stuff
static WINDOW* OutputWindow; static WINDOW* OutputWindow;
static WINDOW* InputWindow; static WINDOW* InputWindow;
static WINDOW* InfoWindow; static WINDOW* InfoWindow;
static int Width; static int Width;
static int Height; static int Height;
static int OutputTop; static int OutputTop;
static int OutBuffer; static int OutBuffer;
static int LastRefresh; static int LastRefresh;
static char LineBuffer[1024]; static char LineBuffer[1024];
static char LineBuffer2[1024]; static char LineBuffer2[1024];
static int LineBufferIndex; static int LineBufferIndex;
static bool HasConsole; static bool HasConsole;
static bool SkipShutdown; static bool SkipShutdown;
static std::thread ConsoleThread; static std::thread ConsoleThread;
static Game::SafeArea OriginalSafeArea; static Game::SafeArea OriginalSafeArea;
static void ShowPrompt(); static void ShowPrompt();
static void RefreshStatus(); static void RefreshStatus();
static void RefreshOutput(); static void RefreshOutput();
static void ScrollOutput(int amount); static void ScrollOutput(int amount);
static const char* Input(); static const char* Input();
static void Print(const char* message); static void Print(const char* message);
static void Error(const char* format, ...); static void Error(const char* format, ...);
static void Create(); static void Create();
static void Destroy(); static void Destroy();
static void StdOutPrint(const char* message); static void StdOutPrint(const char* message);
static void StdOutError(const char* format, ...); static void StdOutError(const char* format, ...);
static void ConsoleRunner(); static void ConsoleRunner();
static void DrawSolidConsoleStub(); static void DrawSolidConsoleStub();
static void StoreSafeArea(); static void StoreSafeArea();
static void RestoreSafeArea(); static void RestoreSafeArea();
static void ToggleConsole(); static void ToggleConsole();
static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType); static char** GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType);
static Game::dvar_t* RegisterConColor(const char* name, float r, float g, float b, float a, float min, float max, int flags, const char* description); static Game::dvar_t* RegisterConColor(const char* name, float r, float g, float b, float a, float min, float max, int flags, const char* description);
}; };
} }

View File

@ -1,174 +1,174 @@
namespace Components namespace Components
{ {
class D3D9Ex : public Component class D3D9Ex : public Component
{ {
public: public:
D3D9Ex(); D3D9Ex();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "D3D9Ex"; }; const char* getName() { return "D3D9Ex"; };
#endif #endif
private: private:
class D3D9Device : public IDirect3DDevice9 class D3D9Device : public IDirect3DDevice9
{ {
public: public:
D3D9Device(IDirect3DDevice9* pOriginal) : m_pIDirect3DDevice9(pOriginal) {}; D3D9Device(IDirect3DDevice9* pOriginal) : m_pIDirect3DDevice9(pOriginal) {};
virtual ~D3D9Device(void) {}; virtual ~D3D9Device(void) {};
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj); HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj);
ULONG __stdcall AddRef(void); ULONG __stdcall AddRef(void);
ULONG __stdcall Release(void); ULONG __stdcall Release(void);
HRESULT __stdcall TestCooperativeLevel(void); HRESULT __stdcall TestCooperativeLevel(void);
UINT __stdcall GetAvailableTextureMem(void); UINT __stdcall GetAvailableTextureMem(void);
HRESULT __stdcall EvictManagedResources(void); HRESULT __stdcall EvictManagedResources(void);
HRESULT __stdcall GetDirect3D(IDirect3D9** ppD3D9); HRESULT __stdcall GetDirect3D(IDirect3D9** ppD3D9);
HRESULT __stdcall GetDeviceCaps(D3DCAPS9* pCaps); HRESULT __stdcall GetDeviceCaps(D3DCAPS9* pCaps);
HRESULT __stdcall GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode); HRESULT __stdcall GetDisplayMode(UINT iSwapChain, D3DDISPLAYMODE* pMode);
HRESULT __stdcall GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters); HRESULT __stdcall GetCreationParameters(D3DDEVICE_CREATION_PARAMETERS *pParameters);
HRESULT __stdcall SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap); HRESULT __stdcall SetCursorProperties(UINT XHotSpot, UINT YHotSpot, IDirect3DSurface9* pCursorBitmap);
void __stdcall SetCursorPosition(int X, int Y, DWORD Flags); void __stdcall SetCursorPosition(int X, int Y, DWORD Flags);
BOOL __stdcall ShowCursor(BOOL bShow); BOOL __stdcall ShowCursor(BOOL bShow);
HRESULT __stdcall CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain); HRESULT __stdcall CreateAdditionalSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DSwapChain9** pSwapChain);
HRESULT __stdcall GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain); HRESULT __stdcall GetSwapChain(UINT iSwapChain, IDirect3DSwapChain9** pSwapChain);
UINT __stdcall GetNumberOfSwapChains(void); UINT __stdcall GetNumberOfSwapChains(void);
HRESULT __stdcall Reset(D3DPRESENT_PARAMETERS* pPresentationParameters); HRESULT __stdcall Reset(D3DPRESENT_PARAMETERS* pPresentationParameters);
HRESULT __stdcall Present(CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion); HRESULT __stdcall Present(CONST RECT* pSourceRect, CONST RECT* pDestRect, HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion);
HRESULT __stdcall GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer); HRESULT __stdcall GetBackBuffer(UINT iSwapChain, UINT iBackBuffer, D3DBACKBUFFER_TYPE Type, IDirect3DSurface9** ppBackBuffer);
HRESULT __stdcall GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus); HRESULT __stdcall GetRasterStatus(UINT iSwapChain, D3DRASTER_STATUS* pRasterStatus);
HRESULT __stdcall SetDialogBoxMode(BOOL bEnableDialogs); HRESULT __stdcall SetDialogBoxMode(BOOL bEnableDialogs);
void __stdcall SetGammaRamp(UINT iSwapChain, DWORD Flags, CONST D3DGAMMARAMP* pRamp); void __stdcall SetGammaRamp(UINT iSwapChain, DWORD Flags, CONST D3DGAMMARAMP* pRamp);
void __stdcall GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp); void __stdcall GetGammaRamp(UINT iSwapChain, D3DGAMMARAMP* pRamp);
HRESULT __stdcall CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle); HRESULT __stdcall CreateTexture(UINT Width, UINT Height, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DTexture9** ppTexture, HANDLE* pSharedHandle);
HRESULT __stdcall CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle); HRESULT __stdcall CreateVolumeTexture(UINT Width, UINT Height, UINT Depth, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DVolumeTexture9** ppVolumeTexture, HANDLE* pSharedHandle);
HRESULT __stdcall CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle); HRESULT __stdcall CreateCubeTexture(UINT EdgeLength, UINT Levels, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DCubeTexture9** ppCubeTexture, HANDLE* pSharedHandle);
HRESULT __stdcall CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle); HRESULT __stdcall CreateVertexBuffer(UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, IDirect3DVertexBuffer9** ppVertexBuffer, HANDLE* pSharedHandle);
HRESULT __stdcall CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle); HRESULT __stdcall CreateIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, D3DPOOL Pool, IDirect3DIndexBuffer9** ppIndexBuffer, HANDLE* pSharedHandle);
HRESULT __stdcall CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle); HRESULT __stdcall CreateRenderTarget(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Lockable, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle);
HRESULT __stdcall CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle); HRESULT __stdcall CreateDepthStencilSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, DWORD MultisampleQuality, BOOL Discard, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle);
HRESULT __stdcall UpdateSurface(IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, CONST POINT* pDestPoint); HRESULT __stdcall UpdateSurface(IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestinationSurface, CONST POINT* pDestPoint);
HRESULT __stdcall UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture); HRESULT __stdcall UpdateTexture(IDirect3DBaseTexture9* pSourceTexture, IDirect3DBaseTexture9* pDestinationTexture);
HRESULT __stdcall GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface); HRESULT __stdcall GetRenderTargetData(IDirect3DSurface9* pRenderTarget, IDirect3DSurface9* pDestSurface);
HRESULT __stdcall GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface); HRESULT __stdcall GetFrontBufferData(UINT iSwapChain, IDirect3DSurface9* pDestSurface);
HRESULT __stdcall StretchRect(IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface, CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter); HRESULT __stdcall StretchRect(IDirect3DSurface9* pSourceSurface, CONST RECT* pSourceRect, IDirect3DSurface9* pDestSurface, CONST RECT* pDestRect, D3DTEXTUREFILTERTYPE Filter);
HRESULT __stdcall ColorFill(IDirect3DSurface9* pSurface, CONST RECT* pRect, D3DCOLOR color); HRESULT __stdcall ColorFill(IDirect3DSurface9* pSurface, CONST RECT* pRect, D3DCOLOR color);
HRESULT __stdcall CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle); HRESULT __stdcall CreateOffscreenPlainSurface(UINT Width, UINT Height, D3DFORMAT Format, D3DPOOL Pool, IDirect3DSurface9** ppSurface, HANDLE* pSharedHandle);
HRESULT __stdcall SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget); HRESULT __stdcall SetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9* pRenderTarget);
HRESULT __stdcall GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget); HRESULT __stdcall GetRenderTarget(DWORD RenderTargetIndex, IDirect3DSurface9** ppRenderTarget);
HRESULT __stdcall SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil); HRESULT __stdcall SetDepthStencilSurface(IDirect3DSurface9* pNewZStencil);
HRESULT __stdcall GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface); HRESULT __stdcall GetDepthStencilSurface(IDirect3DSurface9** ppZStencilSurface);
HRESULT __stdcall BeginScene(void); HRESULT __stdcall BeginScene(void);
HRESULT __stdcall EndScene(void); HRESULT __stdcall EndScene(void);
HRESULT __stdcall Clear(DWORD Count, CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil); HRESULT __stdcall Clear(DWORD Count, CONST D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil);
HRESULT __stdcall SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix); HRESULT __stdcall SetTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix);
HRESULT __stdcall GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix); HRESULT __stdcall GetTransform(D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix);
HRESULT __stdcall MultiplyTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix); HRESULT __stdcall MultiplyTransform(D3DTRANSFORMSTATETYPE State, CONST D3DMATRIX* pMatrix);
HRESULT __stdcall SetViewport(CONST D3DVIEWPORT9* pViewport); HRESULT __stdcall SetViewport(CONST D3DVIEWPORT9* pViewport);
HRESULT __stdcall GetViewport(D3DVIEWPORT9* pViewport); HRESULT __stdcall GetViewport(D3DVIEWPORT9* pViewport);
HRESULT __stdcall SetMaterial(CONST D3DMATERIAL9* pMaterial); HRESULT __stdcall SetMaterial(CONST D3DMATERIAL9* pMaterial);
HRESULT __stdcall GetMaterial(D3DMATERIAL9* pMaterial); HRESULT __stdcall GetMaterial(D3DMATERIAL9* pMaterial);
HRESULT __stdcall SetLight(DWORD Index, CONST D3DLIGHT9* pLight); HRESULT __stdcall SetLight(DWORD Index, CONST D3DLIGHT9* pLight);
HRESULT __stdcall GetLight(DWORD Index, D3DLIGHT9* pLight); HRESULT __stdcall GetLight(DWORD Index, D3DLIGHT9* pLight);
HRESULT __stdcall LightEnable(DWORD Index, BOOL Enable); HRESULT __stdcall LightEnable(DWORD Index, BOOL Enable);
HRESULT __stdcall GetLightEnable(DWORD Index, BOOL* pEnable); HRESULT __stdcall GetLightEnable(DWORD Index, BOOL* pEnable);
HRESULT __stdcall SetClipPlane(DWORD Index, CONST float* pPlane); HRESULT __stdcall SetClipPlane(DWORD Index, CONST float* pPlane);
HRESULT __stdcall GetClipPlane(DWORD Index, float* pPlane); HRESULT __stdcall GetClipPlane(DWORD Index, float* pPlane);
HRESULT __stdcall SetRenderState(D3DRENDERSTATETYPE State, DWORD Value); HRESULT __stdcall SetRenderState(D3DRENDERSTATETYPE State, DWORD Value);
HRESULT __stdcall GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue); HRESULT __stdcall GetRenderState(D3DRENDERSTATETYPE State, DWORD* pValue);
HRESULT __stdcall CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB); HRESULT __stdcall CreateStateBlock(D3DSTATEBLOCKTYPE Type, IDirect3DStateBlock9** ppSB);
HRESULT __stdcall BeginStateBlock(void); HRESULT __stdcall BeginStateBlock(void);
HRESULT __stdcall EndStateBlock(IDirect3DStateBlock9** ppSB); HRESULT __stdcall EndStateBlock(IDirect3DStateBlock9** ppSB);
HRESULT __stdcall SetClipStatus(CONST D3DCLIPSTATUS9* pClipStatus); HRESULT __stdcall SetClipStatus(CONST D3DCLIPSTATUS9* pClipStatus);
HRESULT __stdcall GetClipStatus(D3DCLIPSTATUS9* pClipStatus); HRESULT __stdcall GetClipStatus(D3DCLIPSTATUS9* pClipStatus);
HRESULT __stdcall GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture); HRESULT __stdcall GetTexture(DWORD Stage, IDirect3DBaseTexture9** ppTexture);
HRESULT __stdcall SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture); HRESULT __stdcall SetTexture(DWORD Stage, IDirect3DBaseTexture9* pTexture);
HRESULT __stdcall GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue); HRESULT __stdcall GetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue);
HRESULT __stdcall SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); HRESULT __stdcall SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
HRESULT __stdcall GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue); HRESULT __stdcall GetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD* pValue);
HRESULT __stdcall SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); HRESULT __stdcall SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);
HRESULT __stdcall ValidateDevice(DWORD* pNumPasses); HRESULT __stdcall ValidateDevice(DWORD* pNumPasses);
HRESULT __stdcall SetPaletteEntries(UINT PaletteNumber, CONST PALETTEENTRY* pEntries); HRESULT __stdcall SetPaletteEntries(UINT PaletteNumber, CONST PALETTEENTRY* pEntries);
HRESULT __stdcall GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries); HRESULT __stdcall GetPaletteEntries(UINT PaletteNumber, PALETTEENTRY* pEntries);
HRESULT __stdcall SetCurrentTexturePalette(UINT PaletteNumber); HRESULT __stdcall SetCurrentTexturePalette(UINT PaletteNumber);
HRESULT __stdcall GetCurrentTexturePalette(UINT *PaletteNumber); HRESULT __stdcall GetCurrentTexturePalette(UINT *PaletteNumber);
HRESULT __stdcall SetScissorRect(CONST RECT* pRect); HRESULT __stdcall SetScissorRect(CONST RECT* pRect);
HRESULT __stdcall GetScissorRect(RECT* pRect); HRESULT __stdcall GetScissorRect(RECT* pRect);
HRESULT __stdcall SetSoftwareVertexProcessing(BOOL bSoftware); HRESULT __stdcall SetSoftwareVertexProcessing(BOOL bSoftware);
BOOL __stdcall GetSoftwareVertexProcessing(void); BOOL __stdcall GetSoftwareVertexProcessing(void);
HRESULT __stdcall SetNPatchMode(float nSegments); HRESULT __stdcall SetNPatchMode(float nSegments);
float __stdcall GetNPatchMode(void); float __stdcall GetNPatchMode(void);
HRESULT __stdcall DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount); HRESULT __stdcall DrawPrimitive(D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount);
HRESULT __stdcall DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount); HRESULT __stdcall DrawIndexedPrimitive(D3DPRIMITIVETYPE PrimitiveType, INT BaseVertexIndex, UINT MinVertexIndex, UINT NumVertices, UINT startIndex, UINT primCount);
HRESULT __stdcall DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride); HRESULT __stdcall DrawPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
HRESULT __stdcall DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, CONST void* pIndexData, D3DFORMAT IndexDataFormat, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride); HRESULT __stdcall DrawIndexedPrimitiveUP(D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertices, UINT PrimitiveCount, CONST void* pIndexData, D3DFORMAT IndexDataFormat, CONST void* pVertexStreamZeroData, UINT VertexStreamZeroStride);
HRESULT __stdcall ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags); HRESULT __stdcall ProcessVertices(UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IDirect3DVertexBuffer9* pDestBuffer, IDirect3DVertexDeclaration9* pVertexDecl, DWORD Flags);
HRESULT __stdcall CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl); HRESULT __stdcall CreateVertexDeclaration(CONST D3DVERTEXELEMENT9* pVertexElements, IDirect3DVertexDeclaration9** ppDecl);
HRESULT __stdcall SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl); HRESULT __stdcall SetVertexDeclaration(IDirect3DVertexDeclaration9* pDecl);
HRESULT __stdcall GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl); HRESULT __stdcall GetVertexDeclaration(IDirect3DVertexDeclaration9** ppDecl);
HRESULT __stdcall SetFVF(DWORD FVF); HRESULT __stdcall SetFVF(DWORD FVF);
HRESULT __stdcall GetFVF(DWORD* pFVF); HRESULT __stdcall GetFVF(DWORD* pFVF);
HRESULT __stdcall CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader); HRESULT __stdcall CreateVertexShader(CONST DWORD* pFunction, IDirect3DVertexShader9** ppShader);
HRESULT __stdcall SetVertexShader(IDirect3DVertexShader9* pShader); HRESULT __stdcall SetVertexShader(IDirect3DVertexShader9* pShader);
HRESULT __stdcall GetVertexShader(IDirect3DVertexShader9** ppShader); HRESULT __stdcall GetVertexShader(IDirect3DVertexShader9** ppShader);
HRESULT __stdcall SetVertexShaderConstantF(UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount); HRESULT __stdcall SetVertexShaderConstantF(UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
HRESULT __stdcall GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount); HRESULT __stdcall GetVertexShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount);
HRESULT __stdcall SetVertexShaderConstantI(UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount); HRESULT __stdcall SetVertexShaderConstantI(UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount);
HRESULT __stdcall GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount); HRESULT __stdcall GetVertexShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount);
HRESULT __stdcall SetVertexShaderConstantB(UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount); HRESULT __stdcall SetVertexShaderConstantB(UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount);
HRESULT __stdcall GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount); HRESULT __stdcall GetVertexShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount);
HRESULT __stdcall SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride); HRESULT __stdcall SetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9* pStreamData, UINT OffsetInBytes, UINT Stride);
HRESULT __stdcall GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* OffsetInBytes, UINT* pStride); HRESULT __stdcall GetStreamSource(UINT StreamNumber, IDirect3DVertexBuffer9** ppStreamData, UINT* OffsetInBytes, UINT* pStride);
HRESULT __stdcall SetStreamSourceFreq(UINT StreamNumber, UINT Divider); HRESULT __stdcall SetStreamSourceFreq(UINT StreamNumber, UINT Divider);
HRESULT __stdcall GetStreamSourceFreq(UINT StreamNumber, UINT* Divider); HRESULT __stdcall GetStreamSourceFreq(UINT StreamNumber, UINT* Divider);
HRESULT __stdcall SetIndices(IDirect3DIndexBuffer9* pIndexData); HRESULT __stdcall SetIndices(IDirect3DIndexBuffer9* pIndexData);
HRESULT __stdcall GetIndices(IDirect3DIndexBuffer9** ppIndexData); HRESULT __stdcall GetIndices(IDirect3DIndexBuffer9** ppIndexData);
HRESULT __stdcall CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader); HRESULT __stdcall CreatePixelShader(CONST DWORD* pFunction, IDirect3DPixelShader9** ppShader);
HRESULT __stdcall SetPixelShader(IDirect3DPixelShader9* pShader); HRESULT __stdcall SetPixelShader(IDirect3DPixelShader9* pShader);
HRESULT __stdcall GetPixelShader(IDirect3DPixelShader9** ppShader); HRESULT __stdcall GetPixelShader(IDirect3DPixelShader9** ppShader);
HRESULT __stdcall SetPixelShaderConstantF(UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount); HRESULT __stdcall SetPixelShaderConstantF(UINT StartRegister, CONST float* pConstantData, UINT Vector4fCount);
HRESULT __stdcall GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount); HRESULT __stdcall GetPixelShaderConstantF(UINT StartRegister, float* pConstantData, UINT Vector4fCount);
HRESULT __stdcall SetPixelShaderConstantI(UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount); HRESULT __stdcall SetPixelShaderConstantI(UINT StartRegister, CONST int* pConstantData, UINT Vector4iCount);
HRESULT __stdcall GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount); HRESULT __stdcall GetPixelShaderConstantI(UINT StartRegister, int* pConstantData, UINT Vector4iCount);
HRESULT __stdcall SetPixelShaderConstantB(UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount); HRESULT __stdcall SetPixelShaderConstantB(UINT StartRegister, CONST BOOL* pConstantData, UINT BoolCount);
HRESULT __stdcall GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount); HRESULT __stdcall GetPixelShaderConstantB(UINT StartRegister, BOOL* pConstantData, UINT BoolCount);
HRESULT __stdcall DrawRectPatch(UINT Handle, CONST float* pNumSegs, CONST D3DRECTPATCH_INFO* pRectPatchInfo); HRESULT __stdcall DrawRectPatch(UINT Handle, CONST float* pNumSegs, CONST D3DRECTPATCH_INFO* pRectPatchInfo);
HRESULT __stdcall DrawTriPatch(UINT Handle, CONST float* pNumSegs, CONST D3DTRIPATCH_INFO* pTriPatchInfo); HRESULT __stdcall DrawTriPatch(UINT Handle, CONST float* pNumSegs, CONST D3DTRIPATCH_INFO* pTriPatchInfo);
HRESULT __stdcall DeletePatch(UINT Handle); HRESULT __stdcall DeletePatch(UINT Handle);
HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery); HRESULT __stdcall CreateQuery(D3DQUERYTYPE Type, IDirect3DQuery9** ppQuery);
private: private:
IDirect3DDevice9 *m_pIDirect3DDevice9; IDirect3DDevice9 *m_pIDirect3DDevice9;
}; };
class D3D9 : public IDirect3D9 class D3D9 : public IDirect3D9
{ {
public: public:
D3D9(IDirect3D9Ex *pOriginal) : m_pIDirect3D9(pOriginal) {}; D3D9(IDirect3D9Ex *pOriginal) : m_pIDirect3D9(pOriginal) {};
virtual ~D3D9(void) {}; virtual ~D3D9(void) {};
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj); HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObj);
ULONG __stdcall AddRef(void); ULONG __stdcall AddRef(void);
ULONG __stdcall Release(void); ULONG __stdcall Release(void);
HRESULT __stdcall RegisterSoftwareDevice(void* pInitializeFunction); HRESULT __stdcall RegisterSoftwareDevice(void* pInitializeFunction);
UINT __stdcall GetAdapterCount(void); UINT __stdcall GetAdapterCount(void);
HRESULT __stdcall GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier); HRESULT __stdcall GetAdapterIdentifier(UINT Adapter, DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier);
UINT __stdcall GetAdapterModeCount(UINT Adapter, D3DFORMAT Format); UINT __stdcall GetAdapterModeCount(UINT Adapter, D3DFORMAT Format);
HRESULT __stdcall EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode); HRESULT __stdcall EnumAdapterModes(UINT Adapter, D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE* pMode);
HRESULT __stdcall GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode); HRESULT __stdcall GetAdapterDisplayMode(UINT Adapter, D3DDISPLAYMODE* pMode);
HRESULT __stdcall CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed); HRESULT __stdcall CheckDeviceType(UINT iAdapter, D3DDEVTYPE DevType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL bWindowed);
HRESULT __stdcall CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat); HRESULT __stdcall CheckDeviceFormat(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType, D3DFORMAT CheckFormat);
HRESULT __stdcall CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels); HRESULT __stdcall CheckDeviceMultiSampleType(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed, D3DMULTISAMPLE_TYPE MultiSampleType, DWORD* pQualityLevels);
HRESULT __stdcall CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat); HRESULT __stdcall CheckDepthStencilMatch(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat, D3DFORMAT DepthStencilFormat);
HRESULT __stdcall CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat); HRESULT __stdcall CheckDeviceFormatConversion(UINT Adapter, D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat);
HRESULT __stdcall GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps); HRESULT __stdcall GetDeviceCaps(UINT Adapter, D3DDEVTYPE DeviceType, D3DCAPS9* pCaps);
HMONITOR __stdcall GetAdapterMonitor(UINT Adapter); HMONITOR __stdcall GetAdapterMonitor(UINT Adapter);
HRESULT __stdcall CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface); HRESULT __stdcall CreateDevice(UINT Adapter, D3DDEVTYPE DeviceType, HWND hFocusWindow, DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface);
private: private:
IDirect3D9 *m_pIDirect3D9; IDirect3D9 *m_pIDirect3D9;
}; };
static IDirect3D9* __stdcall Direct3DCreate9Stub(UINT sdk); static IDirect3D9* __stdcall Direct3DCreate9Stub(UINT sdk);
}; };
} }

View File

@ -1,43 +1,43 @@
namespace Components namespace Components
{ {
class Dedicated : public Component class Dedicated : public Component
{ {
public: public:
typedef void(Callback)(); typedef void(Callback)();
Dedicated(); Dedicated();
~Dedicated(); ~Dedicated();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Dedicated"; }; const char* getName() { return "Dedicated"; };
#endif #endif
static bool IsEnabled(); static bool IsEnabled();
static void Heartbeat(); static void Heartbeat();
static void OnFrame(Utils::Slot<Callback> callback); static void OnFrame(Utils::Slot<Callback> callback);
static void Once(Utils::Slot<Callback> callback); static void Once(Utils::Slot<Callback> callback);
private: private:
static Utils::Signal<Callback> FrameSignal; static Utils::Signal<Callback> FrameSignal;
static Utils::Signal<Callback> FrameOnceSignal; static Utils::Signal<Callback> FrameOnceSignal;
static bool SendChat; static bool SendChat;
static void MapRotate(); static void MapRotate();
static void FrameHandler(); static void FrameHandler();
static void FrameStub(); static void FrameStub();
static void InitDedicatedServer(); static void InitDedicatedServer();
static void PostInitialization(); static void PostInitialization();
static void PostInitializationStub(); static void PostInitializationStub();
static const char* EvaluateSay(char* text); static const char* EvaluateSay(char* text);
static void PreSayStub(); static void PreSayStub();
static void PostSayStub(); static void PostSayStub();
static void TimeWrapStub(int code, const char* message); static void TimeWrapStub(int code, const char* message);
}; };
} }

View File

@ -1,108 +1,108 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
bool Discovery::IsTerminating = false; bool Discovery::IsTerminating = false;
bool Discovery::IsPerforming = false; bool Discovery::IsPerforming = false;
std::thread Discovery::Thread; std::thread Discovery::Thread;
std::string Discovery::Challenge; std::string Discovery::Challenge;
void Discovery::Perform() void Discovery::Perform()
{ {
Discovery::IsPerforming = true; Discovery::IsPerforming = true;
} }
Discovery::Discovery() Discovery::Discovery()
{ {
Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::dvar_flag::DVAR_FLAG_SAVED, "Minimum scan range port for local server discovery"); Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::dvar_flag::DVAR_FLAG_SAVED, "Minimum scan range port for local server discovery");
Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::dvar_flag::DVAR_FLAG_SAVED, "Maximum scan range port for local server discovery"); Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::dvar_flag::DVAR_FLAG_SAVED, "Maximum scan range port for local server discovery");
// An additional thread prevents lags // An additional thread prevents lags
// Not sure if that's the best way though // Not sure if that's the best way though
Discovery::IsPerforming = false; Discovery::IsPerforming = false;
Discovery::IsTerminating = false; Discovery::IsTerminating = false;
Discovery::Thread = std::thread([] () Discovery::Thread = std::thread([] ()
{ {
while (!Discovery::IsTerminating) while (!Discovery::IsTerminating)
{ {
if (Discovery::IsPerforming) if (Discovery::IsPerforming)
{ {
int start = Game::Sys_Milliseconds(); int start = Game::Sys_Milliseconds();
Logger::Print("Starting local server discovery...\n"); Logger::Print("Starting local server discovery...\n");
Discovery::Challenge = Utils::Cryptography::Rand::GenerateChallenge(); Discovery::Challenge = Utils::Cryptography::Rand::GenerateChallenge();
unsigned int minPort = Dvar::Var("net_discoveryPortRangeMin").get<unsigned int>(); unsigned int minPort = Dvar::Var("net_discoveryPortRangeMin").get<unsigned int>();
unsigned int maxPort = Dvar::Var("net_discoveryPortRangeMax").get<unsigned int>(); unsigned int maxPort = Dvar::Var("net_discoveryPortRangeMax").get<unsigned int>();
Network::BroadcastRange(minPort, maxPort, Utils::String::VA("discovery %s", Discovery::Challenge.data())); Network::BroadcastRange(minPort, maxPort, Utils::String::VA("discovery %s", Discovery::Challenge.data()));
Logger::Print("Discovery sent within %dms, awaiting responses...\n", Game::Sys_Milliseconds() - start); Logger::Print("Discovery sent within %dms, awaiting responses...\n", Game::Sys_Milliseconds() - start);
Discovery::IsPerforming = false; Discovery::IsPerforming = false;
} }
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(50ms);
} }
}); });
Network::Handle("discovery", [] (Network::Address address, std::string data) Network::Handle("discovery", [] (Network::Address address, std::string data)
{ {
if (address.isSelf()) return; if (address.isSelf()) return;
if (!address.isLocal()) if (!address.isLocal())
{ {
Logger::Print("Received discovery request from non-local address: %s\n", address.getCString()); Logger::Print("Received discovery request from non-local address: %s\n", address.getCString());
return; return;
} }
Logger::Print("Received discovery request from %s\n", address.getCString()); Logger::Print("Received discovery request from %s\n", address.getCString());
Network::SendCommand(address, "discoveryResponse", data); Network::SendCommand(address, "discoveryResponse", data);
}); });
Network::Handle("discoveryResponse", [] (Network::Address address, std::string data) Network::Handle("discoveryResponse", [] (Network::Address address, std::string data)
{ {
if (address.isSelf()) return; if (address.isSelf()) return;
if (!address.isLocal()) if (!address.isLocal())
{ {
Logger::Print("Received discovery response from non-local address: %s\n", address.getCString()); Logger::Print("Received discovery response from non-local address: %s\n", address.getCString());
return; return;
} }
if (Utils::ParseChallenge(data) != Discovery::Challenge) if (Utils::ParseChallenge(data) != Discovery::Challenge)
{ {
Logger::Print("Received discovery with invalid challenge from: %s\n", address.getCString()); Logger::Print("Received discovery with invalid challenge from: %s\n", address.getCString());
return; return;
} }
Logger::Print("Received discovery response from: %s\n", address.getCString()); Logger::Print("Received discovery response from: %s\n", address.getCString());
if (ServerList::IsOfflineList()) if (ServerList::IsOfflineList())
{ {
ServerList::InsertRequest(address, true); ServerList::InsertRequest(address, true);
} }
}); });
// This is placed here in case the anticheat has been disabled! // This is placed here in case the anticheat has been disabled!
// Make sure this is called after the memory scan! // Make sure this is called after the memory scan!
#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT) #if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
Utils::Hook(0x5ACB9E, [] () // Somewhere in the renderer, past the scan check Utils::Hook(0x5ACB9E, [] () // Somewhere in the renderer, past the scan check
{ {
AntiCheat::ScanIntegrityCheck(); AntiCheat::ScanIntegrityCheck();
return Utils::Hook::Call<void()>(0x4AA720)(); return Utils::Hook::Call<void()>(0x4AA720)();
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
#endif #endif
} }
Discovery::~Discovery() Discovery::~Discovery()
{ {
Discovery::IsPerforming = false; Discovery::IsPerforming = false;
Discovery::IsTerminating = true; Discovery::IsTerminating = true;
if (Discovery::Thread.joinable()) if (Discovery::Thread.joinable())
{ {
Discovery::Thread.join(); Discovery::Thread.join();
} }
} }
} }

View File

@ -1,21 +1,21 @@
namespace Components namespace Components
{ {
class Discovery : public Component class Discovery : public Component
{ {
public: public:
Discovery(); Discovery();
~Discovery(); ~Discovery();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Discovery"; }; const char* getName() { return "Discovery"; };
#endif #endif
static void Perform(); static void Perform();
private: private:
static bool IsTerminating; static bool IsTerminating;
static bool IsPerforming; static bool IsPerforming;
static std::thread Thread; static std::thread Thread;
static std::string Challenge; static std::string Challenge;
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +1,97 @@
namespace Components namespace Components
{ {
class Download : public Component class Download : public Component
{ {
public: public:
Download(); Download();
~Download(); ~Download();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Download"; }; const char* getName() { return "Download"; };
#endif #endif
static void InitiateClientDownload(std::string mod); static void InitiateClientDownload(std::string mod);
private: private:
class ClientDownload class ClientDownload
{ {
public: public:
ClientDownload() : valid(false), running(false), terminateThread(false), totalBytes(0), downBytes(0), lastTimeStamp(0), timeStampBytes(0) {} ClientDownload() : valid(false), running(false), terminateThread(false), totalBytes(0), downBytes(0), lastTimeStamp(0), timeStampBytes(0) {}
~ClientDownload() { this->clear(); } ~ClientDownload() { this->clear(); }
bool running; bool running;
bool valid; bool valid;
bool terminateThread; bool terminateThread;
mg_mgr mgr; mg_mgr mgr;
Network::Address target; Network::Address target;
std::string mod; std::string mod;
std::thread thread; std::thread thread;
size_t totalBytes; size_t totalBytes;
size_t downBytes; size_t downBytes;
int lastTimeStamp; int lastTimeStamp;
size_t timeStampBytes; size_t timeStampBytes;
class File class File
{ {
public: public:
std::string name; std::string name;
std::string hash; std::string hash;
size_t size; size_t size;
}; };
std::vector<File> files; std::vector<File> files;
void clear() void clear()
{ {
this->terminateThread = true; this->terminateThread = true;
if (this->thread.joinable()) if (this->thread.joinable())
{ {
this->thread.join(); this->thread.join();
} }
this->running = false; this->running = false;
this->mod.clear(); this->mod.clear();
this->files.clear(); this->files.clear();
if (this->valid) if (this->valid)
{ {
this->valid = false; this->valid = false;
mg_mgr_free(&(this->mgr)); mg_mgr_free(&(this->mgr));
} }
} }
}; };
class FileDownload class FileDownload
{ {
public: public:
ClientDownload* download; ClientDownload* download;
ClientDownload::File file; ClientDownload::File file;
int timestamp; int timestamp;
bool downloading; bool downloading;
unsigned int index; unsigned int index;
std::string buffer; std::string buffer;
size_t receivedBytes; size_t receivedBytes;
}; };
static mg_mgr Mgr; static mg_mgr Mgr;
static ClientDownload CLDownload; static ClientDownload CLDownload;
static void EventHandler(mg_connection *nc, int ev, void *ev_data); static void EventHandler(mg_connection *nc, int ev, void *ev_data);
static void ListHandler(mg_connection *nc, int ev, void *ev_data); static void ListHandler(mg_connection *nc, int ev, void *ev_data);
static void FileHandler(mg_connection *nc, int ev, void *ev_data); static void FileHandler(mg_connection *nc, int ev, void *ev_data);
static void InfoHandler(mg_connection *nc, int ev, void *ev_data); static void InfoHandler(mg_connection *nc, int ev, void *ev_data);
static void DownloadHandler(mg_connection *nc, int ev, void *ev_data); static void DownloadHandler(mg_connection *nc, int ev, void *ev_data);
static bool IsClient(mg_connection *nc); static bool IsClient(mg_connection *nc);
static Game::client_t* GetClient(mg_connection *nc); static Game::client_t* GetClient(mg_connection *nc);
static void Forbid(mg_connection *nc); static void Forbid(mg_connection *nc);
static void ModDownloader(ClientDownload* download); static void ModDownloader(ClientDownload* download);
static bool ParseModList(ClientDownload* download, std::string list); static bool ParseModList(ClientDownload* download, std::string list);
static bool DownloadFile(ClientDownload* download, unsigned int index); static bool DownloadFile(ClientDownload* download, unsigned int index);
}; };
} }

View File

@ -1,207 +1,207 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Utils::Signal<Dvar::Callback> Dvar::RegistrationSignal; Utils::Signal<Dvar::Callback> Dvar::RegistrationSignal;
Dvar::Var::Var(std::string dvarName) : Var() Dvar::Var::Var(std::string dvarName) : Var()
{ {
this->dvar = Game::Dvar_FindVar(dvarName.data()); this->dvar = Game::Dvar_FindVar(dvarName.data());
if (!this->dvar) if (!this->dvar)
{ {
// Quick-register the dvar // Quick-register the dvar
Game::Dvar_SetStringByName(dvarName.data(), ""); Game::Dvar_SetStringByName(dvarName.data(), "");
this->dvar = Game::Dvar_FindVar(dvarName.data()); this->dvar = Game::Dvar_FindVar(dvarName.data());
} }
} }
template <> Game::dvar_t* Dvar::Var::get() template <> Game::dvar_t* Dvar::Var::get()
{ {
return this->dvar; return this->dvar;
} }
template <> char* Dvar::Var::get() template <> char* Dvar::Var::get()
{ {
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING && this->dvar->current.string) if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING && this->dvar->current.string)
{ {
return this->dvar->current.string; return this->dvar->current.string;
} }
return ""; return "";
} }
template <> const char* Dvar::Var::get() template <> const char* Dvar::Var::get()
{ {
return this->get<char*>(); return this->get<char*>();
} }
template <> int Dvar::Var::get() template <> int Dvar::Var::get()
{ {
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_INT) if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_INT)
{ {
return this->dvar->current.integer; return this->dvar->current.integer;
} }
return 0; return 0;
} }
template <> unsigned int Dvar::Var::get() template <> unsigned int Dvar::Var::get()
{ {
return static_cast<unsigned int>(this->get<int>()); return static_cast<unsigned int>(this->get<int>());
} }
template <> float Dvar::Var::get() template <> float Dvar::Var::get()
{ {
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT) if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT)
{ {
return this->dvar->current.value; return this->dvar->current.value;
} }
return 0; return 0;
} }
template <> float* Dvar::Var::get() template <> float* Dvar::Var::get()
{ {
static float val[4] = { 0 }; static float val[4] = { 0 };
if (this->dvar && (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4)) if (this->dvar && (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4))
{ {
return this->dvar->current.vec4; return this->dvar->current.vec4;
} }
return val; return val;
} }
template <> bool Dvar::Var::get() template <> bool Dvar::Var::get()
{ {
if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL) if (this->dvar && this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL)
{ {
return this->dvar->current.boolean; return this->dvar->current.boolean;
} }
return false; return false;
} }
template <> std::string Dvar::Var::get() template <> std::string Dvar::Var::get()
{ {
return this->get<const char*>(); return this->get<const char*>();
} }
void Dvar::Var::set(char* string) void Dvar::Var::set(char* string)
{ {
this->set(const_cast<const char*>(string)); this->set(const_cast<const char*>(string));
} }
void Dvar::Var::set(const char* string) void Dvar::Var::set(const char* string)
{ {
if (this->dvar && this->dvar->name) if (this->dvar && this->dvar->name)
{ {
Game::Dvar_SetCommand(this->dvar->name, string); Game::Dvar_SetCommand(this->dvar->name, string);
} }
} }
void Dvar::Var::set(std::string string) void Dvar::Var::set(std::string string)
{ {
this->set(string.data()); this->set(string.data());
} }
void Dvar::Var::set(int integer) void Dvar::Var::set(int integer)
{ {
if (this->dvar && this->dvar->name) if (this->dvar && this->dvar->name)
{ {
Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%i", integer)); Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%i", integer));
} }
} }
void Dvar::Var::set(float value) void Dvar::Var::set(float value)
{ {
if (this->dvar && this->dvar->name) if (this->dvar && this->dvar->name)
{ {
Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%f", value)); Game::Dvar_SetCommand(this->dvar->name, Utils::String::VA("%f", value));
} }
} }
void Dvar::Var::setRaw(int integer) void Dvar::Var::setRaw(int integer)
{ {
if (this->dvar) if (this->dvar)
{ {
this->dvar->current.integer = integer; this->dvar->current.integer = integer;
} }
} }
template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description) template<> static Dvar::Var Dvar::Register(const char* name, bool value, Dvar::Flag flag, const char* description)
{ {
return Game::Dvar_RegisterBool(name, value, flag.val, description); return Game::Dvar_RegisterBool(name, value, flag.val, description);
} }
template<> static Dvar::Var Dvar::Register(const char* name, const char* value, Dvar::Flag flag, const char* description) template<> static Dvar::Var Dvar::Register(const char* name, const char* value, Dvar::Flag flag, const char* description)
{ {
return Game::Dvar_RegisterString(name, value, flag.val, description); return Game::Dvar_RegisterString(name, value, flag.val, description);
} }
template<> static Dvar::Var Dvar::Register(const char* name, int value, int min, int max, Dvar::Flag flag, const char* description) template<> static Dvar::Var Dvar::Register(const char* name, int value, int min, int max, Dvar::Flag flag, const char* description)
{ {
return Game::Dvar_RegisterInt(name, value, min, max, flag.val, description); return Game::Dvar_RegisterInt(name, value, min, max, flag.val, description);
} }
void Dvar::OnInit(Utils::Slot<Dvar::Callback> callback) void Dvar::OnInit(Utils::Slot<Dvar::Callback> callback)
{ {
Dvar::RegistrationSignal.connect(callback); Dvar::RegistrationSignal.connect(callback);
} }
Game::dvar_t* Dvar::RegisterName(const char* name, const char* /*default*/, Game::dvar_flag flag, const char* description) Game::dvar_t* Dvar::RegisterName(const char* name, const char* /*default*/, Game::dvar_flag flag, const char* description)
{ {
// Run callbacks // Run callbacks
Dvar::RegistrationSignal(); Dvar::RegistrationSignal();
// Name watcher // Name watcher
Renderer::OnFrame([] () Renderer::OnFrame([] ()
{ {
static std::string lastValidName = "Unknown Soldier"; static std::string lastValidName = "Unknown Soldier";
std::string name = Dvar::Var("name").get<char*>(); std::string name = Dvar::Var("name").get<char*>();
// Don't perform any checks if name didn't change // Don't perform any checks if name didn't change
if (name == lastValidName) return; if (name == lastValidName) return;
std::string saneName = Colors::Strip(Utils::String::Trim(name)); std::string saneName = Colors::Strip(Utils::String::Trim(name));
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{')) if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
{ {
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data()); Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
Dvar::Var("name").set(lastValidName); Dvar::Var("name").set(lastValidName);
} }
else else
{ {
lastValidName = name; lastValidName = name;
} }
}); });
return Dvar::Register<const char*>(name, "Unknown Soldier", Dvar::Flag(flag | Game::dvar_flag::DVAR_FLAG_SAVED).val, description).get<Game::dvar_t*>(); return Dvar::Register<const char*>(name, "Unknown Soldier", Dvar::Flag(flag | Game::dvar_flag::DVAR_FLAG_SAVED).val, description).get<Game::dvar_t*>();
} }
Dvar::Dvar() Dvar::Dvar()
{ {
// set flags of cg_drawFPS to archive // set flags of cg_drawFPS to archive
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED); Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_FLAG_SAVED);
// un-cheat cg_fov and add archive flags // un-cheat cg_fov and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED); Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
// un-cheat cg_debugInfoCornerOffset and add archive flags // un-cheat cg_debugInfoCornerOffset and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8FC2, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED); Utils::Hook::Xor<BYTE>(0x4F8FC2, Game::dvar_flag::DVAR_FLAG_CHEAT | Game::dvar_flag::DVAR_FLAG_SAVED);
// remove archive flags for cg_hudchatposition // remove archive flags for cg_hudchatposition
Utils::Hook::Xor<BYTE>(0x4F9992, Game::dvar_flag::DVAR_FLAG_SAVED); Utils::Hook::Xor<BYTE>(0x4F9992, Game::dvar_flag::DVAR_FLAG_SAVED);
// remove write protection from fs_game // remove write protection from fs_game
Utils::Hook::Xor<DWORD>(0x6431EA, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED); Utils::Hook::Xor<DWORD>(0x6431EA, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED);
// set cg_fov max to 90.0 // set cg_fov max to 90.0
static float cgFov90 = 90.0f; static float cgFov90 = 90.0f;
Utils::Hook::Set<float*>(0x4F8E28, &cgFov90); Utils::Hook::Set<float*>(0x4F8E28, &cgFov90);
// set max volume to 1 // set max volume to 1
static float volume = 1.0f; static float volume = 1.0f;
Utils::Hook::Set<float*>(0x408078, &volume); Utils::Hook::Set<float*>(0x408078, &volume);
// Uncheat ui_showList // Uncheat ui_showList
Utils::Hook::Xor<BYTE>(0x6310DC, Game::dvar_flag::DVAR_FLAG_CHEAT); Utils::Hook::Xor<BYTE>(0x6310DC, Game::dvar_flag::DVAR_FLAG_CHEAT);
// Uncheat ui_debugMode // Uncheat ui_debugMode
Utils::Hook::Xor<BYTE>(0x6312DE, Game::dvar_flag::DVAR_FLAG_CHEAT); Utils::Hook::Xor<BYTE>(0x6312DE, Game::dvar_flag::DVAR_FLAG_CHEAT);
// Hook dvar 'name' registration // Hook dvar 'name' registration
Utils::Hook(0x40531C, Dvar::RegisterName, HOOK_CALL).install()->quick(); Utils::Hook(0x40531C, Dvar::RegisterName, HOOK_CALL).install()->quick();
} }
Dvar::~Dvar() Dvar::~Dvar()
{ {
Dvar::RegistrationSignal.clear(); Dvar::RegistrationSignal.clear();
} }
} }

View File

@ -1,60 +1,60 @@
namespace Components namespace Components
{ {
class Dvar : public Component class Dvar : public Component
{ {
public: public:
typedef void(Callback)(); typedef void(Callback)();
class Flag class Flag
{ {
public: public:
Flag(Game::dvar_flag flag) : val(flag){}; Flag(Game::dvar_flag flag) : val(flag){};
Flag(int flag) : Flag(static_cast<Game::dvar_flag>(flag)) {}; Flag(int flag) : Flag(static_cast<Game::dvar_flag>(flag)) {};
Game::dvar_flag val; Game::dvar_flag val;
}; };
class Var class Var
{ {
public: public:
Var() : dvar(0) {}; Var() : dvar(0) {};
Var(const Var &obj) { this->dvar = obj.dvar; }; Var(const Var &obj) { this->dvar = obj.dvar; };
Var(Game::dvar_t* _dvar) : dvar(_dvar) {}; Var(Game::dvar_t* _dvar) : dvar(_dvar) {};
Var(DWORD ppdvar) : Var(*reinterpret_cast<Game::dvar_t**>(ppdvar)) {}; Var(DWORD ppdvar) : Var(*reinterpret_cast<Game::dvar_t**>(ppdvar)) {};
Var(std::string dvarName); Var(std::string dvarName);
template<typename T> T get(); template<typename T> T get();
void set(char* string); void set(char* string);
void set(const char* string); void set(const char* string);
void set(std::string string); void set(std::string string);
void set(int integer); void set(int integer);
void set(float value); void set(float value);
// TODO: Add others // TODO: Add others
void setRaw(int integer); void setRaw(int integer);
private: private:
Game::dvar_t* dvar; Game::dvar_t* dvar;
}; };
Dvar(); Dvar();
~Dvar(); ~Dvar();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Dvar"; }; const char* getName() { return "Dvar"; };
#endif #endif
static void OnInit(Utils::Slot<Callback> callback); static void OnInit(Utils::Slot<Callback> callback);
// Only strings and bools use this type of declaration // Only strings and bools use this type of declaration
template<typename T> static Var Register(const char* name, T value, Flag flag, const char* description); template<typename T> static Var Register(const char* name, T value, Flag flag, const char* description);
template<typename T> static Var Register(const char* name, T value, T min, T max, Flag flag, const char* description); template<typename T> static Var Register(const char* name, T value, T min, T max, Flag flag, const char* description);
private: private:
static Utils::Signal<Callback> RegistrationSignal; static Utils::Signal<Callback> RegistrationSignal;
static Game::dvar_t* RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description); static Game::dvar_t* RegisterName(const char* name, const char* default, Game::dvar_flag flag, const char* description);
}; };
} }

View File

@ -1,176 +1,176 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
// Stuff causes warnings // Stuff causes warnings
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4091) #pragma warning(disable: 4091)
#include <dbghelp.h> #include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib") #pragma comment(lib, "dbghelp.lib")
#pragma warning(pop) #pragma warning(pop)
namespace Components namespace Components
{ {
Utils::Hook Exception::SetFilterHook; Utils::Hook Exception::SetFilterHook;
__declspec(noreturn) void Exception::ErrorLongJmp(jmp_buf _Buf, int _Value) __declspec(noreturn) void Exception::ErrorLongJmp(jmp_buf _Buf, int _Value)
{ {
if (!*reinterpret_cast<DWORD*>(0x1AD7EB4)) if (!*reinterpret_cast<DWORD*>(0x1AD7EB4))
{ {
TerminateProcess(GetCurrentProcess(), 1337); TerminateProcess(GetCurrentProcess(), 1337);
} }
longjmp(_Buf, _Value); longjmp(_Buf, _Value);
} }
LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) LONG WINAPI Exception::ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo)
{ {
// Pass on harmless errors // Pass on harmless errors
if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_INTEGER_OVERFLOW || if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_INTEGER_OVERFLOW ||
ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_FLOAT_OVERFLOW) ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_FLOAT_OVERFLOW)
{ {
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;
} }
auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo); auto minidump = MinidumpUpload::CreateQueuedMinidump(ExceptionInfo);
if (!minidump) if (!minidump)
{ {
OutputDebugStringA("Failed to create new minidump!"); OutputDebugStringA("Failed to create new minidump!");
Utils::OutputDebugLastError(); Utils::OutputDebugLastError();
} }
else else
{ {
delete minidump; delete minidump;
} }
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW)
{ {
Logger::Error("Termination because of a stack overflow.\n"); Logger::Error("Termination because of a stack overflow.\n");
} }
else else
{ {
Logger::Error("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress); Logger::Error("Fatal error (0x%08X) at 0x%08X.", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionInfo->ExceptionRecord->ExceptionAddress);
} }
//TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode); //TerminateProcess(GetCurrentProcess(), ExceptionInfo->ExceptionRecord->ExceptionCode);
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER) LPTOP_LEVEL_EXCEPTION_FILTER WINAPI Exception::SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER)
{ {
Exception::SetFilterHook.uninstall(); Exception::SetFilterHook.uninstall();
LPTOP_LEVEL_EXCEPTION_FILTER retval = SetUnhandledExceptionFilter(&Exception::ExceptionFilter); LPTOP_LEVEL_EXCEPTION_FILTER retval = SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
Exception::SetFilterHook.install(); Exception::SetFilterHook.install();
return retval; return retval;
} }
LPTOP_LEVEL_EXCEPTION_FILTER Exception::Hook() LPTOP_LEVEL_EXCEPTION_FILTER Exception::Hook()
{ {
return SetUnhandledExceptionFilter(&Exception::ExceptionFilter); return SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
} }
Exception::Exception() Exception::Exception()
{ {
#ifdef DEBUG #ifdef DEBUG
// Display DEBUG branding, so we know we're on a debug build // Display DEBUG branding, so we know we're on a debug build
Renderer::OnFrame([]() Renderer::OnFrame([]()
{ {
Game::Font* font = Game::R_RegisterFont("fonts/normalFont"); Game::Font* font = Game::R_RegisterFont("fonts/normalFont");
float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
// Change the color when attaching a debugger // Change the color when attaching a debugger
if (IsDebuggerPresent()) if (IsDebuggerPresent())
{ {
color[0] = 0.6588f; color[0] = 0.6588f;
color[1] = 1.0000f; color[1] = 1.0000f;
color[2] = 0.0000f; color[2] = 0.0000f;
} }
Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); Game::R_AddCmdDrawText("DEBUG-BUILD", 0x7FFFFFFF, font, 15.0f, 10.0f + Game::R_TextHeight(font), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED);
}); });
#endif #endif
#if !defined(DEBUG) || defined(FORCE_EXCEPTION_HANDLER) #if !defined(DEBUG) || defined(FORCE_EXCEPTION_HANDLER)
Exception::SetFilterHook.initialize(SetUnhandledExceptionFilter, Exception::SetUnhandledExceptionFilterStub, HOOK_JUMP); Exception::SetFilterHook.initialize(SetUnhandledExceptionFilter, Exception::SetUnhandledExceptionFilterStub, HOOK_JUMP);
Exception::SetFilterHook.install(); Exception::SetFilterHook.install();
SetUnhandledExceptionFilter(&Exception::ExceptionFilter); SetUnhandledExceptionFilter(&Exception::ExceptionFilter);
#endif #endif
//Utils::Hook(0x4B241F, Exception::ErrorLongJmp, HOOK_CALL).install()->quick(); //Utils::Hook(0x4B241F, Exception::ErrorLongJmp, HOOK_CALL).install()->quick();
Command::Add("mapTest", [](Command::Params* params) Command::Add("mapTest", [](Command::Params* params)
{ {
Game::UI_UpdateArenas(); Game::UI_UpdateArenas();
std::string command; std::string command;
for (int i = 0; i < (params->length() >= 2 ? atoi(params->get(1)) : *Game::arenaCount); ++i) for (int i = 0; i < (params->length() >= 2 ? atoi(params->get(1)) : *Game::arenaCount); ++i)
{ {
char* mapname = ArenaLength::NewArenas[i % *Game::arenaCount].mapName; char* mapname = ArenaLength::NewArenas[i % *Game::arenaCount].mapName;
if (!(i % 2)) command.append(Utils::String::VA("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect if (!(i % 2)) command.append(Utils::String::VA("wait 250;disconnect;wait 750;", mapname)); // Test a disconnect
else command.append(Utils::String::VA("wait 500;", mapname)); // Test direct map switch else command.append(Utils::String::VA("wait 500;", mapname)); // Test direct map switch
command.append(Utils::String::VA("map %s;", mapname)); command.append(Utils::String::VA("map %s;", mapname));
} }
Command::Execute(command, false); Command::Execute(command, false);
}); });
Command::Add("debug_exceptionhandler", [] (Command::Params*) Command::Add("debug_exceptionhandler", [] (Command::Params*)
{ {
Logger::Print("Rerunning SetUnhandledExceptionHandler...\n"); Logger::Print("Rerunning SetUnhandledExceptionHandler...\n");
auto oldHandler = Exception::Hook(); auto oldHandler = Exception::Hook();
Logger::Print("Old exception handler was 0x%010X.\n", oldHandler); Logger::Print("Old exception handler was 0x%010X.\n", oldHandler);
}); });
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization #pragma warning(disable:4740) // flow in or out of inline asm code suppresses global optimization
Command::Add("debug_minidump", [](Command::Params*) Command::Add("debug_minidump", [](Command::Params*)
{ {
// The following code was taken from VC++ 8.0 CRT (invarg.c: line 104) // The following code was taken from VC++ 8.0 CRT (invarg.c: line 104)
CONTEXT ContextRecord; CONTEXT ContextRecord;
EXCEPTION_RECORD ExceptionRecord; EXCEPTION_RECORD ExceptionRecord;
ZeroMemory(&ContextRecord, sizeof(CONTEXT)); ZeroMemory(&ContextRecord, sizeof(CONTEXT));
__asm __asm
{ {
mov [ContextRecord.Eax], eax mov [ContextRecord.Eax], eax
mov [ContextRecord.Ecx], ecx mov [ContextRecord.Ecx], ecx
mov [ContextRecord.Edx], edx mov [ContextRecord.Edx], edx
mov [ContextRecord.Ebx], ebx mov [ContextRecord.Ebx], ebx
mov [ContextRecord.Esi], esi mov [ContextRecord.Esi], esi
mov [ContextRecord.Edi], edi mov [ContextRecord.Edi], edi
mov word ptr [ContextRecord.SegSs], ss mov word ptr [ContextRecord.SegSs], ss
mov word ptr [ContextRecord.SegCs], cs mov word ptr [ContextRecord.SegCs], cs
mov word ptr [ContextRecord.SegDs], ds mov word ptr [ContextRecord.SegDs], ds
mov word ptr [ContextRecord.SegEs], es mov word ptr [ContextRecord.SegEs], es
mov word ptr [ContextRecord.SegFs], fs mov word ptr [ContextRecord.SegFs], fs
mov word ptr [ContextRecord.SegGs], gs mov word ptr [ContextRecord.SegGs], gs
pushfd pushfd
pop [ContextRecord.EFlags] pop [ContextRecord.EFlags]
} }
ContextRecord.ContextFlags = CONTEXT_CONTROL; ContextRecord.ContextFlags = CONTEXT_CONTROL;
ContextRecord.Eip = reinterpret_cast<DWORD>(_ReturnAddress()); ContextRecord.Eip = reinterpret_cast<DWORD>(_ReturnAddress());
ContextRecord.Esp = reinterpret_cast<DWORD>(_AddressOfReturnAddress()); ContextRecord.Esp = reinterpret_cast<DWORD>(_AddressOfReturnAddress());
ContextRecord.Ebp = *reinterpret_cast<DWORD*>(_AddressOfReturnAddress()) - 1; ContextRecord.Ebp = *reinterpret_cast<DWORD*>(_AddressOfReturnAddress()) - 1;
ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD)); ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD));
ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT; ExceptionRecord.ExceptionCode = EXCEPTION_BREAKPOINT;
ExceptionRecord.ExceptionAddress = _ReturnAddress(); ExceptionRecord.ExceptionAddress = _ReturnAddress();
EXCEPTION_POINTERS eptr; EXCEPTION_POINTERS eptr;
eptr.ExceptionRecord = &ExceptionRecord; eptr.ExceptionRecord = &ExceptionRecord;
eptr.ContextRecord = &ContextRecord; eptr.ContextRecord = &ContextRecord;
Exception::ExceptionFilter(&eptr); Exception::ExceptionFilter(&eptr);
}); });
#pragma warning(pop) #pragma warning(pop)
} }
Exception::~Exception() Exception::~Exception()
{ {
Exception::SetFilterHook.uninstall(); Exception::SetFilterHook.uninstall();
} }
} }

View File

@ -1,23 +1,23 @@
namespace Components namespace Components
{ {
class Exception : public Component class Exception : public Component
{ {
public: public:
Exception(); Exception();
~Exception(); ~Exception();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Exception"; }; const char* getName() { return "Exception"; };
#endif #endif
static LPTOP_LEVEL_EXCEPTION_FILTER Hook(); static LPTOP_LEVEL_EXCEPTION_FILTER Hook();
private: private:
static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo); static LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo);
static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilterStub(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
static __declspec(noreturn) void ErrorLongJmp(jmp_buf _Buf, int _Value); static __declspec(noreturn) void ErrorLongJmp(jmp_buf _Buf, int _Value);
static Utils::Hook SetFilterHook; static Utils::Hook SetFilterHook;
}; };
} }

View File

@ -1,65 +1,65 @@
namespace Components namespace Components
{ {
class FastFiles : public Component class FastFiles : public Component
{ {
public: public:
FastFiles(); FastFiles();
~FastFiles(); ~FastFiles();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "FastFiles"; }; const char* getName() { return "FastFiles"; };
#endif #endif
static void AddZonePath(std::string path); static void AddZonePath(std::string path);
static std::string Current(); static std::string Current();
static bool Ready(); static bool Ready();
static bool Exists(std::string file); static bool Exists(std::string file);
static void LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
static float GetFullLoadedFraction(); static float GetFullLoadedFraction();
static unsigned char ZoneKey[1191]; static unsigned char ZoneKey[1191];
private: private:
union Key union Key
{ {
struct struct
{ {
unsigned char key[24]; unsigned char key[24];
unsigned char iv[16]; unsigned char iv[16];
}; };
unsigned char data[1]; unsigned char data[1];
}; };
static unsigned int CurrentZone; static unsigned int CurrentZone;
static unsigned int MaxZones; static unsigned int MaxZones;
static bool IsIW4xZone; static bool IsIW4xZone;
static bool StreamRead; static bool StreamRead;
static Key CurrentKey; static Key CurrentKey;
static symmetric_CTR CurrentCTR; static symmetric_CTR CurrentCTR;
static std::vector<std::string> ZonePaths; static std::vector<std::string> ZonePaths;
static const char* GetZoneLocation(const char* file); static const char* GetZoneLocation(const char* file);
static void LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
static void LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
static void LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
static void ReadHeaderStub(unsigned int* header, int size); static void ReadHeaderStub(unsigned int* header, int size);
static void ReadVersionStub(unsigned int* version, int size); static void ReadVersionStub(unsigned int* version, int size);
static void ReadXFileHeader(void* buffer, int size); static void ReadXFileHeader(void* buffer, int size);
static void AuthLoadInitCrypto(); static void AuthLoadInitCrypto();
static int AuthLoadInflateCompare(unsigned char* buffer, int length, unsigned char* ivValue); static int AuthLoadInflateCompare(unsigned char* buffer, int length, unsigned char* ivValue);
static void AuthLoadInflateDecryptBase(); static void AuthLoadInflateDecryptBase();
static void AuthLoadInflateDecryptBaseFunc(unsigned char* buffer); static void AuthLoadInflateDecryptBaseFunc(unsigned char* buffer);
static int InflateInitDecrypt(z_streamp strm, const char *version, int stream_size); static int InflateInitDecrypt(z_streamp strm, const char *version, int stream_size);
static void LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount); static void LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount);
static void LogStreamRead(int len); static void LogStreamRead(int len);
}; };
} }

View File

@ -1,324 +1,324 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::mutex FileSystem::Mutex; std::mutex FileSystem::Mutex;
std::recursive_mutex FileSystem::FSMutex; std::recursive_mutex FileSystem::FSMutex;
Utils::Memory::Allocator FileSystem::MemAllocator; Utils::Memory::Allocator FileSystem::MemAllocator;
void FileSystem::File::read() void FileSystem::File::read()
{ {
char* _buffer = nullptr; char* _buffer = nullptr;
int size = Game::FS_ReadFile(this->filePath.data(), &_buffer); int size = Game::FS_ReadFile(this->filePath.data(), &_buffer);
this->buffer.clear(); this->buffer.clear();
if (size >= 0) if (size >= 0)
{ {
this->buffer.append(_buffer, size); this->buffer.append(_buffer, size);
Game::FS_FreeFile(_buffer); Game::FS_FreeFile(_buffer);
} }
} }
void FileSystem::RawFile::read() void FileSystem::RawFile::read()
{ {
this->buffer.clear(); this->buffer.clear();
Game::RawFile* rawfile = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data()).rawfile; Game::RawFile* rawfile = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data()).rawfile;
if (!rawfile || Game::DB_IsXAssetDefault(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data())) return; if (!rawfile || Game::DB_IsXAssetDefault(Game::XAssetType::ASSET_TYPE_RAWFILE, this->filePath.data())) return;
this->buffer.resize(Game::DB_GetRawFileLen(rawfile)); this->buffer.resize(Game::DB_GetRawFileLen(rawfile));
Game::DB_GetRawBuffer(rawfile, const_cast<char*>(this->buffer.data()), this->buffer.size()); Game::DB_GetRawBuffer(rawfile, const_cast<char*>(this->buffer.data()), this->buffer.size());
} }
FileSystem::FileReader::FileReader(std::string file) : name(file), handle(0) FileSystem::FileReader::FileReader(std::string file) : name(file), handle(0)
{ {
this->size = Game::FS_FOpenFileReadCurrentThread(this->name.data(), &this->handle); this->size = Game::FS_FOpenFileReadCurrentThread(this->name.data(), &this->handle);
} }
FileSystem::FileReader::~FileReader() FileSystem::FileReader::~FileReader()
{ {
if (this->exists() && this->handle) if (this->exists() && this->handle)
{ {
Game::FS_FCloseFile(this->handle); Game::FS_FCloseFile(this->handle);
} }
} }
bool FileSystem::FileReader::exists() bool FileSystem::FileReader::exists()
{ {
return (this->size >= 0 && this->handle); return (this->size >= 0 && this->handle);
} }
std::string FileSystem::FileReader::getName() std::string FileSystem::FileReader::getName()
{ {
return this->name; return this->name;
} }
int FileSystem::FileReader::getSize() int FileSystem::FileReader::getSize()
{ {
return this->size; return this->size;
} }
std::string FileSystem::FileReader::getBuffer() std::string FileSystem::FileReader::getBuffer()
{ {
Utils::Memory::Allocator allocator; Utils::Memory::Allocator allocator;
if (!this->exists()) return std::string(); if (!this->exists()) return std::string();
int position = Game::FS_FTell(this->handle); int position = Game::FS_FTell(this->handle);
this->seek(0, FS_SEEK_SET); this->seek(0, FS_SEEK_SET);
char* buffer = allocator.allocateArray<char>(this->size); char* buffer = allocator.allocateArray<char>(this->size);
if (!this->read(buffer, this->size)) if (!this->read(buffer, this->size))
{ {
this->seek(position, FS_SEEK_SET); this->seek(position, FS_SEEK_SET);
return std::string(); return std::string();
} }
this->seek(position, FS_SEEK_SET); this->seek(position, FS_SEEK_SET);
return std::string(buffer, this->size); return std::string(buffer, this->size);
} }
bool FileSystem::FileReader::read(void* buffer, size_t _size) bool FileSystem::FileReader::read(void* buffer, size_t _size)
{ {
if (!this->exists() || static_cast<size_t>(this->size) < _size || Game::FS_Read(buffer, _size, this->handle) != static_cast<int>(_size)) if (!this->exists() || static_cast<size_t>(this->size) < _size || Game::FS_Read(buffer, _size, this->handle) != static_cast<int>(_size))
{ {
return false; return false;
} }
return true; return true;
} }
void FileSystem::FileReader::seek(int offset, int origin) void FileSystem::FileReader::seek(int offset, int origin)
{ {
if (this->exists()) if (this->exists())
{ {
Game::FS_Seek(this->handle, offset, origin); Game::FS_Seek(this->handle, offset, origin);
} }
} }
void FileSystem::FileWriter::write(std::string data) void FileSystem::FileWriter::write(std::string data)
{ {
if (this->handle) if (this->handle)
{ {
Game::FS_Write(data.data(), data.size(), this->handle); Game::FS_Write(data.data(), data.size(), this->handle);
} }
} }
void FileSystem::FileWriter::open(bool append) void FileSystem::FileWriter::open(bool append)
{ {
if (append) if (append)
{ {
this->handle = Game::FS_FOpenFileAppend(this->filePath.data()); this->handle = Game::FS_FOpenFileAppend(this->filePath.data());
} }
else else
{ {
this->handle = Game::FS_FOpenFileWrite(this->filePath.data()); this->handle = Game::FS_FOpenFileWrite(this->filePath.data());
} }
} }
void FileSystem::FileWriter::close() void FileSystem::FileWriter::close()
{ {
if (this->handle) if (this->handle)
{ {
Game::FS_FCloseFile(this->handle); Game::FS_FCloseFile(this->handle);
this->handle = 0; this->handle = 0;
} }
} }
std::vector<std::string> FileSystem::GetFileList(std::string path, std::string extension) std::vector<std::string> FileSystem::GetFileList(std::string path, std::string extension)
{ {
std::vector<std::string> fileList; std::vector<std::string> fileList;
int numFiles = 0; int numFiles = 0;
char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0); char** files = Game::FS_GetFileList(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0);
if (files) if (files)
{ {
for (int i = 0; i < numFiles; ++i) for (int i = 0; i < numFiles; ++i)
{ {
if (files[i]) if (files[i])
{ {
fileList.push_back(files[i]); fileList.push_back(files[i]);
} }
} }
Game::FS_FreeFileList(files); Game::FS_FreeFileList(files);
} }
return fileList; return fileList;
} }
std::vector<std::string> FileSystem::GetSysFileList(std::string path, std::string extension, bool folders) std::vector<std::string> FileSystem::GetSysFileList(std::string path, std::string extension, bool folders)
{ {
std::vector<std::string> fileList; std::vector<std::string> fileList;
int numFiles = 0; int numFiles = 0;
char** files = Game::Sys_ListFiles(path.data(), extension.data(), NULL, &numFiles, folders); char** files = Game::Sys_ListFiles(path.data(), extension.data(), NULL, &numFiles, folders);
if (files) if (files)
{ {
for (int i = 0; i < numFiles; ++i) for (int i = 0; i < numFiles; ++i)
{ {
if (files[i]) if (files[i])
{ {
fileList.push_back(files[i]); fileList.push_back(files[i]);
} }
} }
Game::Sys_FreeFileList(files); Game::Sys_FreeFileList(files);
} }
return fileList; return fileList;
} }
void FileSystem::DeleteFile(std::string folder, std::string file) void FileSystem::DeleteFile(std::string folder, std::string file)
{ {
char path[MAX_PATH] = { 0 }; char path[MAX_PATH] = { 0 };
Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").get<const char*>(), reinterpret_cast<char*>(0x63D0BB8), Utils::String::VA("%s/%s", folder.data(), file.data()), reinterpret_cast<char**>(&path)); Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").get<const char*>(), reinterpret_cast<char*>(0x63D0BB8), Utils::String::VA("%s/%s", folder.data(), file.data()), reinterpret_cast<char**>(&path));
Game::FS_Remove(path); Game::FS_Remove(path);
} }
int FileSystem::ReadFile(const char* path, char** buffer) int FileSystem::ReadFile(const char* path, char** buffer)
{ {
if (!buffer) return -1; if (!buffer) return -1;
else *buffer = nullptr; else *buffer = nullptr;
if (!path) return -1; if (!path) return -1;
std::lock_guard<std::mutex> _(FileSystem::Mutex); std::lock_guard<std::mutex> _(FileSystem::Mutex);
FileSystem::FileReader reader(path); FileSystem::FileReader reader(path);
int size = reader.getSize(); int size = reader.getSize();
if (reader.exists() && size >= 0) if (reader.exists() && size >= 0)
{ {
*buffer = FileSystem::AllocateFile(size + 1); *buffer = FileSystem::AllocateFile(size + 1);
if (reader.read(*buffer, size)) return size; if (reader.read(*buffer, size)) return size;
FileSystem::FreeFile(*buffer); FileSystem::FreeFile(*buffer);
*buffer = nullptr; *buffer = nullptr;
} }
return -1; return -1;
} }
char* FileSystem::AllocateFile(int size) char* FileSystem::AllocateFile(int size)
{ {
return FileSystem::MemAllocator.allocateArray<char>(size); return FileSystem::MemAllocator.allocateArray<char>(size);
} }
void FileSystem::FreeFile(void* buffer) void FileSystem::FreeFile(void* buffer)
{ {
FileSystem::MemAllocator.free(buffer); FileSystem::MemAllocator.free(buffer);
} }
void FileSystem::RegisterFolder(const char* folder) void FileSystem::RegisterFolder(const char* folder)
{ {
std::string fs_cdpath = Dvar::Var("fs_cdpath").get<std::string>(); std::string fs_cdpath = Dvar::Var("fs_cdpath").get<std::string>();
std::string fs_basepath = Dvar::Var("fs_basepath").get<std::string>(); std::string fs_basepath = Dvar::Var("fs_basepath").get<std::string>();
std::string fs_homepath = Dvar::Var("fs_homepath").get<std::string>(); std::string fs_homepath = Dvar::Var("fs_homepath").get<std::string>();
if (!fs_cdpath.empty()) Game::FS_AddLocalizedGameDirectory(fs_cdpath.data(), folder); if (!fs_cdpath.empty()) Game::FS_AddLocalizedGameDirectory(fs_cdpath.data(), folder);
if (!fs_basepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_basepath.data(), folder); if (!fs_basepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_basepath.data(), folder);
if (!fs_homepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_homepath.data(), folder); if (!fs_homepath.empty()) Game::FS_AddLocalizedGameDirectory(fs_homepath.data(), folder);
} }
void FileSystem::RegisterFolders() void FileSystem::RegisterFolders()
{ {
if (ZoneBuilder::IsEnabled()) if (ZoneBuilder::IsEnabled())
{ {
FileSystem::RegisterFolder("zonedata"); FileSystem::RegisterFolder("zonedata");
} }
FileSystem::RegisterFolder("userraw"); FileSystem::RegisterFolder("userraw");
} }
__declspec(naked) void FileSystem::StartupStub() __declspec(naked) void FileSystem::StartupStub()
{ {
__asm __asm
{ {
pushad pushad
push esi push esi
call FileSystem::RegisterFolders call FileSystem::RegisterFolders
pop esi pop esi
popad popad
mov edx, ds:63D0CC0h mov edx, ds:63D0CC0h
push 48264Dh push 48264Dh
retn retn
} }
} }
int FileSystem::ExecIsFSStub(const char* execFilename) int FileSystem::ExecIsFSStub(const char* execFilename)
{ {
return !File(execFilename).exists(); return !File(execFilename).exists();
} }
void FileSystem::FsStartupSync(const char* a1) void FileSystem::FsStartupSync(const char* a1)
{ {
std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex); std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex);
return Utils::Hook::Call<void(const char*)>(0x4823A0)(a1); // FS_Startup return Utils::Hook::Call<void(const char*)>(0x4823A0)(a1); // FS_Startup
} }
void FileSystem::FsRestartSync(int a1, int a2) void FileSystem::FsRestartSync(int a1, int a2)
{ {
std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex); std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex);
return Utils::Hook::Call<void(int, int)>(0x461A50)(a1, a2); // FS_Restart return Utils::Hook::Call<void(int, int)>(0x461A50)(a1, a2); // FS_Restart
} }
void FileSystem::DelayLoadImagesSync() void FileSystem::DelayLoadImagesSync()
{ {
std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex); std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex);
return Utils::Hook::Call<void()>(0x494060)(); // DB_LoadDelayedImages return Utils::Hook::Call<void()>(0x494060)(); // DB_LoadDelayedImages
} }
int FileSystem::LoadTextureSync(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image) int FileSystem::LoadTextureSync(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image)
{ {
std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex); std::lock_guard<std::recursive_mutex> _(FileSystem::FSMutex);
return Game::Load_Texture(loadDef, image); return Game::Load_Texture(loadDef, image);
} }
FileSystem::FileSystem() FileSystem::FileSystem()
{ {
FileSystem::MemAllocator.clear(); FileSystem::MemAllocator.clear();
// Thread safe file system interaction // Thread safe file system interaction
Utils::Hook(0x4F4BFF, FileSystem::AllocateFile, HOOK_CALL).install()->quick(); Utils::Hook(0x4F4BFF, FileSystem::AllocateFile, HOOK_CALL).install()->quick();
//Utils::Hook(Game::FS_ReadFile, FileSystem::ReadFile, HOOK_JUMP).install()->quick(); //Utils::Hook(Game::FS_ReadFile, FileSystem::ReadFile, HOOK_JUMP).install()->quick();
Utils::Hook(Game::FS_FreeFile, FileSystem::FreeFile, HOOK_JUMP).install()->quick(); Utils::Hook(Game::FS_FreeFile, FileSystem::FreeFile, HOOK_JUMP).install()->quick();
// Filesystem config checks // Filesystem config checks
Utils::Hook(0x6098FD, FileSystem::ExecIsFSStub, HOOK_CALL).install()->quick(); Utils::Hook(0x6098FD, FileSystem::ExecIsFSStub, HOOK_CALL).install()->quick();
// Register additional folders // Register additional folders
Utils::Hook(0x482647, FileSystem::StartupStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x482647, FileSystem::StartupStub, HOOK_JUMP).install()->quick();
// exec whitelist removal (YAYFINITY WARD) // exec whitelist removal (YAYFINITY WARD)
Utils::Hook::Nop(0x609685, 5); Utils::Hook::Nop(0x609685, 5);
Utils::Hook::Nop(0x60968C, 2); Utils::Hook::Nop(0x60968C, 2);
// ignore 'no iwd files found in main' // ignore 'no iwd files found in main'
Utils::Hook::Nop(0x642A4B, 5); Utils::Hook::Nop(0x642A4B, 5);
// Ignore bad magic, when trying to free hunk when it's already cleared // Ignore bad magic, when trying to free hunk when it's already cleared
Utils::Hook::Set<WORD>(0x49AACE, 0xC35E); Utils::Hook::Set<WORD>(0x49AACE, 0xC35E);
// Synchronize filesystem starts // Synchronize filesystem starts
Utils::Hook(0x4290C6, FileSystem::FsStartupSync, HOOK_CALL).install()->quick(); // FS_InitFilesystem Utils::Hook(0x4290C6, FileSystem::FsStartupSync, HOOK_CALL).install()->quick(); // FS_InitFilesystem
Utils::Hook(0x461A88, FileSystem::FsStartupSync, HOOK_CALL).install()->quick(); // FS_Restart Utils::Hook(0x461A88, FileSystem::FsStartupSync, HOOK_CALL).install()->quick(); // FS_Restart
// Synchronize filesystem restarts // Synchronize filesystem restarts
Utils::Hook(0x4A745B, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // SV_SpawnServer Utils::Hook(0x4A745B, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // SV_SpawnServer
Utils::Hook(0x4C8609, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // FS_ConditionalRestart Utils::Hook(0x4C8609, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // FS_ConditionalRestart
Utils::Hook(0x5AC68E, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // CL_ParseServerMessage Utils::Hook(0x5AC68E, FileSystem::FsRestartSync, HOOK_CALL).install()->quick(); // CL_ParseServerMessage
// Synchronize db image loading // Synchronize db image loading
Utils::Hook(0x415AB8, FileSystem::DelayLoadImagesSync, HOOK_CALL).install()->quick(); Utils::Hook(0x415AB8, FileSystem::DelayLoadImagesSync, HOOK_CALL).install()->quick();
Utils::Hook(0x4D32BC, FileSystem::LoadTextureSync, HOOK_CALL).install()->quick(); Utils::Hook(0x4D32BC, FileSystem::LoadTextureSync, HOOK_CALL).install()->quick();
} }
FileSystem::~FileSystem() FileSystem::~FileSystem()
{ {
assert(FileSystem::MemAllocator.empty()); assert(FileSystem::MemAllocator.empty());
} }
} }

View File

@ -1,117 +1,117 @@
namespace Components namespace Components
{ {
class FileSystem : public Component class FileSystem : public Component
{ {
public: public:
class AbstractFile class AbstractFile
{ {
public: public:
virtual ~AbstractFile() {}; virtual ~AbstractFile() {};
virtual bool exists() = 0; virtual bool exists() = 0;
virtual std::string getName() = 0; virtual std::string getName() = 0;
virtual std::string& getBuffer() = 0; virtual std::string& getBuffer() = 0;
}; };
class File : public AbstractFile class File : public AbstractFile
{ {
public: public:
File() {}; File() {};
File(std::string file) : filePath(file) { this->read(); }; File(std::string file) : filePath(file) { this->read(); };
bool exists() { return !this->buffer.empty(); }; bool exists() { return !this->buffer.empty(); };
std::string getName() { return this->filePath; }; std::string getName() { return this->filePath; };
std::string& getBuffer() { return this->buffer; }; std::string& getBuffer() { return this->buffer; };
private: private:
std::string filePath; std::string filePath;
std::string buffer; std::string buffer;
void read(); void read();
}; };
class RawFile : public AbstractFile class RawFile : public AbstractFile
{ {
public: public:
RawFile() {}; RawFile() {};
RawFile(std::string file) : filePath(file) { this->read(); }; RawFile(std::string file) : filePath(file) { this->read(); };
bool exists() { return !this->buffer.empty(); }; bool exists() { return !this->buffer.empty(); };
std::string getName() { return this->filePath; }; std::string getName() { return this->filePath; };
std::string& getBuffer() { return this->buffer; }; std::string& getBuffer() { return this->buffer; };
private: private:
std::string filePath; std::string filePath;
std::string buffer; std::string buffer;
void read(); void read();
}; };
class FileReader class FileReader
{ {
public: public:
FileReader() : size(-1), name(), handle(0) {}; FileReader() : size(-1), name(), handle(0) {};
FileReader(std::string file); FileReader(std::string file);
~FileReader(); ~FileReader();
bool exists(); bool exists();
std::string getName(); std::string getName();
std::string getBuffer(); std::string getBuffer();
int getSize(); int getSize();
bool read(void* buffer, size_t size); bool read(void* buffer, size_t size);
void seek(int offset, int origin); void seek(int offset, int origin);
private: private:
int handle; int handle;
int size; int size;
std::string name; std::string name;
}; };
class FileWriter class FileWriter
{ {
public: public:
FileWriter(std::string file, bool append = false) : filePath(file), handle(0) { this->open(append); }; FileWriter(std::string file, bool append = false) : filePath(file), handle(0) { this->open(append); };
~FileWriter() { this->close(); }; ~FileWriter() { this->close(); };
void write(std::string data); void write(std::string data);
private: private:
int handle; int handle;
std::string filePath; std::string filePath;
void open(bool append = false); void open(bool append = false);
void close(); void close();
}; };
FileSystem(); FileSystem();
~FileSystem(); ~FileSystem();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "FileSystem"; }; const char* getName() { return "FileSystem"; };
#endif #endif
static std::vector<std::string> GetFileList(std::string path, std::string extension); static std::vector<std::string> GetFileList(std::string path, std::string extension);
static std::vector<std::string> GetSysFileList(std::string path, std::string extension, bool folders = false); static std::vector<std::string> GetSysFileList(std::string path, std::string extension, bool folders = false);
static void DeleteFile(std::string folder, std::string file); static void DeleteFile(std::string folder, std::string file);
private: private:
static std::mutex Mutex; static std::mutex Mutex;
static std::recursive_mutex FSMutex; static std::recursive_mutex FSMutex;
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static int ReadFile(const char* path, char** buffer); static int ReadFile(const char* path, char** buffer);
static char* AllocateFile(int size); static char* AllocateFile(int size);
static void FreeFile(void* buffer); static void FreeFile(void* buffer);
static void RegisterFolder(const char* folder); static void RegisterFolder(const char* folder);
static void RegisterFolders(); static void RegisterFolders();
static void StartupStub(); static void StartupStub();
static int ExecIsFSStub(const char* execFilename); static int ExecIsFSStub(const char* execFilename);
static void FsStartupSync(const char* a1); static void FsStartupSync(const char* a1);
static void FsRestartSync(int a1, int a2); static void FsRestartSync(int a1, int a2);
static void DelayLoadImagesSync(); static void DelayLoadImagesSync();
static int LoadTextureSync(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image); static int LoadTextureSync(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image);
}; };
} }

View File

@ -1,49 +1,49 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::vector<std::string> Flags::EnabledFlags; std::vector<std::string> Flags::EnabledFlags;
bool Flags::HasFlag(std::string flag) bool Flags::HasFlag(std::string flag)
{ {
for (auto entry : Flags::EnabledFlags) for (auto entry : Flags::EnabledFlags)
{ {
if (Utils::String::ToLower(entry) == Utils::String::ToLower(flag)) if (Utils::String::ToLower(entry) == Utils::String::ToLower(flag))
{ {
return true; return true;
} }
} }
return false; return false;
} }
void Flags::ParseFlags() void Flags::ParseFlags()
{ {
int numArgs; int numArgs;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs); LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &numArgs);
if (argv) if (argv)
{ {
for (int i = 0; i < numArgs; ++i) for (int i = 0; i < numArgs; ++i)
{ {
std::wstring wFlag(argv[i]); std::wstring wFlag(argv[i]);
if (wFlag[0] == L'-') if (wFlag[0] == L'-')
{ {
Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end())); Flags::EnabledFlags.push_back(std::string(++wFlag.begin(), wFlag.end()));
} }
} }
LocalFree(argv); LocalFree(argv);
} }
} }
Flags::Flags() Flags::Flags()
{ {
Flags::ParseFlags(); Flags::ParseFlags();
} }
Flags::~Flags() Flags::~Flags()
{ {
Flags::EnabledFlags.clear(); Flags::EnabledFlags.clear();
} }
} }

View File

@ -1,20 +1,20 @@
namespace Components namespace Components
{ {
class Flags : public Component class Flags : public Component
{ {
public: public:
Flags(); Flags();
~Flags(); ~Flags();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Flags"; }; const char* getName() { return "Flags"; };
#endif #endif
static bool HasFlag(std::string flag); static bool HasFlag(std::string flag);
private: private:
static std::vector<std::string> EnabledFlags; static std::vector<std::string> EnabledFlags;
static void ParseFlags(); static void ParseFlags();
}; };
} }

View File

@ -1,131 +1,131 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
void FrameTime::NetSleep(int msec) void FrameTime::NetSleep(int msec)
{ {
if (msec < 0) msec = 0; if (msec < 0) msec = 0;
fd_set fdr; fd_set fdr;
FD_ZERO(&fdr); FD_ZERO(&fdr);
SOCKET highestfd = INVALID_SOCKET; SOCKET highestfd = INVALID_SOCKET;
if (*Game::ip_socket != INVALID_SOCKET) if (*Game::ip_socket != INVALID_SOCKET)
{ {
FD_SET(*Game::ip_socket, &fdr); FD_SET(*Game::ip_socket, &fdr);
highestfd = *Game::ip_socket; highestfd = *Game::ip_socket;
} }
if (highestfd == INVALID_SOCKET) if (highestfd == INVALID_SOCKET)
{ {
// windows ain't happy when select is called without valid FDs // windows ain't happy when select is called without valid FDs
std::this_thread::sleep_for(std::chrono::milliseconds(msec)); std::this_thread::sleep_for(std::chrono::milliseconds(msec));
return; return;
} }
timeval timeout; timeval timeout;
timeout.tv_sec = msec / 1000; timeout.tv_sec = msec / 1000;
timeout.tv_usec = (msec % 1000) * 1000; timeout.tv_usec = (msec % 1000) * 1000;
int retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout); int retval = select(highestfd + 1, &fdr, NULL, NULL, &timeout);
if (retval == SOCKET_ERROR) if (retval == SOCKET_ERROR)
{ {
Logger::Print("Warning: select() syscall failed: %s\n", Game::NET_ErrorString()); Logger::Print("Warning: select() syscall failed: %s\n", Game::NET_ErrorString());
} }
else if (retval > 0) else if (retval > 0)
{ {
// process packets // process packets
if (Dvar::Var(0x1AD7934).get<bool>()) // com_sv_running if (Dvar::Var(0x1AD7934).get<bool>()) // com_sv_running
{ {
Utils::Hook::Call<void()>(0x458160)(); Utils::Hook::Call<void()>(0x458160)();
} }
else else
{ {
Utils::Hook::Call<void()>(0x49F0B0)(); Utils::Hook::Call<void()>(0x49F0B0)();
} }
} }
} }
void FrameTime::SVFrameWaitFunc() void FrameTime::SVFrameWaitFunc()
{ {
int sv_residualTime = *reinterpret_cast<int*>(0x2089E14); int sv_residualTime = *reinterpret_cast<int*>(0x2089E14);
if (sv_residualTime < 50) if (sv_residualTime < 50)
{ {
FrameTime::NetSleep(50 - sv_residualTime); FrameTime::NetSleep(50 - sv_residualTime);
} }
} }
void __declspec(naked) FrameTime::SVFrameWaitStub() void __declspec(naked) FrameTime::SVFrameWaitStub()
{ {
__asm __asm
{ {
pushad pushad
call FrameTime::SVFrameWaitFunc call FrameTime::SVFrameWaitFunc
popad popad
push 4CD420h push 4CD420h
retn retn
} }
} }
int FrameTime::ComTimeVal(int minMsec) int FrameTime::ComTimeVal(int minMsec)
{ {
int timeVal = Game::Sys_Milliseconds() - *reinterpret_cast<uint32_t*>(0x1AD8F3C); // com_frameTime int timeVal = Game::Sys_Milliseconds() - *reinterpret_cast<uint32_t*>(0x1AD8F3C); // com_frameTime
return (timeVal >= minMsec ? 0 : minMsec - timeVal); return (timeVal >= minMsec ? 0 : minMsec - timeVal);
} }
uint32_t FrameTime::ComFrameWait(int minMsec) uint32_t FrameTime::ComFrameWait(int minMsec)
{ {
int timeVal; int timeVal;
do do
{ {
timeVal = FrameTime::ComTimeVal(minMsec); timeVal = FrameTime::ComTimeVal(minMsec);
FrameTime::NetSleep(timeVal < 1 ? 0 : timeVal - 1); FrameTime::NetSleep(timeVal < 1 ? 0 : timeVal - 1);
} while (FrameTime::ComTimeVal(minMsec)); } while (FrameTime::ComTimeVal(minMsec));
uint32_t lastTime = *Game::com_frameTime; uint32_t lastTime = *Game::com_frameTime;
Utils::Hook::Call<void()>(0x43D140)(); // Com_EventLoop Utils::Hook::Call<void()>(0x43D140)(); // Com_EventLoop
*Game::com_frameTime = Game::Sys_Milliseconds(); *Game::com_frameTime = Game::Sys_Milliseconds();
return *Game::com_frameTime - lastTime; return *Game::com_frameTime - lastTime;
} }
void __declspec(naked) FrameTime::ComFrameWaitStub() void __declspec(naked) FrameTime::ComFrameWaitStub()
{ {
__asm __asm
{ {
push ecx push ecx
pushad pushad
push edi push edi
call FrameTime::ComFrameWait call FrameTime::ComFrameWait
add esp, 4 add esp, 4
mov[esp + 20h], eax mov[esp + 20h], eax
popad popad
pop eax pop eax
mov ecx, eax mov ecx, eax
mov edx, 1AD7934h // com_sv_running mov edx, 1AD7934h // com_sv_running
cmp byte ptr[edx + 10h], 0 cmp byte ptr[edx + 10h], 0
push 47DDC1h push 47DDC1h
retn retn
} }
} }
FrameTime::FrameTime() FrameTime::FrameTime()
{ {
if (Dedicated::IsEnabled()) if (Dedicated::IsEnabled())
{ {
Utils::Hook(0x4BAAAD, FrameTime::SVFrameWaitStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4BAAAD, FrameTime::SVFrameWaitStub, HOOK_CALL).install()->quick();
} }
else else
{ {
Utils::Hook(0x47DD80, FrameTime::ComFrameWaitStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x47DD80, FrameTime::ComFrameWaitStub, HOOK_JUMP).install()->quick();
} }
} }
} }

View File

@ -1,22 +1,22 @@
namespace Components namespace Components
{ {
class FrameTime : public Component class FrameTime : public Component
{ {
public: public:
FrameTime(); FrameTime();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "FrameTime"; }; const char* getName() { return "FrameTime"; };
#endif #endif
private: private:
static void SVFrameWaitStub(); static void SVFrameWaitStub();
static void SVFrameWaitFunc(); static void SVFrameWaitFunc();
static void NetSleep(int msec); static void NetSleep(int msec);
static int ComTimeVal(int minMsec); static int ComTimeVal(int minMsec);
static uint32_t ComFrameWait(int minMsec); static uint32_t ComFrameWait(int minMsec);
static void ComFrameWaitStub(); static void ComFrameWaitStub();
}; };
} }

View File

@ -1,112 +1,112 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
unsigned int Gametypes::GetGametypeCount() unsigned int Gametypes::GetGametypeCount()
{ {
return *Game::gameTypeCount; return *Game::gameTypeCount;
} }
const char* Gametypes::GetGametypeText(unsigned int index, int) const char* Gametypes::GetGametypeText(unsigned int index, int)
{ {
if (static_cast<unsigned int>(*Game::gameTypeCount) > index) if (static_cast<unsigned int>(*Game::gameTypeCount) > index)
{ {
return Game::SEH_StringEd_GetString(Game::gameTypes[index].uiName); return Game::SEH_StringEd_GetString(Game::gameTypes[index].uiName);
} }
return ""; return "";
} }
void Gametypes::SelectGametype(unsigned int index) void Gametypes::SelectGametype(unsigned int index)
{ {
if (!*Game::gameTypeCount) return; if (!*Game::gameTypeCount) return;
if (static_cast<unsigned int>(*Game::gameTypeCount) <= index) index = 0; if (static_cast<unsigned int>(*Game::gameTypeCount) <= index) index = 0;
std::string gametype = Game::gameTypes[index].gameType; std::string gametype = Game::gameTypes[index].gameType;
Dvar::Var("ui_gametype").set(gametype); Dvar::Var("ui_gametype").set(gametype);
//Dvar::Var("g_gametype").set(gametype); //Dvar::Var("g_gametype").set(gametype);
} }
void* Gametypes::BuildGametypeList(const char*, void* buffer, size_t size) void* Gametypes::BuildGametypeList(const char*, void* buffer, size_t size)
{ {
std::vector<std::string> gametypes; std::vector<std::string> gametypes;
auto pushGametype = [&] (std::string gametype) auto pushGametype = [&] (std::string gametype)
{ {
auto pos = gametype.find_last_of("/\\"); auto pos = gametype.find_last_of("/\\");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
gametype = gametype.substr(pos + 1); gametype = gametype.substr(pos + 1);
} }
if (Utils::String::EndsWith(gametype, ".txt")) if (Utils::String::EndsWith(gametype, ".txt"))
{ {
gametype = gametype.substr(0, gametype.size() - 4); gametype = gametype.substr(0, gametype.size() - 4);
} }
// No need for that :) // No need for that :)
if (gametype == "_gametypes") return; if (gametype == "_gametypes") return;
if (std::find(gametypes.begin(), gametypes.end(), gametype) == gametypes.end()) if (std::find(gametypes.begin(), gametypes.end(), gametype) == gametypes.end())
{ {
gametypes.push_back(gametype); gametypes.push_back(gametype);
} }
}; };
// Get the gametypes we can find in the filesystem // Get the gametypes we can find in the filesystem
std::vector<std::string> rawGametypes = FileSystem::GetFileList("maps/mp/gametypes/", "txt"); std::vector<std::string> rawGametypes = FileSystem::GetFileList("maps/mp/gametypes/", "txt");
// Get the gametypes we can find in the database // Get the gametypes we can find in the database
Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_RAWFILE, [] (Game::XAssetHeader header, void* data) Game::DB_EnumXAssets(Game::XAssetType::ASSET_TYPE_RAWFILE, [] (Game::XAssetHeader header, void* data)
{ {
std::string name = header.rawfile->name; std::string name = header.rawfile->name;
std::vector<std::string>* rawGametypes = reinterpret_cast<std::vector<std::string>*>(data); std::vector<std::string>* rawGametypes = reinterpret_cast<std::vector<std::string>*>(data);
if (Utils::String::StartsWith(name, "maps/mp/gametypes/") && Utils::String::EndsWith(name, ".txt")) if (Utils::String::StartsWith(name, "maps/mp/gametypes/") && Utils::String::EndsWith(name, ".txt"))
{ {
if (std::count(name.begin(), name.end(), '/') == 3 && std::count(name.begin(), name.end(), '\\') == 0) if (std::count(name.begin(), name.end(), '/') == 3 && std::count(name.begin(), name.end(), '\\') == 0)
{ {
rawGametypes->push_back(name); rawGametypes->push_back(name);
} }
} }
}, &rawGametypes, false); }, &rawGametypes, false);
std::for_each(rawGametypes.begin(), rawGametypes.end(), pushGametype); std::for_each(rawGametypes.begin(), rawGametypes.end(), pushGametype);
std::string data; std::string data;
for (auto& gametype : gametypes) for (auto& gametype : gametypes)
{ {
if (Game::LoadModdableRawfile(0, Utils::String::VA("maps/mp/gametypes/%s.txt", gametype.data()))) if (Game::LoadModdableRawfile(0, Utils::String::VA("maps/mp/gametypes/%s.txt", gametype.data())))
{ {
data.append(gametype); data.append(gametype);
data.append("\r\n"); data.append("\r\n");
} }
} }
// Copy to the actual buffer // Copy to the actual buffer
std::memcpy(buffer, data.data(), std::min(size, data.size() + 1)); std::memcpy(buffer, data.data(), std::min(size, data.size() + 1));
return (data.empty() ? nullptr : buffer); return (data.empty() ? nullptr : buffer);
} }
Gametypes::Gametypes() Gametypes::Gametypes()
{ {
UIFeeder::Add(29.0f, Gametypes::GetGametypeCount, Gametypes::GetGametypeText, Gametypes::SelectGametype); UIFeeder::Add(29.0f, Gametypes::GetGametypeCount, Gametypes::GetGametypeText, Gametypes::SelectGametype);
// Dynamically grab gametypes // Dynamically grab gametypes
Utils::Hook(0x5FA46C, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // Scr_UpdateGameTypeList Utils::Hook(0x5FA46C, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // Scr_UpdateGameTypeList
Utils::Hook(0x632155, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // UI_UpdateGameTypesList Utils::Hook(0x632155, Gametypes::BuildGametypeList, HOOK_CALL).install()->quick(); // UI_UpdateGameTypesList
// This is placed here in case the anticheat has been disabled! // This is placed here in case the anticheat has been disabled!
// Make sure this is called after every onther anticheat check! // Make sure this is called after every onther anticheat check!
#if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT) #if !defined(DEBUG) && !defined(DISABLE_ANTICHEAT)
Utils::Hook(0x5ACBA3, [] () // Somewhere in the renderer, past other renderer hooks! Utils::Hook(0x5ACBA3, [] () // Somewhere in the renderer, past other renderer hooks!
{ {
AntiCheat::FlagIntegrityCheck(); AntiCheat::FlagIntegrityCheck();
return Utils::Hook::Call<void()>(0x50AB20)(); return Utils::Hook::Call<void()>(0x50AB20)();
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
#endif #endif
} }
} }

View File

@ -1,19 +1,19 @@
namespace Components namespace Components
{ {
class Gametypes : public Component class Gametypes : public Component
{ {
public: public:
Gametypes(); Gametypes();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Gametypes"; }; const char* getName() { return "Gametypes"; };
#endif #endif
private: private:
static unsigned int GetGametypeCount(); static unsigned int GetGametypeCount();
static const char* GetGametypeText(unsigned int index, int column); static const char* GetGametypeText(unsigned int index, int column);
static void SelectGametype(unsigned int index); static void SelectGametype(unsigned int index);
static void* BuildGametypeList(const char* file, void* buffer, size_t size); static void* BuildGametypeList(const char* file, void* buffer, size_t size);
}; };
} }

View File

@ -1,233 +1,233 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Pipe IPCPipe::ServerPipe; Pipe IPCPipe::ServerPipe;
Pipe IPCPipe::ClientPipe; Pipe IPCPipe::ClientPipe;
#pragma region Pipe #pragma region Pipe
Pipe::Pipe() : type(IPCTYPE_NONE), reconnectAttempt(0), pipe(INVALID_HANDLE_VALUE), connectCallback(0), threadAttached(false) Pipe::Pipe() : type(IPCTYPE_NONE), reconnectAttempt(0), pipe(INVALID_HANDLE_VALUE), connectCallback(0), threadAttached(false)
{ {
this->destroy(); this->destroy();
} }
Pipe::~Pipe() Pipe::~Pipe()
{ {
this->destroy(); this->destroy();
} }
bool Pipe::connect(std::string name) bool Pipe::connect(std::string name)
{ {
this->destroy(); this->destroy();
this->type = IPCTYPE_CLIENT; this->type = IPCTYPE_CLIENT;
this->setName(name); this->setName(name);
this->pipe = CreateFileA(this->pipeFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); this->pipe = CreateFileA(this->pipeFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == this->pipe) if (INVALID_HANDLE_VALUE == this->pipe)
{ {
Logger::Print("Failed to connect to the pipe\n"); Logger::Print("Failed to connect to the pipe\n");
if (this->reconnectAttempt < IPC_MAX_RECONNECTS) if (this->reconnectAttempt < IPC_MAX_RECONNECTS)
{ {
Logger::Print("Attempting to reconnect to the pipe.\n"); Logger::Print("Attempting to reconnect to the pipe.\n");
++this->reconnectAttempt; ++this->reconnectAttempt;
std::this_thread::sleep_for(500ms); std::this_thread::sleep_for(500ms);
return this->connect(name); return this->connect(name);
} }
else else
{ {
this->destroy(); this->destroy();
return false; return false;
} }
} }
this->reconnectAttempt = 0; this->reconnectAttempt = 0;
Logger::Print("Successfully connected to the pipe\n"); Logger::Print("Successfully connected to the pipe\n");
return true; return true;
} }
bool Pipe::create(std::string name) bool Pipe::create(std::string name)
{ {
this->destroy(); this->destroy();
this->type = IPCTYPE_SERVER; this->type = IPCTYPE_SERVER;
this->setName(name); this->setName(name);
this->pipe = CreateNamedPipeA(this->pipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->packet), sizeof(this->packet), NMPWAIT_USE_DEFAULT_WAIT, NULL); this->pipe = CreateNamedPipeA(this->pipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->packet), sizeof(this->packet), NMPWAIT_USE_DEFAULT_WAIT, NULL);
if (INVALID_HANDLE_VALUE != this->pipe && this->pipe) if (INVALID_HANDLE_VALUE != this->pipe && this->pipe)
{ {
// Only create the thread, when not performing unit tests! // Only create the thread, when not performing unit tests!
if (!Loader::PerformingUnitTests()) if (!Loader::PerformingUnitTests())
{ {
this->threadAttached = true; this->threadAttached = true;
this->thread = std::thread(Pipe::ReceiveThread, this); this->thread = std::thread(Pipe::ReceiveThread, this);
} }
Logger::Print("Pipe successfully created\n"); Logger::Print("Pipe successfully created\n");
return true; return true;
} }
Logger::Print("Failed to create the pipe\n"); Logger::Print("Failed to create the pipe\n");
this->destroy(); this->destroy();
return false; return false;
} }
void Pipe::onConnect(Pipe::Callback callback) void Pipe::onConnect(Pipe::Callback callback)
{ {
this->connectCallback = callback; this->connectCallback = callback;
} }
void Pipe::setCallback(std::string command, Utils::Slot<Pipe::PacketCallback> callback) void Pipe::setCallback(std::string command, Utils::Slot<Pipe::PacketCallback> callback)
{ {
this->packetCallbacks[command] = callback; this->packetCallbacks[command] = callback;
} }
bool Pipe::write(std::string command, std::string data) bool Pipe::write(std::string command, std::string data)
{ {
if (this->type != IPCTYPE_CLIENT || this->pipe == INVALID_HANDLE_VALUE) return false; if (this->type != IPCTYPE_CLIENT || this->pipe == INVALID_HANDLE_VALUE) return false;
Pipe::Packet _packet; Pipe::Packet _packet;
strcpy_s(_packet.command, command.data()); strcpy_s(_packet.command, command.data());
strcpy_s(_packet.buffer, data.data()); strcpy_s(_packet.buffer, data.data());
DWORD cbBytes; DWORD cbBytes;
return (WriteFile(this->pipe, &_packet, sizeof(_packet), &cbBytes, NULL) || GetLastError() == ERROR_IO_PENDING); return (WriteFile(this->pipe, &_packet, sizeof(_packet), &cbBytes, NULL) || GetLastError() == ERROR_IO_PENDING);
} }
void Pipe::destroy() void Pipe::destroy()
{ {
//this->Type = IPCTYPE_NONE; //this->Type = IPCTYPE_NONE;
//*this->PipeFile = 0; //*this->PipeFile = 0;
//*this->PipeName = 0; //*this->PipeName = 0;
if (this->pipe && INVALID_HANDLE_VALUE != this->pipe) if (this->pipe && INVALID_HANDLE_VALUE != this->pipe)
{ {
if (this->type == IPCTYPE_SERVER) DisconnectNamedPipe(this->pipe); if (this->type == IPCTYPE_SERVER) DisconnectNamedPipe(this->pipe);
CloseHandle(this->pipe); CloseHandle(this->pipe);
Logger::Print("Disconnected from the pipe.\n"); Logger::Print("Disconnected from the pipe.\n");
} }
this->threadAttached = false; this->threadAttached = false;
if (this->thread.joinable()) if (this->thread.joinable())
{ {
Logger::Print("Terminating pipe thread...\n"); Logger::Print("Terminating pipe thread...\n");
this->thread.join(); this->thread.join();
Logger::Print("Pipe thread terminated.\n"); Logger::Print("Pipe thread terminated.\n");
} }
} }
void Pipe::setName(std::string name) void Pipe::setName(std::string name)
{ {
memset(this->pipeName, 0, sizeof(this->pipeName)); memset(this->pipeName, 0, sizeof(this->pipeName));
memset(this->pipeFile, 0, sizeof(this->pipeFile)); memset(this->pipeFile, 0, sizeof(this->pipeFile));
strncpy_s(this->pipeName, name.data(), sizeof(this->pipeName)); strncpy_s(this->pipeName, name.data(), sizeof(this->pipeName));
sprintf_s(this->pipeFile, sizeof(this->pipeFile), "\\\\.\\Pipe\\%s", this->pipeName); sprintf_s(this->pipeFile, sizeof(this->pipeFile), "\\\\.\\Pipe\\%s", this->pipeName);
} }
void Pipe::ReceiveThread(Pipe* pipe) void Pipe::ReceiveThread(Pipe* pipe)
{ {
if (!pipe || pipe->type != IPCTYPE_SERVER || pipe->pipe == INVALID_HANDLE_VALUE || !pipe->pipe) return; if (!pipe || pipe->type != IPCTYPE_SERVER || pipe->pipe == INVALID_HANDLE_VALUE || !pipe->pipe) return;
if (ConnectNamedPipe(pipe->pipe, NULL) == FALSE) if (ConnectNamedPipe(pipe->pipe, NULL) == FALSE)
{ {
Logger::Print("Failed to initialize pipe reading.\n"); Logger::Print("Failed to initialize pipe reading.\n");
return; return;
} }
Logger::Print("Client connected to the pipe\n"); Logger::Print("Client connected to the pipe\n");
pipe->connectCallback(); pipe->connectCallback();
DWORD cbBytes; DWORD cbBytes;
while (pipe->threadAttached && pipe->pipe && pipe->pipe != INVALID_HANDLE_VALUE) while (pipe->threadAttached && pipe->pipe && pipe->pipe != INVALID_HANDLE_VALUE)
{ {
BOOL bResult = ReadFile(pipe->pipe, &pipe->packet, sizeof(pipe->packet), &cbBytes, NULL); BOOL bResult = ReadFile(pipe->pipe, &pipe->packet, sizeof(pipe->packet), &cbBytes, NULL);
if (bResult && cbBytes) if (bResult && cbBytes)
{ {
if (pipe->packetCallbacks.find(pipe->packet.command) != pipe->packetCallbacks.end()) if (pipe->packetCallbacks.find(pipe->packet.command) != pipe->packetCallbacks.end())
{ {
pipe->packetCallbacks[pipe->packet.command](pipe->packet.buffer); pipe->packetCallbacks[pipe->packet.command](pipe->packet.buffer);
} }
} }
else if (pipe->threadAttached && pipe->pipe != INVALID_HANDLE_VALUE) else if (pipe->threadAttached && pipe->pipe != INVALID_HANDLE_VALUE)
{ {
Logger::Print("Failed to read from client through pipe\n"); Logger::Print("Failed to read from client through pipe\n");
DisconnectNamedPipe(pipe->pipe); DisconnectNamedPipe(pipe->pipe);
ConnectNamedPipe(pipe->pipe, NULL); ConnectNamedPipe(pipe->pipe, NULL);
pipe->connectCallback(); pipe->connectCallback();
} }
ZeroMemory(&pipe->packet, sizeof(pipe->packet)); ZeroMemory(&pipe->packet, sizeof(pipe->packet));
} }
} }
#pragma endregion #pragma endregion
// Callback to connect first instance's client pipe to the second instance's server pipe // Callback to connect first instance's client pipe to the second instance's server pipe
void IPCPipe::ConnectClient() void IPCPipe::ConnectClient()
{ {
if (Singleton::IsFirstInstance()) if (Singleton::IsFirstInstance())
{ {
IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_CLIENT); IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_CLIENT);
} }
} }
// Writes to the process on the other end of the pipe // Writes to the process on the other end of the pipe
bool IPCPipe::Write(std::string command, std::string data) bool IPCPipe::Write(std::string command, std::string data)
{ {
return IPCPipe::ClientPipe.write(command, data); return IPCPipe::ClientPipe.write(command, data);
} }
// Installs a callback for receiving commands from the process on the other end of the pipe // Installs a callback for receiving commands from the process on the other end of the pipe
void IPCPipe::On(std::string command, Utils::Slot<Pipe::PacketCallback> callback) void IPCPipe::On(std::string command, Utils::Slot<Pipe::PacketCallback> callback)
{ {
IPCPipe::ServerPipe.setCallback(command, callback); IPCPipe::ServerPipe.setCallback(command, callback);
} }
IPCPipe::IPCPipe() IPCPipe::IPCPipe()
{ {
if (Dedicated::IsEnabled()) return; if (Dedicated::IsEnabled()) return;
// Server pipe // Server pipe
IPCPipe::ServerPipe.onConnect(IPCPipe::ConnectClient); IPCPipe::ServerPipe.onConnect(IPCPipe::ConnectClient);
IPCPipe::ServerPipe.create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT)); IPCPipe::ServerPipe.create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT));
// Connect second instance's client pipe to first instance's server pipe // Connect second instance's client pipe to first instance's server pipe
if (!Singleton::IsFirstInstance()) if (!Singleton::IsFirstInstance())
{ {
IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_SERVER); IPCPipe::ClientPipe.connect(IPC_PIPE_NAME_SERVER);
} }
IPCPipe::On("ping", [] (std::string data) IPCPipe::On("ping", [] (std::string data)
{ {
Logger::Print("Received ping form pipe, sending pong!\n"); Logger::Print("Received ping form pipe, sending pong!\n");
IPCPipe::Write("pong", data); IPCPipe::Write("pong", data);
}); });
IPCPipe::On("pong", [] (std::string data) IPCPipe::On("pong", [] (std::string data)
{ {
Logger::Print("Received pong form pipe!\n"); Logger::Print("Received pong form pipe!\n");
}); });
// Test pipe functionality by sending pings // Test pipe functionality by sending pings
Command::Add("ipcping", [] (Command::Params*) Command::Add("ipcping", [] (Command::Params*)
{ {
Logger::Print("Sending ping to pipe!\n"); Logger::Print("Sending ping to pipe!\n");
IPCPipe::Write("ping", ""); IPCPipe::Write("ping", "");
}); });
} }
} }

View File

@ -1,78 +1,78 @@
#define IPC_MAX_RECONNECTS 3 #define IPC_MAX_RECONNECTS 3
#define IPC_COMMAND_SIZE 100 #define IPC_COMMAND_SIZE 100
#define IPC_BUFFER_SIZE 0x2000 #define IPC_BUFFER_SIZE 0x2000
#define IPC_PIPE_NAME_SERVER "IW4x-Server" #define IPC_PIPE_NAME_SERVER "IW4x-Server"
#define IPC_PIPE_NAME_CLIENT "IW4x-Client" #define IPC_PIPE_NAME_CLIENT "IW4x-Client"
namespace Components namespace Components
{ {
class Pipe class Pipe
{ {
public: public:
struct Packet struct Packet
{ {
char command[IPC_COMMAND_SIZE]; char command[IPC_COMMAND_SIZE];
char buffer[IPC_BUFFER_SIZE]; char buffer[IPC_BUFFER_SIZE];
}; };
enum Type enum Type
{ {
IPCTYPE_NONE, IPCTYPE_NONE,
IPCTYPE_SERVER, IPCTYPE_SERVER,
IPCTYPE_CLIENT IPCTYPE_CLIENT
}; };
typedef void(__cdecl PacketCallback)(std::string data); typedef void(__cdecl PacketCallback)(std::string data);
typedef void(__cdecl Callback)(); typedef void(__cdecl Callback)();
Pipe(); Pipe();
~Pipe(); ~Pipe();
bool connect(std::string name); bool connect(std::string name);
bool create(std::string name); bool create(std::string name);
bool write(std::string command, std::string data); bool write(std::string command, std::string data);
void setCallback(std::string command, Utils::Slot<PacketCallback> callback); void setCallback(std::string command, Utils::Slot<PacketCallback> callback);
void onConnect(Callback callback); void onConnect(Callback callback);
private: private:
Utils::Slot<void()> connectCallback; Utils::Slot<void()> connectCallback;
std::map<std::string, Utils::Slot<PacketCallback>> packetCallbacks; std::map<std::string, Utils::Slot<PacketCallback>> packetCallbacks;
HANDLE pipe; HANDLE pipe;
std::thread thread; std::thread thread;
bool threadAttached; bool threadAttached;
Type type; Type type;
Packet packet; Packet packet;
char pipeName[MAX_PATH]; char pipeName[MAX_PATH];
char pipeFile[MAX_PATH]; char pipeFile[MAX_PATH];
unsigned int reconnectAttempt; unsigned int reconnectAttempt;
void destroy(); void destroy();
void setName(std::string name); void setName(std::string name);
static void ReceiveThread(Pipe* pipe); static void ReceiveThread(Pipe* pipe);
}; };
class IPCPipe : public Component class IPCPipe : public Component
{ {
public: public:
IPCPipe(); IPCPipe();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "IPCPipe"; }; const char* getName() { return "IPCPipe"; };
#endif #endif
static bool Write(std::string command, std::string data); static bool Write(std::string command, std::string data);
static void On(std::string command, Utils::Slot<Pipe::PacketCallback> callback); static void On(std::string command, Utils::Slot<Pipe::PacketCallback> callback);
private: private:
static Pipe ServerPipe; static Pipe ServerPipe;
static Pipe ClientPipe; static Pipe ClientPipe;
static void ConnectClient(); static void ConnectClient();
}; };
} }

View File

@ -1,69 +1,69 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Game::kbutton_t Lean::in_leanleft; Game::kbutton_t Lean::in_leanleft;
Game::kbutton_t Lean::in_leanright; Game::kbutton_t Lean::in_leanright;
void Lean::IN_LeanLeft_Up() void Lean::IN_LeanLeft_Up()
{ {
Game::IN_KeyUp(&Lean::in_leanleft); Game::IN_KeyUp(&Lean::in_leanleft);
} }
void Lean::IN_LeanLeft_Down() void Lean::IN_LeanLeft_Down()
{ {
Game::IN_KeyDown(&Lean::in_leanleft); Game::IN_KeyDown(&Lean::in_leanleft);
} }
void Lean::IN_LeanRight_Up() void Lean::IN_LeanRight_Up()
{ {
Game::IN_KeyUp(&Lean::in_leanright); Game::IN_KeyUp(&Lean::in_leanright);
} }
void Lean::IN_LeanRight_Down() void Lean::IN_LeanRight_Down()
{ {
Game::IN_KeyDown(&Lean::in_leanright); Game::IN_KeyDown(&Lean::in_leanright);
} }
void Lean::SetLeanFlags(Game::usercmd_s* cmds) void Lean::SetLeanFlags(Game::usercmd_s* cmds)
{ {
if (Lean::in_leanleft.active || Lean::in_leanleft.wasPressed) if (Lean::in_leanleft.active || Lean::in_leanleft.wasPressed)
{ {
cmds->buttons |= BUTTON_FLAG_LEANLEFT; cmds->buttons |= BUTTON_FLAG_LEANLEFT;
} }
if (Lean::in_leanright.active || Lean::in_leanright.wasPressed) if (Lean::in_leanright.active || Lean::in_leanright.wasPressed)
{ {
cmds->buttons |= BUTTON_FLAG_LEANRIGHT; cmds->buttons |= BUTTON_FLAG_LEANRIGHT;
} }
Lean::in_leanleft.wasPressed = 0; Lean::in_leanleft.wasPressed = 0;
Lean::in_leanright.wasPressed = 0; Lean::in_leanright.wasPressed = 0;
} }
void __declspec(naked) Lean::CL_CmdButtonsStub() void __declspec(naked) Lean::CL_CmdButtonsStub()
{ {
__asm __asm
{ {
// CL_CmdButtons // CL_CmdButtons
mov ecx, 5A6510h mov ecx, 5A6510h
call ecx call ecx
push esi push esi
call Lean::SetLeanFlags call Lean::SetLeanFlags
pop esi pop esi
retn retn
} }
} }
Lean::Lean() Lean::Lean()
{ {
Command::AddRaw("+leanleft", Lean::IN_LeanLeft_Down, true); Command::AddRaw("+leanleft", Lean::IN_LeanLeft_Down, true);
Command::AddRaw("-leanleft", Lean::IN_LeanLeft_Up, true); Command::AddRaw("-leanleft", Lean::IN_LeanLeft_Up, true);
Command::AddRaw("+leanright", Lean::IN_LeanRight_Down, true); Command::AddRaw("+leanright", Lean::IN_LeanRight_Down, true);
Command::AddRaw("-leanright", Lean::IN_LeanRight_Up, true); Command::AddRaw("-leanright", Lean::IN_LeanRight_Up, true);
Utils::Hook(0x5A6D84, Lean::CL_CmdButtonsStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A6D84, Lean::CL_CmdButtonsStub, HOOK_CALL).install()->quick();
} }
} }

View File

@ -1,28 +1,28 @@
#define BUTTON_FLAG_LEANLEFT 0x40 #define BUTTON_FLAG_LEANLEFT 0x40
#define BUTTON_FLAG_LEANRIGHT 0x80 #define BUTTON_FLAG_LEANRIGHT 0x80
namespace Components namespace Components
{ {
class Lean : public Component class Lean : public Component
{ {
public: public:
Lean(); Lean();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Lean"; }; const char* getName() { return "Lean"; };
#endif #endif
private: private:
static Game::kbutton_t in_leanleft; static Game::kbutton_t in_leanleft;
static Game::kbutton_t in_leanright; static Game::kbutton_t in_leanright;
static void IN_LeanLeft_Up(); static void IN_LeanLeft_Up();
static void IN_LeanLeft_Down(); static void IN_LeanLeft_Down();
static void IN_LeanRight_Up(); static void IN_LeanRight_Up();
static void IN_LeanRight_Down(); static void IN_LeanRight_Down();
static void CL_CmdButtonsStub(); static void CL_CmdButtonsStub();
static void SetLeanFlags(Game::usercmd_s* cmds); static void SetLeanFlags(Game::usercmd_s* cmds);
}; };
} }

View File

@ -1,198 +1,198 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::recursive_mutex Localization::LocalizeMutex; std::recursive_mutex Localization::LocalizeMutex;
Dvar::Var Localization::UseLocalization; Dvar::Var Localization::UseLocalization;
Utils::Memory::Allocator Localization::MemAllocator; Utils::Memory::Allocator Localization::MemAllocator;
std::unordered_map<std::string, Game::LocalizeEntry*> Localization::LocalizeMap; std::unordered_map<std::string, Game::LocalizeEntry*> Localization::LocalizeMap;
std::unordered_map<std::string, Game::LocalizeEntry*> Localization::TempLocalizeMap; std::unordered_map<std::string, Game::LocalizeEntry*> Localization::TempLocalizeMap;
void Localization::Set(std::string key, std::string value) void Localization::Set(std::string key, std::string value)
{ {
std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex); std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex);
if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end()) if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
{ {
Game::LocalizeEntry* entry = Localization::LocalizeMap[key]; Game::LocalizeEntry* entry = Localization::LocalizeMap[key];
char* newStaticValue = Localization::MemAllocator.duplicateString(value); char* newStaticValue = Localization::MemAllocator.duplicateString(value);
if (!newStaticValue) return; if (!newStaticValue) return;
if (entry->value) Localization::MemAllocator.free(entry->value); if (entry->value) Localization::MemAllocator.free(entry->value);
entry->value = newStaticValue; entry->value = newStaticValue;
return; return;
} }
Game::LocalizeEntry* entry = Localization::MemAllocator.allocate<Game::LocalizeEntry>(); Game::LocalizeEntry* entry = Localization::MemAllocator.allocate<Game::LocalizeEntry>();
if (!entry) return; if (!entry) return;
entry->name = Localization::MemAllocator.duplicateString(key); entry->name = Localization::MemAllocator.duplicateString(key);
if (!entry->name) if (!entry->name)
{ {
Localization::MemAllocator.free(entry); Localization::MemAllocator.free(entry);
return; return;
} }
entry->value = Localization::MemAllocator.duplicateString(value); entry->value = Localization::MemAllocator.duplicateString(value);
if (!entry->value) if (!entry->value)
{ {
Localization::MemAllocator.free(entry->name); Localization::MemAllocator.free(entry->name);
Localization::MemAllocator.free(entry); Localization::MemAllocator.free(entry);
return; return;
} }
Localization::LocalizeMap[key] = entry; Localization::LocalizeMap[key] = entry;
} }
const char* Localization::Get(const char* key) const char* Localization::Get(const char* key)
{ {
if (!Localization::UseLocalization.get<bool>()) return key; if (!Localization::UseLocalization.get<bool>()) return key;
Game::LocalizeEntry* entry = nullptr; Game::LocalizeEntry* entry = nullptr;
std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex); std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex);
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end()) if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
{ {
entry = Localization::TempLocalizeMap[key]; entry = Localization::TempLocalizeMap[key];
} }
else if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end()) else if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end())
{ {
entry = Localization::LocalizeMap[key]; entry = Localization::LocalizeMap[key];
} }
if (!entry || !entry->value) if (!entry || !entry->value)
{ {
entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, key).localize; entry = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, key).localize;
} }
if (entry && entry->value) if (entry && entry->value)
{ {
return entry->value; return entry->value;
} }
return key; return key;
} }
void Localization::SetTemp(std::string key, std::string value) void Localization::SetTemp(std::string key, std::string value)
{ {
std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex); std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex);
if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end()) if (Localization::TempLocalizeMap.find(key) != Localization::TempLocalizeMap.end())
{ {
Game::LocalizeEntry* entry = Localization::TempLocalizeMap[key]; Game::LocalizeEntry* entry = Localization::TempLocalizeMap[key];
if(entry->value) Localization::MemAllocator.free(entry->value); if(entry->value) Localization::MemAllocator.free(entry->value);
entry->value = Localization::MemAllocator.duplicateString(value); entry->value = Localization::MemAllocator.duplicateString(value);
} }
else else
{ {
Game::LocalizeEntry* entry = Localization::MemAllocator.allocate<Game::LocalizeEntry>(); Game::LocalizeEntry* entry = Localization::MemAllocator.allocate<Game::LocalizeEntry>();
if (!entry) return; if (!entry) return;
entry->name = Localization::MemAllocator.duplicateString(key); entry->name = Localization::MemAllocator.duplicateString(key);
if (!entry->name) if (!entry->name)
{ {
Localization::MemAllocator.free(entry); Localization::MemAllocator.free(entry);
return; return;
} }
entry->value = Localization::MemAllocator.duplicateString(value); entry->value = Localization::MemAllocator.duplicateString(value);
if (!entry->value) if (!entry->value)
{ {
Localization::MemAllocator.free(entry->name); Localization::MemAllocator.free(entry->name);
Localization::MemAllocator.free(entry); Localization::MemAllocator.free(entry);
return; return;
} }
Localization::TempLocalizeMap[key] = entry; Localization::TempLocalizeMap[key] = entry;
} }
} }
void Localization::ClearTemp() void Localization::ClearTemp()
{ {
std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex); std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex);
for (auto i = Localization::TempLocalizeMap.begin(); i != Localization::TempLocalizeMap.end(); ++i) for (auto i = Localization::TempLocalizeMap.begin(); i != Localization::TempLocalizeMap.end(); ++i)
{ {
if (i->second) if (i->second)
{ {
if (i->second->name) Localization::MemAllocator.free(i->second->name); if (i->second->name) Localization::MemAllocator.free(i->second->name);
if (i->second->value) Localization::MemAllocator.free(i->second->value); if (i->second->value) Localization::MemAllocator.free(i->second->value);
Localization::MemAllocator.free(i->second); Localization::MemAllocator.free(i->second);
} }
} }
Localization::TempLocalizeMap.clear(); Localization::TempLocalizeMap.clear();
} }
void __stdcall Localization::SetStringStub(const char* key, const char* value, bool /*isEnglish*/) void __stdcall Localization::SetStringStub(const char* key, const char* value, bool /*isEnglish*/)
{ {
Localization::Set(key, value); Localization::Set(key, value);
} }
void Localization::LoadLanguageStrings() void Localization::LoadLanguageStrings()
{ {
//if (ZoneBuilder::IsEnabled()) //if (ZoneBuilder::IsEnabled())
{ {
if (FileSystem::File(Utils::String::VA("localizedstrings/iw4x_%s.str", Game::Win_GetLanguage())).exists()) if (FileSystem::File(Utils::String::VA("localizedstrings/iw4x_%s.str", Game::Win_GetLanguage())).exists())
{ {
Game::SE_Load(Utils::String::VA("localizedstrings/iw4x_%s.str", Game::Win_GetLanguage()), 0); Game::SE_Load(Utils::String::VA("localizedstrings/iw4x_%s.str", Game::Win_GetLanguage()), 0);
} }
else if (FileSystem::File("localizedstrings/iw4x_english.str").exists()) else if (FileSystem::File("localizedstrings/iw4x_english.str").exists())
{ {
Game::SE_Load("localizedstrings/iw4x_english.str", 0); Game::SE_Load("localizedstrings/iw4x_english.str", 0);
} }
} }
} }
__declspec(naked) void Localization::SELoadLanguageStub() __declspec(naked) void Localization::SELoadLanguageStub()
{ {
__asm __asm
{ {
pushad pushad
call Localization::LoadLanguageStrings call Localization::LoadLanguageStrings
popad popad
push 629E20h push 629E20h
retn retn
} }
} }
Localization::Localization() Localization::Localization()
{ {
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, [] (Game::XAssetType, std::string filename) AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_LOCALIZE_ENTRY, [] (Game::XAssetType, std::string filename)
{ {
Game::XAssetHeader header = { 0 }; Game::XAssetHeader header = { 0 };
std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex); std::lock_guard<std::recursive_mutex> _(Localization::LocalizeMutex);
if (Localization::TempLocalizeMap.find(filename) != Localization::TempLocalizeMap.end()) if (Localization::TempLocalizeMap.find(filename) != Localization::TempLocalizeMap.end())
{ {
header.localize = Localization::TempLocalizeMap[filename]; header.localize = Localization::TempLocalizeMap[filename];
} }
else if (Localization::LocalizeMap.find(filename) != Localization::LocalizeMap.end()) else if (Localization::LocalizeMap.find(filename) != Localization::LocalizeMap.end())
{ {
header.localize = Localization::LocalizeMap[filename]; header.localize = Localization::LocalizeMap[filename];
} }
return header; return header;
}); });
// Resolving hook // Resolving hook
Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).install()->quick(); Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).install()->quick();
// Set loading entry point // Set loading entry point
Utils::Hook(0x41D859, Localization::SELoadLanguageStub, HOOK_CALL).install()->quick(); Utils::Hook(0x41D859, Localization::SELoadLanguageStub, HOOK_CALL).install()->quick();
// Overwrite SetString // Overwrite SetString
Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4CE5EE, Localization::SetStringStub, HOOK_CALL).install()->quick();
Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings"); Localization::UseLocalization = Dvar::Register<bool>("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings");
} }
Localization::~Localization() Localization::~Localization()
{ {
Localization::ClearTemp(); Localization::ClearTemp();
Localization::LocalizeMap.clear(); Localization::LocalizeMap.clear();
Localization::MemAllocator.clear(); Localization::MemAllocator.clear();
} }
} }

View File

@ -1,30 +1,30 @@
namespace Components namespace Components
{ {
class Localization : public Component class Localization : public Component
{ {
public: public:
Localization(); Localization();
~Localization(); ~Localization();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Localization"; }; const char* getName() { return "Localization"; };
#endif #endif
static void Set(std::string key, std::string value); static void Set(std::string key, std::string value);
static const char* Get(const char* key); static const char* Get(const char* key);
static void SetTemp(std::string key, std::string value); static void SetTemp(std::string key, std::string value);
static void ClearTemp(); static void ClearTemp();
private: private:
static std::recursive_mutex LocalizeMutex; static std::recursive_mutex LocalizeMutex;
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static std::unordered_map<std::string, Game::LocalizeEntry*> LocalizeMap; static std::unordered_map<std::string, Game::LocalizeEntry*> LocalizeMap;
static std::unordered_map<std::string, Game::LocalizeEntry*> TempLocalizeMap; static std::unordered_map<std::string, Game::LocalizeEntry*> TempLocalizeMap;
static Dvar::Var UseLocalization; static Dvar::Var UseLocalization;
static void __stdcall SetStringStub(const char* key, const char* value, bool isEnglish); static void __stdcall SetStringStub(const char* key, const char* value, bool isEnglish);
static void LoadLanguageStrings(); static void LoadLanguageStrings();
static void SELoadLanguageStub(); static void SELoadLanguageStub();
}; };
} }

View File

@ -1,325 +1,325 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::mutex Logger::MessageMutex; std::mutex Logger::MessageMutex;
std::vector<std::string> Logger::MessageQueue; std::vector<std::string> Logger::MessageQueue;
std::vector<Network::Address> Logger::LoggingAddresses[2]; std::vector<Network::Address> Logger::LoggingAddresses[2];
void(*Logger::PipeCallback)(std::string) = nullptr; void(*Logger::PipeCallback)(std::string) = nullptr;
bool Logger::IsConsoleReady() bool Logger::IsConsoleReady()
{ {
return (IsWindow(*reinterpret_cast<HWND*>(0x64A3288)) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console"))); return (IsWindow(*reinterpret_cast<HWND*>(0x64A3288)) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console")));
} }
void Logger::PrintStub(int channel, const char* message, ...) void Logger::PrintStub(int channel, const char* message, ...)
{ {
return Logger::MessagePrint(channel, Logger::Format(&message)); return Logger::MessagePrint(channel, Logger::Format(&message));
} }
void Logger::Print(const char* message, ...) void Logger::Print(const char* message, ...)
{ {
return Logger::MessagePrint(0, Logger::Format(&message)); return Logger::MessagePrint(0, Logger::Format(&message));
} }
void Logger::Print(int channel, const char* message, ...) void Logger::Print(int channel, const char* message, ...)
{ {
return Logger::MessagePrint(channel, Logger::Format(&message)); return Logger::MessagePrint(channel, Logger::Format(&message));
} }
void Logger::MessagePrint(int channel, std::string message) void Logger::MessagePrint(int channel, std::string message)
{ {
if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests()) if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests())
{ {
printf("%s", message.data()); printf("%s", message.data());
fflush(stdout); fflush(stdout);
return; return;
} }
if (!Logger::IsConsoleReady()) if (!Logger::IsConsoleReady())
{ {
OutputDebugStringA(message.data()); OutputDebugStringA(message.data());
} }
if (!Game::Sys_IsMainThread()) if (!Game::Sys_IsMainThread())
{ {
Logger::EnqueueMessage(message); Logger::EnqueueMessage(message);
} }
else else
{ {
Game::Com_PrintMessage(channel, message.data(), 0); Game::Com_PrintMessage(channel, message.data(), 0);
} }
} }
void Logger::ErrorPrint(int error, std::string message) void Logger::ErrorPrint(int error, std::string message)
{ {
return Game::Com_Error(error, "%s", message.data()); return Game::Com_Error(error, "%s", message.data());
} }
void Logger::Error(int error, const char* message, ...) void Logger::Error(int error, const char* message, ...)
{ {
return Logger::ErrorPrint(error, Logger::Format(&message)); return Logger::ErrorPrint(error, Logger::Format(&message));
} }
void Logger::Error(const char* message, ...) void Logger::Error(const char* message, ...)
{ {
return Logger::ErrorPrint(0, Logger::Format(&message)); return Logger::ErrorPrint(0, Logger::Format(&message));
} }
void Logger::SoftError(const char* message, ...) void Logger::SoftError(const char* message, ...)
{ {
return Logger::ErrorPrint(2, Logger::Format(&message)); return Logger::ErrorPrint(2, Logger::Format(&message));
} }
std::string Logger::Format(const char** message) std::string Logger::Format(const char** message)
{ {
char buffer[0x1000] = { 0 }; char buffer[0x1000] = { 0 };
va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1])); va_list ap = reinterpret_cast<char*>(const_cast<char**>(&message[1]));
//va_start(ap, *message); //va_start(ap, *message);
_vsnprintf_s(buffer, sizeof(buffer), *message, ap); _vsnprintf_s(buffer, sizeof(buffer), *message, ap);
va_end(ap); va_end(ap);
return buffer; return buffer;
} }
void Logger::Flush() void Logger::Flush()
{ {
// if (!Game::Sys_IsMainThread()) // if (!Game::Sys_IsMainThread())
// { // {
// while (!Logger::MessageQueue.empty()) // while (!Logger::MessageQueue.empty())
// { // {
// std::this_thread::sleep_for(10ms); // std::this_thread::sleep_for(10ms);
// } // }
// } // }
// else // else
{ {
Logger::Frame(); Logger::Frame();
} }
} }
void Logger::Frame() void Logger::Frame()
{ {
std::lock_guard<std::mutex> _(Logger::MessageMutex); std::lock_guard<std::mutex> _(Logger::MessageMutex);
for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i)
{ {
Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0); Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0);
if (!Logger::IsConsoleReady()) if (!Logger::IsConsoleReady())
{ {
OutputDebugStringA(Logger::MessageQueue[i].data()); OutputDebugStringA(Logger::MessageQueue[i].data());
} }
} }
Logger::MessageQueue.clear(); Logger::MessageQueue.clear();
} }
void Logger::PipeOutput(void(*callback)(std::string)) void Logger::PipeOutput(void(*callback)(std::string))
{ {
Logger::PipeCallback = callback; Logger::PipeCallback = callback;
} }
void Logger::PrintMessagePipe(const char* data) void Logger::PrintMessagePipe(const char* data)
{ {
if (Logger::PipeCallback) if (Logger::PipeCallback)
{ {
Logger::PipeCallback(data); Logger::PipeCallback(data);
} }
} }
void Logger::NetworkLog(const char* data, bool gLog) void Logger::NetworkLog(const char* data, bool gLog)
{ {
if (!data) return; if (!data) return;
std::string buffer(data); std::string buffer(data);
for (auto& addr : Logger::LoggingAddresses[gLog & 1]) for (auto& addr : Logger::LoggingAddresses[gLog & 1])
{ {
Network::SendCommand(addr, "print", buffer); Network::SendCommand(addr, "print", buffer);
} }
} }
__declspec(naked) void Logger::GameLogStub() __declspec(naked) void Logger::GameLogStub()
{ {
__asm __asm
{ {
push 1 push 1
push [esp + 8h] push [esp + 8h]
call Logger::NetworkLog call Logger::NetworkLog
add esp, 8h add esp, 8h
mov eax, 4576C0h mov eax, 4576C0h
jmp eax jmp eax
} }
} }
__declspec(naked) void Logger::PrintMessageStub() __declspec(naked) void Logger::PrintMessageStub()
{ {
__asm __asm
{ {
mov eax, Logger::PipeCallback mov eax, Logger::PipeCallback
test eax, eax test eax, eax
jz returnPrint jz returnPrint
push [esp + 8h] push [esp + 8h]
call Logger::PrintMessagePipe call Logger::PrintMessagePipe
add esp, 4h add esp, 4h
retn retn
returnPrint: returnPrint:
push 0 push 0
push [esp + 0Ch] push [esp + 0Ch]
call Logger::NetworkLog call Logger::NetworkLog
add esp, 8h add esp, 8h
push esi push esi
mov esi, [esp + 0Ch] mov esi, [esp + 0Ch]
mov eax, 4AA835h mov eax, 4AA835h
jmp eax jmp eax
} }
} }
void Logger::EnqueueMessage(std::string message) void Logger::EnqueueMessage(std::string message)
{ {
Logger::MessageMutex.lock(); Logger::MessageMutex.lock();
Logger::MessageQueue.push_back(message); Logger::MessageQueue.push_back(message);
Logger::MessageMutex.unlock(); Logger::MessageMutex.unlock();
} }
Logger::Logger() Logger::Logger()
{ {
Logger::PipeOutput(nullptr); Logger::PipeOutput(nullptr);
QuickPatch::OnFrame(Logger::Frame); QuickPatch::OnFrame(Logger::Frame);
Utils::Hook(0x4B0218, Logger::GameLogStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4B0218, Logger::GameLogStub, HOOK_CALL).install()->quick();
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).install()->quick(); Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).install()->quick();
if (Loader::PerformingUnitTests()) if (Loader::PerformingUnitTests())
{ {
Utils::Hook(Game::Com_Printf, Logger::PrintStub, HOOK_JUMP).install()->quick(); Utils::Hook(Game::Com_Printf, Logger::PrintStub, HOOK_JUMP).install()->quick();
} }
Dvar::OnInit([] () Dvar::OnInit([] ()
{ {
Command::AddSV("log_add", [] (Command::Params* params) Command::AddSV("log_add", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
Network::Address addr(params->get(1)); Network::Address addr(params->get(1));
if (std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr) == Logger::LoggingAddresses[0].end()) if (std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr) == Logger::LoggingAddresses[0].end())
{ {
Logger::LoggingAddresses[0].push_back(addr); Logger::LoggingAddresses[0].push_back(addr);
} }
}); });
Command::AddSV("log_del", [] (Command::Params* params) Command::AddSV("log_del", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
int num = atoi(params->get(1)); int num = atoi(params->get(1));
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size()) if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size())
{ {
auto addr = Logger::LoggingAddresses[0].begin() + num; auto addr = Logger::LoggingAddresses[0].begin() + num;
Logger::Print("Address %s removed\n", addr->getCString()); Logger::Print("Address %s removed\n", addr->getCString());
Logger::LoggingAddresses[0].erase(addr); Logger::LoggingAddresses[0].erase(addr);
} }
else else
{ {
Network::Address addr(params->get(1)); Network::Address addr(params->get(1));
auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr); auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr);
if (i != Logger::LoggingAddresses[0].end()) if (i != Logger::LoggingAddresses[0].end())
{ {
Logger::LoggingAddresses[0].erase(i); Logger::LoggingAddresses[0].erase(i);
Logger::Print("Address %s removed\n", addr.getCString()); Logger::Print("Address %s removed\n", addr.getCString());
} }
else else
{ {
Logger::Print("Address %s not found!\n", addr.getCString()); Logger::Print("Address %s not found!\n", addr.getCString());
} }
} }
}); });
Command::AddSV("log_list", [] (Command::Params*) Command::AddSV("log_list", [] (Command::Params*)
{ {
Logger::Print("# ID: Address\n"); Logger::Print("# ID: Address\n");
Logger::Print("-------------\n"); Logger::Print("-------------\n");
for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i) for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i)
{ {
Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[0][i].getCString()); Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[0][i].getCString());
} }
}); });
Command::AddSV("g_log_add", [] (Command::Params* params) Command::AddSV("g_log_add", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
Network::Address addr(params->get(1)); Network::Address addr(params->get(1));
if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end()) if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end())
{ {
Logger::LoggingAddresses[1].push_back(addr); Logger::LoggingAddresses[1].push_back(addr);
} }
}); });
Command::AddSV("g_log_del", [] (Command::Params* params) Command::AddSV("g_log_del", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
int num = atoi(params->get(1)); int num = atoi(params->get(1));
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size()) if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size())
{ {
auto addr = Logger::LoggingAddresses[1].begin() + num; auto addr = Logger::LoggingAddresses[1].begin() + num;
Logger::Print("Address %s removed\n", addr->getCString()); Logger::Print("Address %s removed\n", addr->getCString());
Logger::LoggingAddresses[1].erase(addr); Logger::LoggingAddresses[1].erase(addr);
} }
else else
{ {
Network::Address addr(params->get(1)); Network::Address addr(params->get(1));
auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr); auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr);
if (i != Logger::LoggingAddresses[1].end()) if (i != Logger::LoggingAddresses[1].end())
{ {
Logger::LoggingAddresses[1].erase(i); Logger::LoggingAddresses[1].erase(i);
Logger::Print("Address %s removed\n", addr.getCString()); Logger::Print("Address %s removed\n", addr.getCString());
} }
else else
{ {
Logger::Print("Address %s not found!\n", addr.getCString()); Logger::Print("Address %s not found!\n", addr.getCString());
} }
} }
}); });
Command::AddSV("g_log_list", [] (Command::Params*) Command::AddSV("g_log_list", [] (Command::Params*)
{ {
Logger::Print("# ID: Address\n"); Logger::Print("# ID: Address\n");
Logger::Print("-------------\n"); Logger::Print("-------------\n");
for (unsigned int i = 0; i < Logger::LoggingAddresses[1].size(); ++i) for (unsigned int i = 0; i < Logger::LoggingAddresses[1].size(); ++i)
{ {
Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[1][i].getCString()); Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[1][i].getCString());
} }
}); });
}); });
} }
Logger::~Logger() Logger::~Logger()
{ {
Logger::LoggingAddresses[0].clear(); Logger::LoggingAddresses[0].clear();
Logger::LoggingAddresses[1].clear(); Logger::LoggingAddresses[1].clear();
Logger::MessageMutex.lock(); Logger::MessageMutex.lock();
Logger::MessageQueue.clear(); Logger::MessageQueue.clear();
Logger::MessageMutex.unlock(); Logger::MessageMutex.unlock();
// Flush the console log // Flush the console log
if (int fh = *reinterpret_cast<int*>(0x1AD8F28)) if (int fh = *reinterpret_cast<int*>(0x1AD8F28))
{ {
Game::FS_FCloseFile(fh); Game::FS_FCloseFile(fh);
} }
} }
} }

View File

@ -1,44 +1,44 @@
namespace Components namespace Components
{ {
class Logger : public Component class Logger : public Component
{ {
public: public:
Logger(); Logger();
~Logger(); ~Logger();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Logger"; }; const char* getName() { return "Logger"; };
#endif #endif
static void MessagePrint(int channel, std::string message); static void MessagePrint(int channel, std::string message);
static void Print(int channel, const char* message, ...); static void Print(int channel, const char* message, ...);
static void Print(const char* message, ...); static void Print(const char* message, ...);
static void ErrorPrint(int error, std::string message); static void ErrorPrint(int error, std::string message);
static void Error(const char* message, ...); static void Error(const char* message, ...);
static void Error(int error, const char* message, ...); static void Error(int error, const char* message, ...);
static void SoftError(const char* message, ...); static void SoftError(const char* message, ...);
static bool IsConsoleReady(); static bool IsConsoleReady();
static void PrintStub(int channel, const char* message, ...); static void PrintStub(int channel, const char* message, ...);
static void PipeOutput(void(*callback)(std::string)); static void PipeOutput(void(*callback)(std::string));
static void Flush(); static void Flush();
private: private:
static std::mutex MessageMutex; static std::mutex MessageMutex;
static std::vector<std::string> MessageQueue; static std::vector<std::string> MessageQueue;
static std::vector<Network::Address> LoggingAddresses[2]; static std::vector<Network::Address> LoggingAddresses[2];
static void(*PipeCallback)(std::string); static void(*PipeCallback)(std::string);
static void Frame(); static void Frame();
static void GameLogStub(); static void GameLogStub();
static void PrintMessageStub(); static void PrintMessageStub();
static void PrintMessagePipe(const char* data); static void PrintMessagePipe(const char* data);
static void EnqueueMessage(std::string message); static void EnqueueMessage(std::string message);
static void NetworkLog(const char* data, bool gLog); static void NetworkLog(const char* data, bool gLog);
static std::string Format(const char** message); static std::string Format(const char** message);
}; };
} }

View File

@ -1,59 +1,59 @@
namespace Components namespace Components
{ {
class Maps : public Component class Maps : public Component
{ {
public: public:
Maps(); Maps();
~Maps(); ~Maps();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Maps"; }; const char* getName() { return "Maps"; };
#endif #endif
static void HandleAsSPMap(); static void HandleAsSPMap();
static void AddDependency(std::string expression, std::string zone); static void AddDependency(std::string expression, std::string zone);
static std::pair<std::string, std::string> GetTeamsForMap(std::string map); static std::pair<std::string, std::string> GetTeamsForMap(std::string map);
static std::vector<std::string> GetDependenciesForMap(std::string map); static std::vector<std::string> GetDependenciesForMap(std::string map);
static std::string CurrentMainZone; static std::string CurrentMainZone;
private: private:
class DLC class DLC
{ {
public: public:
int index; int index;
std::string url; std::string url;
std::vector<std::string> maps; std::vector<std::string> maps;
}; };
static bool IsSPMap; static bool IsSPMap;
static std::vector<DLC> DlcPacks; static std::vector<DLC> DlcPacks;
static std::vector<Game::XAssetEntry> EntryPool; static std::vector<Game::XAssetEntry> EntryPool;
static std::vector<std::pair<std::string, std::string>> DependencyList; static std::vector<std::pair<std::string, std::string>> DependencyList;
static std::vector<std::string> CurrentDependencies; static std::vector<std::string> CurrentDependencies;
static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname); static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname);
static void LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict); static void LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool* restrict);
static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
static void OverrideMapEnts(Game::MapEnts* ents); static void OverrideMapEnts(Game::MapEnts* ents);
static int IgnoreEntityStub(const char* entity); static int IgnoreEntityStub(const char* entity);
static Game::G_GlassData* GetWorldData(); static Game::G_GlassData* GetWorldData();
static void GetWorldDataStub(); static void GetWorldDataStub();
static void LoadRawSun(); static void LoadRawSun();
static void AddDlc(DLC dlc); static void AddDlc(DLC dlc);
static void UpdateDlcStatus(); static void UpdateDlcStatus();
#if defined(DEBUG) && defined(ENABLE_DXSDK) #if defined(DEBUG) && defined(ENABLE_DXSDK)
static void ExportMap(Game::GfxWorld* world); static void ExportMap(Game::GfxWorld* world);
#endif #endif
void reallocateEntryPool(); void reallocateEntryPool();
}; };
} }

View File

@ -1,189 +1,189 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
int Materials::ImageNameLength; int Materials::ImageNameLength;
Utils::Hook Materials::ImageVersionCheckHook; Utils::Hook Materials::ImageVersionCheckHook;
__declspec(naked) void Materials::ImageVersionCheck() __declspec(naked) void Materials::ImageVersionCheck()
{ {
__asm __asm
{ {
cmp eax, 9 cmp eax, 9
je returnSafely je returnSafely
jmp Materials::ImageVersionCheckHook.original jmp Materials::ImageVersionCheckHook.original
returnSafely: returnSafely:
mov al, 1 mov al, 1
add esp, 18h add esp, 18h
retn retn
} }
} }
Game::Material* Materials::ResolveMaterial(const char* stringPtr) Game::Material* Materials::ResolveMaterial(const char* stringPtr)
{ {
const char* imagePtr = stringPtr + 4; const char* imagePtr = stringPtr + 4;
unsigned int length = static_cast<unsigned int>(stringPtr[3] & 0xFF); unsigned int length = static_cast<unsigned int>(stringPtr[3] & 0xFF);
if (strlen(imagePtr) >= length) if (strlen(imagePtr) >= length)
{ {
Materials::ImageNameLength = 4 + length; Materials::ImageNameLength = 4 + length;
std::string image(imagePtr, length); std::string image(imagePtr, length);
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material; return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, image.data()).material;
} }
Materials::ImageNameLength = 4; Materials::ImageNameLength = 4;
return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; return Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material;
} }
__declspec(naked) void Materials::PostDrawMaterialStub() __declspec(naked) void Materials::PostDrawMaterialStub()
{ {
__asm __asm
{ {
mov eax, Materials::ImageNameLength mov eax, Materials::ImageNameLength
add [esp + 30h], eax add [esp + 30h], eax
mov eax, 5358FFh mov eax, 5358FFh
jmp eax jmp eax
} }
} }
__declspec(naked) void Materials::DrawMaterialStub() __declspec(naked) void Materials::DrawMaterialStub()
{ {
__asm __asm
{ {
push ecx push ecx
call Materials::ResolveMaterial call Materials::ResolveMaterial
add esp, 4h add esp, 4h
mov edx, 5310F0h mov edx, 5310F0h
jmp edx jmp edx
} }
} }
int Materials::WriteDeathMessageIcon(char* string, int offset, Game::Material* material) int Materials::WriteDeathMessageIcon(char* string, int offset, Game::Material* material)
{ {
if (!material) if (!material)
{ {
material = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material; material = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MATERIAL, "default").material;
} }
int length = strlen(material->name); int length = strlen(material->name);
string[offset++] = static_cast<char>(length); string[offset++] = static_cast<char>(length);
strncpy_s(string + offset, 1024 - offset, material->name, length); strncpy_s(string + offset, 1024 - offset, material->name, length);
return offset + length; return offset + length;
} }
__declspec(naked) void Materials::DeathMessageStub() __declspec(naked) void Materials::DeathMessageStub()
{ {
__asm __asm
{ {
push edx // Material push edx // Material
push eax // offset push eax // offset
push ecx // String push ecx // String
call Materials::WriteDeathMessageIcon call Materials::WriteDeathMessageIcon
add esp, 14h add esp, 14h
retn retn
} }
} }
int Materials::FormatImagePath(char* buffer, size_t size, int, int, const char* image) int Materials::FormatImagePath(char* buffer, size_t size, int, int, const char* image)
{ {
#if 0 #if 0
if (Utils::String::StartsWith(image, "preview_")) if (Utils::String::StartsWith(image, "preview_"))
{ {
std::string newImage = image; std::string newImage = image;
Utils::String::Replace(newImage, "preview_", "loadscreen_"); Utils::String::Replace(newImage, "preview_", "loadscreen_");
if (FileSystem::FileReader(fmt::sprintf("images/%s.iwi", newImage.data())).exists()) if (FileSystem::FileReader(fmt::sprintf("images/%s.iwi", newImage.data())).exists())
{ {
image = Utils::String::VA("%s", newImage.data()); image = Utils::String::VA("%s", newImage.data());
} }
} }
#endif #endif
return _snprintf_s(buffer, size, size, "images/%s.iwi", image); return _snprintf_s(buffer, size, size, "images/%s.iwi", image);
} }
#ifdef DEBUG #ifdef DEBUG
void Materials::DumpImageCfg(int, const char*, const char* material) void Materials::DumpImageCfg(int, const char*, const char* material)
{ {
Materials::DumpImageCfgPath(0, nullptr, Utils::String::VA("images/%s.iwi", material)); Materials::DumpImageCfgPath(0, nullptr, Utils::String::VA("images/%s.iwi", material));
} }
void Materials::DumpImageCfgPath(int, const char*, const char* material) void Materials::DumpImageCfgPath(int, const char*, const char* material)
{ {
FILE* fp = nullptr; FILE* fp = nullptr;
if (!fopen_s(&fp, "dump.cfg", "a") && fp) if (!fopen_s(&fp, "dump.cfg", "a") && fp)
{ {
fprintf(fp, "dumpraw %s\n", material); fprintf(fp, "dumpraw %s\n", material);
fclose(fp); fclose(fp);
} }
} }
int Materials::MaterialComparePrint(Game::Material* m1, Game::Material* m2) int Materials::MaterialComparePrint(Game::Material* m1, Game::Material* m2)
{ {
static Game::Material* a,* b; static Game::Material* a,* b;
a = m1, b = m2; a = m1, b = m2;
return Utils::Hook::Call<int(Game::Material*, Game::Material*)>(0x5235B0)(m1, m2); return Utils::Hook::Call<int(Game::Material*, Game::Material*)>(0x5235B0)(m1, m2);
} }
#endif #endif
Materials::Materials() Materials::Materials()
{ {
Materials::ImageNameLength = 7; Materials::ImageNameLength = 7;
// Allow codo images // Allow codo images
Materials::ImageVersionCheckHook.initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->install(); Materials::ImageVersionCheckHook.initialize(0x53A456, Materials::ImageVersionCheck, HOOK_CALL)->install();
// Fix material pointer exploit // Fix material pointer exploit
Utils::Hook(0x534E0C, Materials::DrawMaterialStub, HOOK_CALL).install()->quick(); Utils::Hook(0x534E0C, Materials::DrawMaterialStub, HOOK_CALL).install()->quick();
// Increment string pointer accordingly // Increment string pointer accordingly
Utils::Hook(0x5358FA, Materials::PostDrawMaterialStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x5358FA, Materials::PostDrawMaterialStub, HOOK_JUMP).install()->quick();
// Adapt death message to IW5 material format // Adapt death message to IW5 material format
Utils::Hook(0x5A30D9, Materials::DeathMessageStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x5A30D9, Materials::DeathMessageStub, HOOK_JUMP).install()->quick();
// Resolve preview images to loadscreens // Resolve preview images to loadscreens
Utils::Hook(0x53AC19, Materials::FormatImagePath, HOOK_CALL).install()->quick(); Utils::Hook(0x53AC19, Materials::FormatImagePath, HOOK_CALL).install()->quick();
#ifdef DEBUG #ifdef DEBUG
if (Flags::HasFlag("dump")) if (Flags::HasFlag("dump"))
{ {
Utils::Hook(0x51F5AC, Materials::DumpImageCfg, HOOK_CALL).install()->quick(); Utils::Hook(0x51F5AC, Materials::DumpImageCfg, HOOK_CALL).install()->quick();
Utils::Hook(0x51F4C4, Materials::DumpImageCfg, HOOK_CALL).install()->quick(); Utils::Hook(0x51F4C4, Materials::DumpImageCfg, HOOK_CALL).install()->quick();
Utils::Hook(0x53AC62, Materials::DumpImageCfgPath, HOOK_CALL).install()->quick(); Utils::Hook(0x53AC62, Materials::DumpImageCfgPath, HOOK_CALL).install()->quick();
} }
else else
{ {
// Ignore missing images // Ignore missing images
Utils::Hook::Nop(0x51F5AC, 5); Utils::Hook::Nop(0x51F5AC, 5);
Utils::Hook::Nop(0x51F4C4, 5); Utils::Hook::Nop(0x51F4C4, 5);
} }
Utils::Hook::Set<void*>(0x523894, Materials::MaterialComparePrint); Utils::Hook::Set<void*>(0x523894, Materials::MaterialComparePrint);
#endif #endif
// Renderer::OnFrame([] () // Renderer::OnFrame([] ()
// { // {
// Game::Font* font = Game::R_RegisterFont("fonts/normalFont"); // Game::Font* font = Game::R_RegisterFont("fonts/normalFont");
// float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; // float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
// //
// Game::R_AddCmdDrawText("test^==preview_mp_rustzob", 0x7FFFFFFF, font, 500.0f, 150.0f, 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED); // Game::R_AddCmdDrawText("test^==preview_mp_rustzob", 0x7FFFFFFF, font, 500.0f, 150.0f, 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_SHADOWED);
// }); // });
} }
Materials::~Materials() Materials::~Materials()
{ {
Materials::ImageVersionCheckHook.uninstall(); Materials::ImageVersionCheckHook.uninstall();
} }
} }

View File

@ -1,34 +1,34 @@
namespace Components namespace Components
{ {
class Materials : public Component class Materials : public Component
{ {
public: public:
Materials(); Materials();
~Materials(); ~Materials();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Materials"; }; const char* getName() { return "Materials"; };
#endif #endif
static int FormatImagePath(char* buffer, size_t size, int, int, const char* image); static int FormatImagePath(char* buffer, size_t size, int, int, const char* image);
private: private:
static int ImageNameLength; static int ImageNameLength;
static Utils::Hook ImageVersionCheckHook; static Utils::Hook ImageVersionCheckHook;
static void ImageVersionCheck(); static void ImageVersionCheck();
static Game::Material* ResolveMaterial(const char* stringPtr); static Game::Material* ResolveMaterial(const char* stringPtr);
static void DrawMaterialStub(); static void DrawMaterialStub();
static void PostDrawMaterialStub(); static void PostDrawMaterialStub();
static int WriteDeathMessageIcon(char* string, int offset, Game::Material* material); static int WriteDeathMessageIcon(char* string, int offset, Game::Material* material);
static void DeathMessageStub(); static void DeathMessageStub();
#ifdef DEBUG #ifdef DEBUG
static void DumpImageCfg(int, const char*, const char* material); static void DumpImageCfg(int, const char*, const char* material);
static void DumpImageCfgPath(int, const char*, const char* material); static void DumpImageCfgPath(int, const char*, const char* material);
static int MaterialComparePrint(Game::Material* m1, Game::Material* m2); static int MaterialComparePrint(Game::Material* m1, Game::Material* m2);
#endif #endif
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +1,60 @@
#define MAX_SOURCEFILES 64 #define MAX_SOURCEFILES 64
#undef LoadMenu #undef LoadMenu
namespace Components namespace Components
{ {
class Menus : public Component class Menus : public Component
{ {
public: public:
Menus(); Menus();
~Menus(); ~Menus();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Menus"; }; const char* getName() { return "Menus"; };
#endif #endif
static void FreeEverything(); static void FreeEverything();
static void Add(std::string menu); static void Add(std::string menu);
private: private:
static std::unordered_map<std::string, Game::menuDef_t*> MenuList; static std::unordered_map<std::string, Game::menuDef_t*> MenuList;
static std::unordered_map<std::string, Game::MenuList*> MenuListList; static std::unordered_map<std::string, Game::MenuList*> MenuListList;
static std::vector<std::string> CustomMenus; static std::vector<std::string> CustomMenus;
static Game::XAssetHeader MenuLoad(Game::XAssetType type, std::string filename); static Game::XAssetHeader MenuLoad(Game::XAssetType type, std::string filename);
static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, std::string filename); static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, std::string filename);
static Game::MenuList* LoadMenuList(Game::MenuList* menuList); static Game::MenuList* LoadMenuList(Game::MenuList* menuList);
static Game::MenuList* LoadScriptMenu(const char* menu); static Game::MenuList* LoadScriptMenu(const char* menu);
static std::vector<Game::menuDef_t*> LoadMenu(Game::menuDef_t* menudef); static std::vector<Game::menuDef_t*> LoadMenu(Game::menuDef_t* menudef);
static std::vector<Game::menuDef_t*> LoadMenu(std::string file); static std::vector<Game::menuDef_t*> LoadMenu(std::string file);
static Game::script_t* LoadMenuScript(std::string name, std::string buffer); static Game::script_t* LoadMenuScript(std::string name, std::string buffer);
static int LoadMenuSource(std::string name, std::string buffer); static int LoadMenuSource(std::string name, std::string buffer);
static int ReserveSourceHandle(); static int ReserveSourceHandle();
static bool IsValidSourceHandle(int handle); static bool IsValidSourceHandle(int handle);
static Game::menuDef_t* ParseMenu(int handle); static Game::menuDef_t* ParseMenu(int handle);
static void FreeMenuSource(int handle); static void FreeMenuSource(int handle);
static void FreeMenuList(Game::MenuList* menuList); static void FreeMenuList(Game::MenuList* menuList);
static void FreeMenu(Game::menuDef_t* menudef); static void FreeMenu(Game::menuDef_t* menudef);
static void RemoveMenu(std::string menu); static void RemoveMenu(std::string menu);
static void RemoveMenu(Game::menuDef_t* menudef); static void RemoveMenu(Game::menuDef_t* menudef);
static void RemoveMenuList(std::string menuList); static void RemoveMenuList(std::string menuList);
static void RemoveMenuList(Game::MenuList* menuList); static void RemoveMenuList(Game::MenuList* menuList);
static void OverrideMenu(Game::menuDef_t *menu); static void OverrideMenu(Game::menuDef_t *menu);
static bool IsMenuVisible(Game::UiContext *dc, Game::menuDef_t *menu); static bool IsMenuVisible(Game::UiContext *dc, Game::menuDef_t *menu);
static void RemoveMenuFromContext(Game::UiContext *dc, Game::menuDef_t *menu); static void RemoveMenuFromContext(Game::UiContext *dc, Game::menuDef_t *menu);
// Ugly! // Ugly!
static int KeywordHash(char* key); static int KeywordHash(char* key);
}; };
} }

View File

@ -1,107 +1,107 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::vector<std::string> ModList::Mods; std::vector<std::string> ModList::Mods;
unsigned int ModList::CurrentMod; unsigned int ModList::CurrentMod;
bool ModList::HasMod(std::string modName) bool ModList::HasMod(std::string modName)
{ {
auto list = FileSystem::GetSysFileList(Dvar::Var("fs_basepath").get<std::string>() + "\\mods", "", true); auto list = FileSystem::GetSysFileList(Dvar::Var("fs_basepath").get<std::string>() + "\\mods", "", true);
for (auto mod : list) for (auto mod : list)
{ {
if (mod == modName) if (mod == modName)
{ {
return true; return true;
} }
} }
return false; return false;
} }
unsigned int ModList::GetItemCount() unsigned int ModList::GetItemCount()
{ {
return ModList::Mods.size(); return ModList::Mods.size();
} }
const char* ModList::GetItemText(unsigned int index, int /*column*/) const char* ModList::GetItemText(unsigned int index, int /*column*/)
{ {
if (index < ModList::Mods.size()) if (index < ModList::Mods.size())
{ {
return ModList::Mods[index].data(); return ModList::Mods[index].data();
} }
return "..."; return "...";
} }
void ModList::Select(unsigned int index) void ModList::Select(unsigned int index)
{ {
ModList::CurrentMod = index; ModList::CurrentMod = index;
} }
void ModList::UIScript_LoadMods(UIScript::Token) void ModList::UIScript_LoadMods(UIScript::Token)
{ {
auto folder = Dvar::Var("fs_basepath").get<std::string>() + "\\mods"; auto folder = Dvar::Var("fs_basepath").get<std::string>() + "\\mods";
Game::Com_Printf(0, "Searching for mods in %s...\n", folder.data()); Game::Com_Printf(0, "Searching for mods in %s...\n", folder.data());
ModList::Mods = FileSystem::GetSysFileList(folder, "", true); ModList::Mods = FileSystem::GetSysFileList(folder, "", true);
Game::Com_Printf(0, "Found %i mods!\n", ModList::Mods.size()); Game::Com_Printf(0, "Found %i mods!\n", ModList::Mods.size());
} }
void ModList::UIScript_RunMod(UIScript::Token) void ModList::UIScript_RunMod(UIScript::Token)
{ {
if (ModList::CurrentMod < ModList::Mods.size()) if (ModList::CurrentMod < ModList::Mods.size())
{ {
ModList::RunMod(ModList::Mods[ModList::CurrentMod]); ModList::RunMod(ModList::Mods[ModList::CurrentMod]);
} }
} }
void ModList::UIScript_ClearMods(UIScript::Token) void ModList::UIScript_ClearMods(UIScript::Token)
{ {
auto fsGame = Dvar::Var("fs_game"); auto fsGame = Dvar::Var("fs_game");
fsGame.set(""); fsGame.set("");
fsGame.get<Game::dvar_t*>()->modified = true; fsGame.get<Game::dvar_t*>()->modified = true;
if (Dvar::Var("cl_modVidRestart").get<bool>()) if (Dvar::Var("cl_modVidRestart").get<bool>())
{ {
Game::Cmd_ExecuteSingleCommand(0, 0, "vid_restart"); Game::Cmd_ExecuteSingleCommand(0, 0, "vid_restart");
} }
else else
{ {
Game::Cmd_ExecuteSingleCommand(0, 0, "closemenu mods_menu"); Game::Cmd_ExecuteSingleCommand(0, 0, "closemenu mods_menu");
} }
} }
void ModList::RunMod(std::string mod) void ModList::RunMod(std::string mod)
{ {
auto fsGame = Dvar::Var("fs_game"); auto fsGame = Dvar::Var("fs_game");
fsGame.set(Utils::String::VA("mods/%s", mod.data())); fsGame.set(Utils::String::VA("mods/%s", mod.data()));
fsGame.get<Game::dvar_t*>()->modified = true; fsGame.get<Game::dvar_t*>()->modified = true;
if (Dvar::Var("cl_modVidRestart").get<bool>()) if (Dvar::Var("cl_modVidRestart").get<bool>())
{ {
Command::Execute("vid_restart", false); Command::Execute("vid_restart", false);
} }
else else
{ {
Command::Execute("closemenu mods_menu", false); Command::Execute("closemenu mods_menu", false);
} }
} }
ModList::ModList() ModList::ModList()
{ {
ModList::CurrentMod = 0; ModList::CurrentMod = 0;
Dvar::Register("cl_modVidRestart", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Perform a vid_restart when loading a mod."); Dvar::Register("cl_modVidRestart", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Perform a vid_restart when loading a mod.");
UIScript::Add("LoadMods", ModList::UIScript_LoadMods); UIScript::Add("LoadMods", ModList::UIScript_LoadMods);
UIScript::Add("RunMod", ModList::UIScript_RunMod); UIScript::Add("RunMod", ModList::UIScript_RunMod);
UIScript::Add("ClearMods", ModList::UIScript_ClearMods); UIScript::Add("ClearMods", ModList::UIScript_ClearMods);
UIFeeder::Add(9.0f, ModList::GetItemCount, ModList::GetItemText, ModList::Select); UIFeeder::Add(9.0f, ModList::GetItemCount, ModList::GetItemText, ModList::Select);
} }
ModList::~ModList() ModList::~ModList()
{ {
ModList::Mods.clear(); ModList::Mods.clear();
} }
} }

View File

@ -1,28 +1,28 @@
namespace Components namespace Components
{ {
class ModList : public Component class ModList : public Component
{ {
public: public:
ModList(); ModList();
~ModList(); ~ModList();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "ModList"; }; const char* getName() { return "ModList"; };
#endif #endif
static void RunMod(std::string mod); static void RunMod(std::string mod);
private: private:
static std::vector<std::string> Mods; static std::vector<std::string> Mods;
static unsigned int CurrentMod; static unsigned int CurrentMod;
static bool HasMod(std::string modName); static bool HasMod(std::string modName);
static unsigned int GetItemCount(); static unsigned int GetItemCount();
static const char* GetItemText(unsigned int index, int column); static const char* GetItemText(unsigned int index, int column);
static void Select(unsigned int index); static void Select(unsigned int index);
static void UIScript_LoadMods(UIScript::Token); static void UIScript_LoadMods(UIScript::Token);
static void UIScript_RunMod(UIScript::Token); static void UIScript_RunMod(UIScript::Token);
static void UIScript_ClearMods(UIScript::Token); static void UIScript_ClearMods(UIScript::Token);
}; };
} }

View File

@ -1,35 +1,35 @@
namespace Components namespace Components
{ {
class ModelSurfs : public Component class ModelSurfs : public Component
{ {
public: public:
ModelSurfs(); ModelSurfs();
~ModelSurfs(); ~ModelSurfs();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "ModelSurfs"; }; const char* getName() { return "ModelSurfs"; };
#endif #endif
private: private:
static std::unordered_map<void*, IUnknown*> BufferMap; static std::unordered_map<void*, IUnknown*> BufferMap;
static std::unordered_map<std::string, Game::CModelAllocData*> AllocMap; static std::unordered_map<std::string, Game::CModelAllocData*> AllocMap;
static void ReleaseModelSurf(Game::XAssetHeader header); static void ReleaseModelSurf(Game::XAssetHeader header);
static void BeginRecover(); static void BeginRecover();
static void EndRecover(); static void EndRecover();
static IUnknown* GetBuffer(void* buffer); static IUnknown* GetBuffer(void* buffer);
static void SetBuffer(char streamHandle, void* buffer, IUnknown** bufferOut, int* offsetOut); static void SetBuffer(char streamHandle, void* buffer, IUnknown** bufferOut, int* offsetOut);
static void CreateBuffers(Game::XModelSurfs* surfs); static void CreateBuffers(Game::XModelSurfs* surfs);
static Game::XModelSurfs* LoadXModelSurfaces(std::string name); static Game::XModelSurfs* LoadXModelSurfaces(std::string name);
static bool LoadSurfaces(Game::XModel* model); static bool LoadSurfaces(Game::XModel* model);
static void XModelSurfsFixup(Game::XModel* model); static void XModelSurfsFixup(Game::XModel* model);
static void GetIndexBaseStub(); static void GetIndexBaseStub();
static void GetIndexBufferStub(); static void GetIndexBufferStub();
static void GetIndexBufferStub2(); static void GetIndexBufferStub2();
static void GetVertexBufferStub(); static void GetVertexBufferStub();
}; };
} }

View File

@ -1,47 +1,47 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::unordered_map<std::string, const char*> MusicalTalent::SoundAliasList; std::unordered_map<std::string, const char*> MusicalTalent::SoundAliasList;
void MusicalTalent::Replace(std::string sound, const char* file) void MusicalTalent::Replace(std::string sound, const char* file)
{ {
MusicalTalent::SoundAliasList[Utils::String::ToLower(sound)] = file; MusicalTalent::SoundAliasList[Utils::String::ToLower(sound)] = file;
} }
Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename) Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename)
{ {
Game::XAssetHeader header = { 0 }; Game::XAssetHeader header = { 0 };
if (MusicalTalent::SoundAliasList.find(Utils::String::ToLower(filename)) != MusicalTalent::SoundAliasList.end()) if (MusicalTalent::SoundAliasList.find(Utils::String::ToLower(filename)) != MusicalTalent::SoundAliasList.end())
{ {
Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).sound; Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).sound;
if (aliases) if (aliases)
{ {
if (aliases->head->soundFile->type == 2) if (aliases->head->soundFile->type == 2)
{ {
aliases->head->soundFile->data.stream.name = MusicalTalent::SoundAliasList[Utils::String::ToLower(filename)]; aliases->head->soundFile->data.stream.name = MusicalTalent::SoundAliasList[Utils::String::ToLower(filename)];
} }
header.sound = aliases; header.sound = aliases;
} }
} }
return header; return header;
} }
MusicalTalent::MusicalTalent() MusicalTalent::MusicalTalent()
{ {
if (ZoneBuilder::IsEnabled()) return; if (ZoneBuilder::IsEnabled()) return;
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases); AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases);
MusicalTalent::Replace("music_mainmenu_mp", "hz_t_menumusic.mp3"); MusicalTalent::Replace("music_mainmenu_mp", "hz_t_menumusic.mp3");
} }
MusicalTalent::~MusicalTalent() MusicalTalent::~MusicalTalent()
{ {
MusicalTalent::SoundAliasList.clear(); MusicalTalent::SoundAliasList.clear();
} }
} }

View File

@ -1,19 +1,19 @@
namespace Components namespace Components
{ {
class MusicalTalent : public Component class MusicalTalent : public Component
{ {
public: public:
MusicalTalent(); MusicalTalent();
~MusicalTalent(); ~MusicalTalent();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "MusicalTalent"; }; const char* getName() { return "MusicalTalent"; };
#endif #endif
static void Replace(std::string sound, const char* file); static void Replace(std::string sound, const char* file);
private: private:
static std::unordered_map<std::string, const char*> SoundAliasList; static std::unordered_map<std::string, const char*> SoundAliasList;
static Game::XAssetHeader ModifyAliases(Game::XAssetType type, std::string filename); static Game::XAssetHeader ModifyAliases(Game::XAssetType type, std::string filename);
}; };
} }

View File

@ -1,378 +1,378 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::string Network::SelectedPacket; std::string Network::SelectedPacket;
Utils::Signal<Network::CallbackRaw> Network::StartupSignal; Utils::Signal<Network::CallbackRaw> Network::StartupSignal;
std::map<std::string, Utils::Slot<Network::Callback>> Network::PacketHandlers; std::map<std::string, Utils::Slot<Network::Callback>> Network::PacketHandlers;
Network::Address::Address(std::string addrString) Network::Address::Address(std::string addrString)
{ {
Game::NET_StringToAdr(addrString.data(), &this->address); Game::NET_StringToAdr(addrString.data(), &this->address);
} }
Network::Address::Address(sockaddr* addr) Network::Address::Address(sockaddr* addr)
{ {
Game::SockadrToNetadr(addr, &this->address); Game::SockadrToNetadr(addr, &this->address);
} }
bool Network::Address::operator==(const Network::Address &obj) bool Network::Address::operator==(const Network::Address &obj)
{ {
return Game::NET_CompareAdr(this->address, obj.address); return Game::NET_CompareAdr(this->address, obj.address);
} }
void Network::Address::setPort(unsigned short port) void Network::Address::setPort(unsigned short port)
{ {
this->address.port = htons(port); this->address.port = htons(port);
} }
unsigned short Network::Address::getPort() unsigned short Network::Address::getPort()
{ {
return ntohs(this->address.port); return ntohs(this->address.port);
} }
void Network::Address::setIP(DWORD ip) void Network::Address::setIP(DWORD ip)
{ {
this->address.ip.full = ip; this->address.ip.full = ip;
} }
void Network::Address::setIP(Game::netIP_t ip) void Network::Address::setIP(Game::netIP_t ip)
{ {
this->address.ip = ip; this->address.ip = ip;
} }
Game::netIP_t Network::Address::getIP() Game::netIP_t Network::Address::getIP()
{ {
return this->address.ip; return this->address.ip;
} }
void Network::Address::setType(Game::netadrtype_t type) void Network::Address::setType(Game::netadrtype_t type)
{ {
this->address.type = type; this->address.type = type;
} }
Game::netadrtype_t Network::Address::getType() Game::netadrtype_t Network::Address::getType()
{ {
return this->address.type; return this->address.type;
} }
sockaddr Network::Address::getSockAddr() sockaddr Network::Address::getSockAddr()
{ {
sockaddr addr; sockaddr addr;
this->toSockAddr(&addr); this->toSockAddr(&addr);
return addr; return addr;
} }
void Network::Address::toSockAddr(sockaddr* addr) void Network::Address::toSockAddr(sockaddr* addr)
{ {
if (addr) if (addr)
{ {
Game::NetadrToSockadr(&this->address, addr); Game::NetadrToSockadr(&this->address, addr);
} }
} }
void Network::Address::toSockAddr(sockaddr_in* addr) void Network::Address::toSockAddr(sockaddr_in* addr)
{ {
this->toSockAddr(reinterpret_cast<sockaddr*>(addr)); this->toSockAddr(reinterpret_cast<sockaddr*>(addr));
} }
Game::netadr_t* Network::Address::get() Game::netadr_t* Network::Address::get()
{ {
return &this->address; return &this->address;
} }
const char* Network::Address::getCString() const char* Network::Address::getCString()
{ {
return Game::NET_AdrToString(this->address); return Game::NET_AdrToString(this->address);
} }
std::string Network::Address::getString() std::string Network::Address::getString()
{ {
return this->getCString(); return this->getCString();
} }
bool Network::Address::isLocal() bool Network::Address::isLocal()
{ {
// According to: https://en.wikipedia.org/wiki/Private_network // According to: https://en.wikipedia.org/wiki/Private_network
// 10.X.X.X // 10.X.X.X
if (this->getIP().bytes[0] == 10) return true; if (this->getIP().bytes[0] == 10) return true;
// 192.168.X.X // 192.168.X.X
if (this->getIP().bytes[0] == 192 && this->getIP().bytes[1] == 168) return true; if (this->getIP().bytes[0] == 192 && this->getIP().bytes[1] == 168) return true;
// 172.16.X.X - 172.31.X.X // 172.16.X.X - 172.31.X.X
if (this->getIP().bytes[0] == 172 && (this->getIP().bytes[1] >= 16) && (this->getIP().bytes[1] < 32)) return true; if (this->getIP().bytes[0] == 172 && (this->getIP().bytes[1] >= 16) && (this->getIP().bytes[1] < 32)) return true;
// 127.0.0.1 // 127.0.0.1
if (this->getIP().full == 0x0100007F) return true; if (this->getIP().full == 0x0100007F) return true;
// TODO: Maybe check for matching localIPs and subnet mask // TODO: Maybe check for matching localIPs and subnet mask
return false; return false;
} }
bool Network::Address::isSelf() bool Network::Address::isSelf()
{ {
if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback if (Game::NET_IsLocalAddress(this->address)) return true; // Loopback
if (this->getPort() != (Dvar::Var("net_port").get<int>() & 0xFFFF)) return false; // Port not equal if (this->getPort() != (Dvar::Var("net_port").get<int>() & 0xFFFF)) return false; // Port not equal
for (int i = 0; i < *Game::numIP; ++i) for (int i = 0; i < *Game::numIP; ++i)
{ {
if (this->getIP().full == Game::localIP[i].full) if (this->getIP().full == Game::localIP[i].full)
{ {
return true; return true;
} }
} }
return false; return false;
} }
bool Network::Address::isLoopback() bool Network::Address::isLoopback()
{ {
if (this->getIP().full == 0x100007f) // 127.0.0.1 if (this->getIP().full == 0x100007f) // 127.0.0.1
{ {
return true; return true;
} }
return Game::NET_IsLocalAddress(this->address); return Game::NET_IsLocalAddress(this->address);
} }
bool Network::Address::isValid() bool Network::Address::isValid()
{ {
return (this->getType() != Game::netadrtype_t::NA_BAD); return (this->getType() != Game::netadrtype_t::NA_BAD);
} }
void Network::Address::serialize(Proto::Network::Address* protoAddress) void Network::Address::serialize(Proto::Network::Address* protoAddress)
{ {
protoAddress->set_ip(this->getIP().full); protoAddress->set_ip(this->getIP().full);
protoAddress->set_port(this->getPort() & 0xFFFF); protoAddress->set_port(this->getPort() & 0xFFFF);
} }
void Network::Address::deserialize(const Proto::Network::Address& protoAddress) void Network::Address::deserialize(const Proto::Network::Address& protoAddress)
{ {
this->setIP(protoAddress.ip()); this->setIP(protoAddress.ip());
this->setPort(static_cast<uint16_t>(protoAddress.port())); this->setPort(static_cast<uint16_t>(protoAddress.port()));
this->setType(Game::netadrtype_t::NA_IP); this->setType(Game::netadrtype_t::NA_IP);
} }
void Network::Handle(std::string packet, Utils::Slot<Network::Callback> callback) void Network::Handle(std::string packet, Utils::Slot<Network::Callback> callback)
{ {
Network::PacketHandlers[Utils::String::ToLower(packet)] = callback; Network::PacketHandlers[Utils::String::ToLower(packet)] = callback;
} }
void Network::OnStart(Utils::Slot<Network::CallbackRaw> callback) void Network::OnStart(Utils::Slot<Network::CallbackRaw> callback)
{ {
Network::StartupSignal.connect(callback); Network::StartupSignal.connect(callback);
} }
void Network::Send(Game::netsrc_t type, Network::Address target, std::string data) void Network::Send(Game::netsrc_t type, Network::Address target, std::string data)
{ {
// NET_OutOfBandPrint only supports non-binary data! // NET_OutOfBandPrint only supports non-binary data!
//Game::NET_OutOfBandPrint(type, *target.Get(), data.data()); //Game::NET_OutOfBandPrint(type, *target.Get(), data.data());
std::string rawData; std::string rawData;
rawData.append("\xFF\xFF\xFF\xFF", 4); rawData.append("\xFF\xFF\xFF\xFF", 4);
rawData.append(data); rawData.append(data);
//rawData.append("\0", 1); //rawData.append("\0", 1);
Network::SendRaw(type, target, rawData); Network::SendRaw(type, target, rawData);
} }
void Network::Send(Network::Address target, std::string data) void Network::Send(Network::Address target, std::string data)
{ {
Network::Send(Game::netsrc_t::NS_CLIENT, target, data); Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
} }
void Network::SendRaw(Game::netsrc_t type, Network::Address target, std::string data) void Network::SendRaw(Game::netsrc_t type, Network::Address target, std::string data)
{ {
// NET_OutOfBandData doesn't seem to work properly // NET_OutOfBandData doesn't seem to work properly
//Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size()); //Game::NET_OutOfBandData(type, *target.Get(), data.data(), data.size());
Game::Sys_SendPacket(type, data.size(), data.data(), *target.get()); Game::Sys_SendPacket(type, data.size(), data.data(), *target.get());
} }
void Network::SendRaw(Network::Address target, std::string data) void Network::SendRaw(Network::Address target, std::string data)
{ {
Network::SendRaw(Game::netsrc_t::NS_CLIENT, target, data); Network::SendRaw(Game::netsrc_t::NS_CLIENT, target, data);
} }
void Network::SendCommand(Game::netsrc_t type, Network::Address target, std::string command, std::string data) void Network::SendCommand(Game::netsrc_t type, Network::Address target, std::string command, std::string data)
{ {
// Use space as separator (possible separators are '\n', ' '). // Use space as separator (possible separators are '\n', ' ').
// Though, our handler only needs exactly 1 char as separator and doesn't which char it is // Though, our handler only needs exactly 1 char as separator and doesn't which char it is
std::string packet; std::string packet;
packet.append(command); packet.append(command);
packet.append(" ", 1); packet.append(" ", 1);
packet.append(data); packet.append(data);
Network::Send(type, target, packet); Network::Send(type, target, packet);
} }
void Network::SendCommand(Network::Address target, std::string command, std::string data) void Network::SendCommand(Network::Address target, std::string command, std::string data)
{ {
Network::SendCommand(Game::netsrc_t::NS_CLIENT, target, command, data); Network::SendCommand(Game::netsrc_t::NS_CLIENT, target, command, data);
} }
void Network::Broadcast(unsigned short port, std::string data) void Network::Broadcast(unsigned short port, std::string data)
{ {
Address target; Address target;
target.setPort(port); target.setPort(port);
target.setIP(INADDR_BROADCAST); target.setIP(INADDR_BROADCAST);
target.setType(Game::netadrtype_t::NA_BROADCAST); target.setType(Game::netadrtype_t::NA_BROADCAST);
Network::Send(Game::netsrc_t::NS_CLIENT, target, data); Network::Send(Game::netsrc_t::NS_CLIENT, target, data);
} }
void Network::BroadcastRange(unsigned int min, unsigned int max, std::string data) void Network::BroadcastRange(unsigned int min, unsigned int max, std::string data)
{ {
for (unsigned int i = min; i < max; ++i) for (unsigned int i = min; i < max; ++i)
{ {
Network::Broadcast(static_cast<unsigned short>(i & 0xFFFF), data); Network::Broadcast(static_cast<unsigned short>(i & 0xFFFF), data);
} }
} }
void Network::BroadcastAll(std::string data) void Network::BroadcastAll(std::string data)
{ {
Network::BroadcastRange(100, 65536, data); Network::BroadcastRange(100, 65536, data);
} }
int Network::PacketInterceptionHandler(const char* packet) int Network::PacketInterceptionHandler(const char* packet)
{ {
// Packet rate limit. // Packet rate limit.
static uint32_t packets = 0; static uint32_t packets = 0;
static int lastClean = 0; static int lastClean = 0;
if ((Game::Sys_Milliseconds() - lastClean) > 1'000) if ((Game::Sys_Milliseconds() - lastClean) > 1'000)
{ {
packets = 0; packets = 0;
lastClean = Game::Sys_Milliseconds(); lastClean = Game::Sys_Milliseconds();
} }
if ((++packets) > NETWORK_MAX_PACKETS_PER_SECOND) if ((++packets) > NETWORK_MAX_PACKETS_PER_SECOND)
{ {
return 1; return 1;
} }
std::string packetCommand = packet; std::string packetCommand = packet;
auto pos = packetCommand.find_first_of("\\\n "); auto pos = packetCommand.find_first_of("\\\n ");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
packetCommand = packetCommand.substr(0, pos); packetCommand = packetCommand.substr(0, pos);
} }
packetCommand = Utils::String::ToLower(packetCommand); packetCommand = Utils::String::ToLower(packetCommand);
// Check if custom handler exists // Check if custom handler exists
for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); ++i) for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); ++i)
{ {
if (Utils::String::ToLower(i->first) == packetCommand) if (Utils::String::ToLower(i->first) == packetCommand)
{ {
Network::SelectedPacket = i->first; Network::SelectedPacket = i->first;
return 0; return 0;
} }
} }
// No interception // No interception
return 1; return 1;
} }
void Network::DeployPacket(Game::netadr_t* from, Game::msg_t* msg) void Network::DeployPacket(Game::netadr_t* from, Game::msg_t* msg)
{ {
if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end()) if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end())
{ {
std::string data; std::string data;
size_t offset = Network::SelectedPacket.size() + 4 + 1; size_t offset = Network::SelectedPacket.size() + 4 + 1;
if (static_cast<size_t>(msg->cursize) > offset) if (static_cast<size_t>(msg->cursize) > offset)
{ {
data.append(msg->data + offset, msg->cursize - offset); data.append(msg->data + offset, msg->cursize - offset);
} }
// Remove trailing 0x00 byte // Remove trailing 0x00 byte
// Actually, don't remove it, it might be part of the packet. Send correctly formatted packets instead! // Actually, don't remove it, it might be part of the packet. Send correctly formatted packets instead!
//if (data.size() && !data[data.size() - 1]) data.pop_back(); //if (data.size() && !data[data.size() - 1]) data.pop_back();
Network::PacketHandlers[Network::SelectedPacket](from, data); Network::PacketHandlers[Network::SelectedPacket](from, data);
} }
else else
{ {
Logger::Print("Error: Network packet intercepted, but handler is missing!\n"); Logger::Print("Error: Network packet intercepted, but handler is missing!\n");
} }
} }
void Network::NetworkStart() void Network::NetworkStart()
{ {
Network::StartupSignal(); Network::StartupSignal();
} }
__declspec(naked) void Network::NetworkStartStub() __declspec(naked) void Network::NetworkStartStub()
{ {
__asm __asm
{ {
mov eax, 64D900h mov eax, 64D900h
call eax call eax
jmp Network::NetworkStart jmp Network::NetworkStart
} }
} }
__declspec(naked) void Network::DeployPacketStub() __declspec(naked) void Network::DeployPacketStub()
{ {
__asm __asm
{ {
lea eax, [esp + 0C54h] lea eax, [esp + 0C54h]
push ebp // Command push ebp // Command
push eax // Address pointer push eax // Address pointer
call Network::DeployPacket call Network::DeployPacket
add esp, 8h add esp, 8h
mov al, 1 mov al, 1
pop edi pop edi
pop esi pop esi
pop ebp pop ebp
pop ebx pop ebx
add esp, 0C40h add esp, 0C40h
retn retn
} }
} }
__declspec(naked) void Network::PacketErrorCheck() __declspec(naked) void Network::PacketErrorCheck()
{ {
__asm __asm
{ {
cmp eax, 2746h cmp eax, 2746h
jz returnIgnore jz returnIgnore
cmp eax, WSAENETRESET cmp eax, WSAENETRESET
jz returnIgnore jz returnIgnore
push 465325h push 465325h
retn retn
returnIgnore: returnIgnore:
push 4654C6h push 4654C6h
retn retn
} }
} }
Network::Network() Network::Network()
{ {
AssertSize(Game::netadr_t, 20); AssertSize(Game::netadr_t, 20);
// maximum size in NET_OutOfBandPrint // maximum size in NET_OutOfBandPrint
Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC); Utils::Hook::Set<DWORD>(0x4AEF08, 0x1FFFC);
Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC); Utils::Hook::Set<DWORD>(0x4AEFA3, 0x1FFFC);
// increase max port binding attempts from 10 to 100 // increase max port binding attempts from 10 to 100
Utils::Hook::Set<BYTE>(0x4FD48A, 100); Utils::Hook::Set<BYTE>(0x4FD48A, 100);
// increase cl_maxpackets limit // increase cl_maxpackets limit
Utils::Hook::Set<BYTE>(0x4050A1, 125); Utils::Hook::Set<BYTE>(0x4050A1, 125);
// Parse port as short in Net_AddrToString // Parse port as short in Net_AddrToString
Utils::Hook::Set<char*>(0x4698E3, "%u.%u.%u.%u:%hu"); Utils::Hook::Set<char*>(0x4698E3, "%u.%u.%u.%u:%hu");
// Install startup handler // Install startup handler
Utils::Hook(0x4FD4D4, Network::NetworkStartStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4FD4D4, Network::NetworkStartStub, HOOK_JUMP).install()->quick();
// Install interception handler // Install interception handler
Utils::Hook(0x5AA709, Network::PacketInterceptionHandler, HOOK_CALL).install()->quick(); Utils::Hook(0x5AA709, Network::PacketInterceptionHandler, HOOK_CALL).install()->quick();
// Prevent recvfrom error spam // Prevent recvfrom error spam
Utils::Hook(0x46531A, Network::PacketErrorCheck, HOOK_JUMP).install()->quick(); Utils::Hook(0x46531A, Network::PacketErrorCheck, HOOK_JUMP).install()->quick();
// Install packet deploy hook // Install packet deploy hook
Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub); Utils::Hook::RedirectJump(0x5AA713, Network::DeployPacketStub);
Network::Handle("resolveAddress", [] (Address address, std::string data) Network::Handle("resolveAddress", [] (Address address, std::string data)
{ {
Network::SendRaw(address, address.getString()); Network::SendRaw(address, address.getString());
}); });
} }
Network::~Network() Network::~Network()
{ {
Network::SelectedPacket.clear(); Network::SelectedPacket.clear();
Network::PacketHandlers.clear(); Network::PacketHandlers.clear();
Network::StartupSignal.clear(); Network::StartupSignal.clear();
} }
} }

View File

@ -1,96 +1,96 @@
#define NETWORK_MAX_PACKETS_PER_SECOND 100'000 #define NETWORK_MAX_PACKETS_PER_SECOND 100'000
namespace Components namespace Components
{ {
class Network : public Component class Network : public Component
{ {
public: public:
class Address class Address
{ {
public: public:
Address() { setType(Game::netadrtype_t::NA_BAD); }; Address() { setType(Game::netadrtype_t::NA_BAD); };
Address(std::string addrString); Address(std::string addrString);
Address(sockaddr* addr); Address(sockaddr* addr);
Address(sockaddr addr) : Address(&addr) {} Address(sockaddr addr) : Address(&addr) {}
Address(sockaddr_in addr) : Address(&addr) {} Address(sockaddr_in addr) : Address(&addr) {}
Address(sockaddr_in* addr) : Address(reinterpret_cast<sockaddr*>(addr)) {} Address(sockaddr_in* addr) : Address(reinterpret_cast<sockaddr*>(addr)) {}
Address(Game::netadr_t addr) : address(addr) {} Address(Game::netadr_t addr) : address(addr) {}
Address(Game::netadr_t* addr) : Address(*addr) {} Address(Game::netadr_t* addr) : Address(*addr) {}
Address(const Address& obj) : address(obj.address) {}; Address(const Address& obj) : address(obj.address) {};
Address(const Proto::Network::Address& addr) { this->deserialize(addr); }; Address(const Proto::Network::Address& addr) { this->deserialize(addr); };
bool operator!=(const Address &obj) { return !(*this == obj); }; bool operator!=(const Address &obj) { return !(*this == obj); };
bool operator==(const Address &obj); bool operator==(const Address &obj);
void setPort(unsigned short port); void setPort(unsigned short port);
unsigned short getPort(); unsigned short getPort();
void setIP(DWORD ip); void setIP(DWORD ip);
void setIP(Game::netIP_t ip); void setIP(Game::netIP_t ip);
Game::netIP_t getIP(); Game::netIP_t getIP();
void setType(Game::netadrtype_t type); void setType(Game::netadrtype_t type);
Game::netadrtype_t getType(); Game::netadrtype_t getType();
sockaddr getSockAddr(); sockaddr getSockAddr();
void toSockAddr(sockaddr* addr); void toSockAddr(sockaddr* addr);
void toSockAddr(sockaddr_in* addr); void toSockAddr(sockaddr_in* addr);
Game::netadr_t* get(); Game::netadr_t* get();
const char* getCString(); const char* getCString();
std::string getString(); std::string getString();
bool isLocal(); bool isLocal();
bool isSelf(); bool isSelf();
bool isValid(); bool isValid();
bool isLoopback(); bool isLoopback();
void serialize(Proto::Network::Address* protoAddress); void serialize(Proto::Network::Address* protoAddress);
void deserialize(const Proto::Network::Address& protoAddress); void deserialize(const Proto::Network::Address& protoAddress);
private: private:
Game::netadr_t address; Game::netadr_t address;
}; };
typedef void(Callback)(Address address, std::string data); typedef void(Callback)(Address address, std::string data);
typedef void(CallbackRaw)(); typedef void(CallbackRaw)();
Network(); Network();
~Network(); ~Network();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Network"; }; const char* getName() { return "Network"; };
#endif #endif
static void Handle(std::string packet, Utils::Slot<Callback> callback); static void Handle(std::string packet, Utils::Slot<Callback> callback);
static void OnStart(Utils::Slot<CallbackRaw> callback); static void OnStart(Utils::Slot<CallbackRaw> callback);
// Send quake-styled binary data // Send quake-styled binary data
static void Send(Address target, std::string data); static void Send(Address target, std::string data);
static void Send(Game::netsrc_t type, Address target, std::string data); static void Send(Game::netsrc_t type, Address target, std::string data);
// Allows sending raw data without quake header // Allows sending raw data without quake header
static void SendRaw(Address target, std::string data); static void SendRaw(Address target, std::string data);
static void SendRaw(Game::netsrc_t type, Address target, std::string data); static void SendRaw(Game::netsrc_t type, Address target, std::string data);
// Send quake-style command using binary data // Send quake-style command using binary data
static void SendCommand(Address target, std::string command, std::string data = ""); static void SendCommand(Address target, std::string command, std::string data = "");
static void SendCommand(Game::netsrc_t type, Address target, std::string command, std::string data = ""); static void SendCommand(Game::netsrc_t type, Address target, std::string command, std::string data = "");
static void Broadcast(unsigned short port, std::string data); static void Broadcast(unsigned short port, std::string data);
static void BroadcastRange(unsigned int min, unsigned int max, std::string data); static void BroadcastRange(unsigned int min, unsigned int max, std::string data);
static void BroadcastAll(std::string data); static void BroadcastAll(std::string data);
private: private:
static std::string SelectedPacket; static std::string SelectedPacket;
static Utils::Signal<CallbackRaw> StartupSignal; static Utils::Signal<CallbackRaw> StartupSignal;
static std::map<std::string, Utils::Slot<Callback>> PacketHandlers; static std::map<std::string, Utils::Slot<Callback>> PacketHandlers;
static int PacketInterceptionHandler(const char* packet); static int PacketInterceptionHandler(const char* packet);
static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg); static void DeployPacket(Game::netadr_t* from, Game::msg_t* msg);
static void DeployPacketStub(); static void DeployPacketStub();
static void NetworkStart(); static void NetworkStart();
static void NetworkStartStub(); static void NetworkStartStub();
static void PacketErrorCheck(); static void PacketErrorCheck();
}; };
} }

View File

@ -1,199 +1,199 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
#define NEWS_MOTD_DEFUALT "Welcome to IW4x Multiplayer!" #define NEWS_MOTD_DEFUALT "Welcome to IW4x Multiplayer!"
namespace Components namespace Components
{ {
bool News::Terminate; bool News::Terminate;
std::thread News::Thread; std::thread News::Thread;
bool News::unitTest() bool News::unitTest()
{ {
bool result = true; bool result = true;
if (News::Thread.joinable()) if (News::Thread.joinable())
{ {
Logger::Print("Awaiting thread termination...\n"); Logger::Print("Awaiting thread termination...\n");
News::Thread.join(); News::Thread.join();
if (!strlen(Localization::Get("MPUI_CHANGELOG_TEXT")) || Localization::Get("MPUI_CHANGELOG_TEXT") == "Loading..."s) if (!strlen(Localization::Get("MPUI_CHANGELOG_TEXT")) || Localization::Get("MPUI_CHANGELOG_TEXT") == "Loading..."s)
{ {
Logger::Print("Failed to fetch changelog!\n"); Logger::Print("Failed to fetch changelog!\n");
result = false; result = false;
} }
else else
{ {
Logger::Print("Successfully fetched changelog.\n"); Logger::Print("Successfully fetched changelog.\n");
} }
if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFUALT)) if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFUALT))
{ {
Logger::Print("Failed to fetch motd!\n"); Logger::Print("Failed to fetch motd!\n");
result = false; result = false;
} }
else else
{ {
Logger::Print("Successfully fetched motd.\n"); Logger::Print("Successfully fetched motd.\n");
} }
} }
return result; return result;
} }
void News::ExitProcessStub(unsigned int exitCode) void News::ExitProcessStub(unsigned int exitCode)
{ {
std::this_thread::sleep_for(10ms); std::this_thread::sleep_for(10ms);
STARTUPINFOA sInfo; STARTUPINFOA sInfo;
PROCESS_INFORMATION pInfo; PROCESS_INFORMATION pInfo;
ZeroMemory(&sInfo, sizeof(sInfo)); ZeroMemory(&sInfo, sizeof(sInfo));
ZeroMemory(&pInfo, sizeof(pInfo)); ZeroMemory(&pInfo, sizeof(pInfo));
sInfo.cb = sizeof(sInfo); sInfo.cb = sizeof(sInfo);
CreateProcessA("updater.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &sInfo, &pInfo); CreateProcessA("updater.exe", NULL, NULL, NULL, false, NULL, NULL, NULL, &sInfo, &pInfo);
if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE) if (pInfo.hThread && pInfo.hThread != INVALID_HANDLE_VALUE)
{ {
CloseHandle(pInfo.hThread); CloseHandle(pInfo.hThread);
} }
if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE) if (pInfo.hProcess && pInfo.hProcess != INVALID_HANDLE_VALUE)
{ {
CloseHandle(pInfo.hProcess); CloseHandle(pInfo.hProcess);
} }
TerminateProcess(GetCurrentProcess(), exitCode); TerminateProcess(GetCurrentProcess(), exitCode);
} }
const char* News::GetNewsText() const char* News::GetNewsText()
{ {
return Localization::Get("MPUI_MOTD_TEXT"); return Localization::Get("MPUI_MOTD_TEXT");
} }
void News::CheckForUpdate() void News::CheckForUpdate()
{ {
std::string caches = Utils::Cache::GetFile("/iw4/caches.xml"); std::string caches = Utils::Cache::GetFile("/iw4/caches.xml");
if (!caches.empty()) if (!caches.empty())
{ {
std::string str = "<Cache ID=\"iw4x\" Version=\""; std::string str = "<Cache ID=\"iw4x\" Version=\"";
auto pos = caches.find(str); auto pos = caches.find(str);
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
caches = caches.substr(pos + str.size()); caches = caches.substr(pos + str.size());
pos = caches.find_first_of("\""); pos = caches.find_first_of("\"");
if (pos != std::string::npos) if (pos != std::string::npos)
{ {
caches = caches.substr(0, pos); caches = caches.substr(0, pos);
int version = atoi(caches.data()); int version = atoi(caches.data());
Dvar::Var("cl_updateversion").get<Game::dvar_t*>()->current.integer = version; Dvar::Var("cl_updateversion").get<Game::dvar_t*>()->current.integer = version;
Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean = (version > REVISION); Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean = (version > REVISION);
} }
} }
} }
} }
News::News() News::News()
{ {
if (ZoneBuilder::IsEnabled()) return; // Maybe also dedi? if (ZoneBuilder::IsEnabled()) return; // Maybe also dedi?
Dvar::Register<int>("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_FLAG_WRITEPROTECTED, "Current version number."); Dvar::Register<int>("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_FLAG_WRITEPROTECTED, "Current version number.");
Dvar::Register<int>("cl_updateversion", 0, 0, -1, Game::DVAR_FLAG_WRITEPROTECTED, "New version number."); Dvar::Register<int>("cl_updateversion", 0, 0, -1, Game::DVAR_FLAG_WRITEPROTECTED, "New version number.");
Dvar::Register<bool>("cl_updateavailable", 0, Game::DVAR_FLAG_WRITEPROTECTED, "New update is available."); Dvar::Register<bool>("cl_updateavailable", 0, Game::DVAR_FLAG_WRITEPROTECTED, "New update is available.");
Localization::Set("MPUI_CHANGELOG_TEXT", "Loading..."); Localization::Set("MPUI_CHANGELOG_TEXT", "Loading...");
Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT); Localization::Set("MPUI_MOTD_TEXT", NEWS_MOTD_DEFUALT);
if (Utils::IO::FileExists("updater.exe")) if (Utils::IO::FileExists("updater.exe"))
{ {
remove("updater.exe"); remove("updater.exe");
} }
// make newsfeed (ticker) menu items not cut off based on safe area // make newsfeed (ticker) menu items not cut off based on safe area
Utils::Hook::Nop(0x63892D, 5); Utils::Hook::Nop(0x63892D, 5);
// hook for getting the news ticker string // hook for getting the news ticker string
Utils::Hook::Nop(0x6388BB, 2); // skip the "if (item->text[0] == '@')" localize check Utils::Hook::Nop(0x6388BB, 2); // skip the "if (item->text[0] == '@')" localize check
Utils::Hook(0x6388C1, News::GetNewsText, HOOK_CALL).install()->quick(); Utils::Hook(0x6388C1, News::GetNewsText, HOOK_CALL).install()->quick();
Command::Add("checkforupdate", [] (Command::Params*) Command::Add("checkforupdate", [] (Command::Params*)
{ {
News::CheckForUpdate(); News::CheckForUpdate();
}); });
Command::Add("getautoupdate", [] (Command::Params*) Command::Add("getautoupdate", [] (Command::Params*)
{ {
if (!Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean) return; if (!Dvar::Var("cl_updateavailable").get<Game::dvar_t*>()->current.boolean) return;
Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", "Downloading updater"); Localization::SetTemp("MENU_RECONNECTING_TO_PARTY", "Downloading updater");
Command::Execute("openmenu popup_reconnectingtoparty", true); Command::Execute("openmenu popup_reconnectingtoparty", true);
// Run the updater on shutdown // Run the updater on shutdown
Utils::Hook::Set(0x6D72A0, News::ExitProcessStub); Utils::Hook::Set(0x6D72A0, News::ExitProcessStub);
std::thread([] () std::thread([] ()
{ {
std::string data = Utils::Cache::GetFile("/iw4/updater.exe"); std::string data = Utils::Cache::GetFile("/iw4/updater.exe");
if (data.empty()) if (data.empty())
{ {
Localization::ClearTemp(); Localization::ClearTemp();
Command::Execute("closemenu popup_reconnectingtoparty", false); Command::Execute("closemenu popup_reconnectingtoparty", false);
Game::MessageBox("Failed to download the updater!", "Error"); Game::MessageBox("Failed to download the updater!", "Error");
} }
else else
{ {
Console::SetSkipShutdown(); Console::SetSkipShutdown();
Utils::IO::WriteFile("updater.exe", data); Utils::IO::WriteFile("updater.exe", data);
Command::Execute("wait 300; quit;", false); Command::Execute("wait 300; quit;", false);
} }
}).detach(); }).detach();
}); });
if (!Utils::IsWineEnvironment()) if (!Utils::IsWineEnvironment())
{ {
News::Terminate = false; News::Terminate = false;
News::Thread = std::thread([] () News::Thread = std::thread([] ()
{ {
Localization::Set("MPUI_CHANGELOG_TEXT", Utils::Cache::GetFile("/iw4/changelog.txt")); Localization::Set("MPUI_CHANGELOG_TEXT", Utils::Cache::GetFile("/iw4/changelog.txt"));
std::string data = Utils::Cache::GetFile("/iw4/motd.txt"); std::string data = Utils::Cache::GetFile("/iw4/motd.txt");
if (!data.empty()) if (!data.empty())
{ {
Localization::Set("MPUI_MOTD_TEXT", data); Localization::Set("MPUI_MOTD_TEXT", data);
} }
if (!Loader::PerformingUnitTests()) if (!Loader::PerformingUnitTests())
{ {
while (!News::Terminate) while (!News::Terminate)
{ {
News::CheckForUpdate(); News::CheckForUpdate();
// Sleep for 3 minutes // Sleep for 3 minutes
for (int i = 0; i < 180 && !News::Terminate; ++i) for (int i = 0; i < 180 && !News::Terminate; ++i)
{ {
std::this_thread::sleep_for(1s); std::this_thread::sleep_for(1s);
} }
} }
} }
}); });
} }
} }
News::~News() News::~News()
{ {
News::Terminate = true; News::Terminate = true;
if (News::Thread.joinable()) if (News::Thread.joinable())
{ {
News::Thread.join(); News::Thread.join();
} }
} }
} }

View File

@ -1,24 +1,24 @@
namespace Components namespace Components
{ {
class News : public Component class News : public Component
{ {
public: public:
News(); News();
~News(); ~News();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "News"; }; const char* getName() { return "News"; };
#endif #endif
bool unitTest(); bool unitTest();
private: private:
static std::thread Thread; static std::thread Thread;
static bool Terminate; static bool Terminate;
static void CheckForUpdate(); static void CheckForUpdate();
static void ExitProcessStub(unsigned int exitCode); static void ExitProcessStub(unsigned int exitCode);
static const char* GetNewsText(); static const char* GetNewsText();
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +1,95 @@
#define NODE_QUERY_INTERVAL 1000 * 60 * 2 // Query nodelist from nodes evry 2 minutes #define NODE_QUERY_INTERVAL 1000 * 60 * 2 // Query nodelist from nodes evry 2 minutes
#define NODE_QUERY_TIMEOUT 1000 * 30 * 1 // Invalidate nodes after 30 seconds without query response #define NODE_QUERY_TIMEOUT 1000 * 30 * 1 // Invalidate nodes after 30 seconds without query response
#define NODE_INVALID_DELETE 1000 * 60 * 10 // Delete invalidated nodes after 10 minutes #define NODE_INVALID_DELETE 1000 * 60 * 10 // Delete invalidated nodes after 10 minutes
#define NODE_FRAME_QUERY_LIMIT 3 // Limit of nodes to be queried per frame #define NODE_FRAME_QUERY_LIMIT 3 // Limit of nodes to be queried per frame
#define NODE_FRAME_LOCK 60 // Limit of max frames per second #define NODE_FRAME_LOCK 60 // Limit of max frames per second
#define NODE_PACKET_LIMIT 111 // Send 111 nodes per synchronization packet #define NODE_PACKET_LIMIT 111 // Send 111 nodes per synchronization packet
#define NODE_STORE_INTERVAL 1000 * 60* 1 // Store nodes every minute #define NODE_STORE_INTERVAL 1000 * 60* 1 // Store nodes every minute
#define SESSION_TIMEOUT 1000 * 10 // 10 seconds session timeout #define SESSION_TIMEOUT 1000 * 10 // 10 seconds session timeout
#define NODE_VERSION 4 #define NODE_VERSION 4
namespace Components namespace Components
{ {
class Node : public Component class Node : public Component
{ {
public: public:
Node(); Node();
~Node(); ~Node();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Node"; }; const char* getName() { return "Node"; };
#endif #endif
bool unitTest(); bool unitTest();
static void SyncNodeList(); static void SyncNodeList();
static void AddNode(Network::Address address); static void AddNode(Network::Address address);
static unsigned int GetValidNodeCount(); static unsigned int GetValidNodeCount();
static void LoadNodeRemotePreset(); static void LoadNodeRemotePreset();
private: private:
enum EntryState enum EntryState
{ {
STATE_UNKNOWN, STATE_UNKNOWN,
STATE_NEGOTIATING, STATE_NEGOTIATING,
STATE_VALID, STATE_VALID,
STATE_INVALID, STATE_INVALID,
}; };
class NodeEntry class NodeEntry
{ {
public: public:
Network::Address address; Network::Address address;
std::string challenge; std::string challenge;
Utils::Cryptography::ECC::Key publicKey; Utils::Cryptography::ECC::Key publicKey;
EntryState state; EntryState state;
bool registered; // Do we consider this node as registered? bool registered; // Do we consider this node as registered?
int lastTime; // Last time we heard anything from the server itself int lastTime; // Last time we heard anything from the server itself
int lastHeard; // Last time we heard something of the server at all (refs form other nodes) int lastHeard; // Last time we heard something of the server at all (refs form other nodes)
int lastListQuery; // Last time we got the list of the node int lastListQuery; // Last time we got the list of the node
// This is only relevant for clients // This is only relevant for clients
bool isDedi; bool isDedi;
uint32_t protocol; uint32_t protocol;
uint32_t version; uint32_t version;
}; };
class ClientSession class ClientSession
{ {
public: public:
Network::Address address; Network::Address address;
std::string challenge; std::string challenge;
bool valid; bool valid;
//bool terminated; // Sessions can't explicitly be terminated, they can only timeout //bool terminated; // Sessions can't explicitly be terminated, they can only timeout
int lastTime; int lastTime;
}; };
static Utils::Cryptography::ECC::Key SignatureKey; static Utils::Cryptography::ECC::Key SignatureKey;
static std::recursive_mutex NodeMutex; static std::recursive_mutex NodeMutex;
static std::mutex SessionMutex; static std::mutex SessionMutex;
static std::vector<NodeEntry> Nodes; static std::vector<NodeEntry> Nodes;
static std::vector<ClientSession> Sessions; static std::vector<ClientSession> Sessions;
static void LoadNodes(); static void LoadNodes();
static void LoadNodePreset(); static void LoadNodePreset();
static void StoreNodes(bool force); static void StoreNodes(bool force);
static void PerformRegistration(Network::Address address); static void PerformRegistration(Network::Address address);
static void SendNodeList(Network::Address address); static void SendNodeList(Network::Address address);
static NodeEntry* FindNode(Network::Address address); static NodeEntry* FindNode(Network::Address address);
static ClientSession* FindSession(Network::Address address); static ClientSession* FindSession(Network::Address address);
static void DeleteInvalidNodes(); static void DeleteInvalidNodes();
static void DeleteInvalidSessions(); static void DeleteInvalidSessions();
static void FrameHandler(); static void FrameHandler();
static const char* GetStateName(EntryState state); static const char* GetStateName(EntryState state);
}; };
} }

View File

@ -1,459 +1,461 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Party::JoinContainer Party::Container; Party::JoinContainer Party::Container;
std::map<uint64_t, Network::Address> Party::LobbyMap; std::map<uint64_t, Network::Address> Party::LobbyMap;
SteamID Party::GenerateLobbyId() SteamID Party::GenerateLobbyId()
{ {
SteamID id; SteamID id;
id.AccountID = Game::Sys_Milliseconds(); id.AccountID = Game::Sys_Milliseconds();
id.Universe = 1; id.Universe = 1;
id.AccountType = 8; id.AccountType = 8;
id.AccountInstance = 0x40000; id.AccountInstance = 0x40000;
return id; return id;
} }
Network::Address Party::Target() Network::Address Party::Target()
{ {
return Party::Container.target; return Party::Container.target;
} }
void Party::Connect(Network::Address target) void Party::Connect(Network::Address target)
{ {
Node::AddNode(target); Node::AddNode(target);
Party::Container.valid = true; Party::Container.valid = true;
Party::Container.awaitingPlaylist = false; Party::Container.awaitingPlaylist = false;
Party::Container.joinTime = Game::Sys_Milliseconds(); Party::Container.joinTime = Game::Sys_Milliseconds();
Party::Container.target = target; Party::Container.target = target;
Party::Container.challenge = Utils::Cryptography::Rand::GenerateChallenge(); Party::Container.challenge = Utils::Cryptography::Rand::GenerateChallenge();
Network::SendCommand(Party::Container.target, "getinfo", Party::Container.challenge); Network::SendCommand(Party::Container.target, "getinfo", Party::Container.challenge);
Command::Execute("openmenu popup_reconnectingtoparty"); Command::Execute("openmenu popup_reconnectingtoparty");
} }
const char* Party::GetLobbyInfo(SteamID lobby, std::string key) const char* Party::GetLobbyInfo(SteamID lobby, std::string key)
{ {
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end()) if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
{ {
Network::Address address = Party::LobbyMap[lobby.Bits]; Network::Address address = Party::LobbyMap[lobby.Bits];
if (key == "addr") if (key == "addr")
{ {
return Utils::String::VA("%d", address.getIP().full); return Utils::String::VA("%d", address.getIP().full);
} }
else if (key =="port") else if (key =="port")
{ {
return Utils::String::VA("%d", address.getPort()); return Utils::String::VA("%d", address.getPort());
} }
} }
return "212"; return "212";
} }
void Party::RemoveLobby(SteamID lobby) void Party::RemoveLobby(SteamID lobby)
{ {
if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end()) if (Party::LobbyMap.find(lobby.Bits) != Party::LobbyMap.end())
{ {
Party::LobbyMap.erase(Party::LobbyMap.find(lobby.Bits)); Party::LobbyMap.erase(Party::LobbyMap.find(lobby.Bits));
} }
} }
void Party::ConnectError(std::string message) void Party::ConnectError(std::string message)
{ {
Localization::ClearTemp(); Localization::ClearTemp();
Command::Execute("closemenu popup_reconnectingtoparty"); Command::Execute("closemenu popup_reconnectingtoparty");
Dvar::Var("partyend_reason").set(message); Dvar::Var("partyend_reason").set(message);
Command::Execute("openmenu menu_xboxlive_partyended"); Command::Execute("openmenu menu_xboxlive_partyended");
} }
std::string Party::GetMotd() std::string Party::GetMotd()
{ {
return Party::Container.motd; return Party::Container.motd;
} }
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int /*value*/, int /*min*/, int max, Game::dvar_flag flag, const char* description) Game::dvar_t* Party::RegisterMinPlayers(const char* name, int /*value*/, int /*min*/, int max, Game::dvar_flag flag, const char* description)
{ {
return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).get<Game::dvar_t*>(); return Dvar::Register<int>(name, 1, 1, max, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED | flag, description).get<Game::dvar_t*>();
} }
bool Party::PlaylistAwaiting() bool Party::PlaylistAwaiting()
{ {
return Party::Container.awaitingPlaylist; return Party::Container.awaitingPlaylist;
} }
void Party::PlaylistContinue() void Party::PlaylistContinue()
{ {
Dvar::Var("xblive_privateserver").set(false); Dvar::Var("xblive_privateserver").set(false);
// Ensure we can join // Ensure we can join
*Game::g_lobbyCreateInProgress = false; *Game::g_lobbyCreateInProgress = false;
Party::Container.awaitingPlaylist = false; Party::Container.awaitingPlaylist = false;
SteamID id = Party::GenerateLobbyId(); SteamID id = Party::GenerateLobbyId();
// Temporary workaround // Temporary workaround
// TODO: Patch the 127.0.0.1 -> loopback mapping in the party code // TODO: Patch the 127.0.0.1 -> loopback mapping in the party code
if (Party::Container.target.isLoopback()) if (Party::Container.target.isLoopback())
{ {
if (*Game::numIP) if (*Game::numIP)
{ {
Party::Container.target.setIP(*Game::localIP); Party::Container.target.setIP(*Game::localIP);
Party::Container.target.setType(Game::netadrtype_t::NA_IP); Party::Container.target.setType(Game::netadrtype_t::NA_IP);
Logger::Print("Trying to connect to party with loopback address, using a local ip instead: %s\n", Party::Container.target.getCString()); Logger::Print("Trying to connect to party with loopback address, using a local ip instead: %s\n", Party::Container.target.getCString());
} }
else else
{ {
Logger::Print("Trying to connect to party with loopback address, but no local ip was found.\n"); Logger::Print("Trying to connect to party with loopback address, but no local ip was found.\n");
} }
} }
Party::LobbyMap[id.Bits] = Party::Container.target; Party::LobbyMap[id.Bits] = Party::Container.target;
Game::Steam_JoinLobby(id, 0); Game::Steam_JoinLobby(id, 0);
} }
void Party::PlaylistError(std::string error) void Party::PlaylistError(std::string error)
{ {
Party::Container.valid = false; Party::Container.valid = false;
Party::Container.awaitingPlaylist = false; Party::Container.awaitingPlaylist = false;
Party::ConnectError(error); Party::ConnectError(error);
} }
DWORD Party::UIDvarIntStub(char* dvar) DWORD Party::UIDvarIntStub(char* dvar)
{ {
if (!_stricmp(dvar, "onlinegame")) if (!_stricmp(dvar, "onlinegame"))
{ {
return 0x649E660; return 0x649E660;
} }
return Utils::Hook::Call<DWORD(char*)>(0x4D5390)(dvar); return Utils::Hook::Call<DWORD(char*)>(0x4D5390)(dvar);
} }
Party::Party() Party::Party()
{ {
static Game::dvar_t* partyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").get<Game::dvar_t*>(); static Game::dvar_t* partyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").get<Game::dvar_t*>();
Dvar::Register<bool>("xblive_privatematch", true, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "").get<Game::dvar_t*>(); Dvar::Register<bool>("xblive_privatematch", true, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "").get<Game::dvar_t*>();
// various changes to SV_DirectConnect-y stuff to allow non-party joinees // various changes to SV_DirectConnect-y stuff to allow non-party joinees
Utils::Hook::Set<WORD>(0x460D96, 0x90E9); Utils::Hook::Set<WORD>(0x460D96, 0x90E9);
Utils::Hook::Set<BYTE>(0x460F0A, 0xEB); Utils::Hook::Set<BYTE>(0x460F0A, 0xEB);
Utils::Hook::Set<BYTE>(0x401CA4, 0xEB); Utils::Hook::Set<BYTE>(0x401CA4, 0xEB);
Utils::Hook::Set<BYTE>(0x401C15, 0xEB); Utils::Hook::Set<BYTE>(0x401C15, 0xEB);
// disable configstring checksum matching (it's unreliable at most) // disable configstring checksum matching (it's unreliable at most)
Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer
Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate
Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate
// AnonymousAddRequest // AnonymousAddRequest
Utils::Hook::Set<BYTE>(0x5B5E18, 0xEB); Utils::Hook::Set<BYTE>(0x5B5E18, 0xEB);
Utils::Hook::Set<BYTE>(0x5B5E64, 0xEB); Utils::Hook::Set<BYTE>(0x5B5E64, 0xEB);
Utils::Hook::Nop(0x5B5E5C, 2); Utils::Hook::Nop(0x5B5E5C, 2);
// HandleClientHandshake // HandleClientHandshake
Utils::Hook::Set<BYTE>(0x5B6EA5, 0xEB); Utils::Hook::Set<BYTE>(0x5B6EA5, 0xEB);
Utils::Hook::Set<BYTE>(0x5B6EF3, 0xEB); Utils::Hook::Set<BYTE>(0x5B6EF3, 0xEB);
Utils::Hook::Nop(0x5B6EEB, 2); Utils::Hook::Nop(0x5B6EEB, 2);
// Allow local connections // Allow local connections
Utils::Hook::Set<BYTE>(0x4D43DA, 0xEB); Utils::Hook::Set<BYTE>(0x4D43DA, 0xEB);
// LobbyID mismatch // LobbyID mismatch
Utils::Hook::Nop(0x4E50D6, 2); Utils::Hook::Nop(0x4E50D6, 2);
Utils::Hook::Set<BYTE>(0x4E50DA, 0xEB); Utils::Hook::Set<BYTE>(0x4E50DA, 0xEB);
// causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored // causes 'does current Steam lobby match' calls in Steam_JoinLobby to be ignored
Utils::Hook::Set<BYTE>(0x49D007, 0xEB); Utils::Hook::Set<BYTE>(0x49D007, 0xEB);
// functions checking party heartbeat timeouts, cause random issues // functions checking party heartbeat timeouts, cause random issues
Utils::Hook::Nop(0x4E532D, 5); Utils::Hook::Nop(0x4E532D, 5);
// Steam_JoinLobby call causes migration // Steam_JoinLobby call causes migration
Utils::Hook::Nop(0x5AF851, 5); Utils::Hook::Nop(0x5AF851, 5);
Utils::Hook::Set<BYTE>(0x5AF85B, 0xEB); Utils::Hook::Set<BYTE>(0x5AF85B, 0xEB);
// Allow xpartygo in public lobbies // Allow xpartygo in public lobbies
Utils::Hook::Set<BYTE>(0x5A969E, 0xEB); Utils::Hook::Set<BYTE>(0x5A969E, 0xEB);
Utils::Hook::Nop(0x5A96BE, 2); Utils::Hook::Nop(0x5A96BE, 2);
// Always open lobby menu when connecting // Always open lobby menu when connecting
// It's not possible to entirely patch it via code // It's not possible to entirely patch it via code
//Utils::Hook::Set<BYTE>(0x5B1698, 0xEB); //Utils::Hook::Set<BYTE>(0x5B1698, 0xEB);
//Utils::Hook::Nop(0x5029F2, 6); //Utils::Hook::Nop(0x5029F2, 6);
//Utils::Hook::SetString(0x70573C, "menu_xboxlive_lobby"); //Utils::Hook::SetString(0x70573C, "menu_xboxlive_lobby");
// Disallow selecting team in private match // Disallow selecting team in private match
//Utils::Hook::Nop(0x5B2BD8, 6); //Utils::Hook::Nop(0x5B2BD8, 6);
// Force teams, even if not private match // Force teams, even if not private match
Utils::Hook::Set<BYTE>(0x487BB2, 0xEB); Utils::Hook::Set<BYTE>(0x487BB2, 0xEB);
// Force xblive_privatematch 0 and rename it // Force xblive_privatematch 0 and rename it
//Utils::Hook::Set<BYTE>(0x420A6A, 4); //Utils::Hook::Set<BYTE>(0x420A6A, 4);
Utils::Hook::Set<BYTE>(0x420A6C, 0); Utils::Hook::Set<BYTE>(0x420A6C, 0);
Utils::Hook::Set<char*>(0x420A6E, "xblive_privateserver"); Utils::Hook::Set<char*>(0x420A6E, "xblive_privateserver");
// Remove migration shutdown, it causes crashes and will be destroyed when erroring anyways // Remove migration shutdown, it causes crashes and will be destroyed when erroring anyways
Utils::Hook::Nop(0x5A8E1C, 12); Utils::Hook::Nop(0x5A8E1C, 12);
Utils::Hook::Nop(0x5A8E33, 11); Utils::Hook::Nop(0x5A8E33, 11);
// Enable XP Bar // Enable XP Bar
Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).install()->quick(); Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).install()->quick();
// Set NAT to open // Set NAT to open
Utils::Hook::Set<int>(0x79D898, 1); Utils::Hook::Set<int>(0x79D898, 1);
// Disable host migration // Disable host migration
Utils::Hook::Set<BYTE>(0x5B58B2, 0xEB); Utils::Hook::Set<BYTE>(0x5B58B2, 0xEB);
Utils::Hook::Set<BYTE>(0x4D6171, 0); Utils::Hook::Set<BYTE>(0x4D6171, 0);
// Patch playlist stuff for non-party behavior // Patch playlist stuff for non-party behavior
Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable);
Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable);
Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable);
// Invert corresponding jumps // Invert corresponding jumps
Utils::Hook::Xor<BYTE>(0x4A409B, 1); Utils::Hook::Xor<BYTE>(0x4A409B, 1);
Utils::Hook::Xor<BYTE>(0x4573FA, 1); Utils::Hook::Xor<BYTE>(0x4573FA, 1);
Utils::Hook::Xor<BYTE>(0x5B1A17, 1); Utils::Hook::Xor<BYTE>(0x5B1A17, 1);
// Fix xstartlobby // Fix xstartlobby
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB); //Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
// Patch party_minplayers to 1 and protect it // Patch party_minplayers to 1 and protect it
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).install()->quick(); //Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).install()->quick();
// Set ui_maxclients to sv_maxclients // Set ui_maxclients to sv_maxclients
Utils::Hook::Set<char*>(0x42618F, "sv_maxclients"); Utils::Hook::Set<char*>(0x42618F, "sv_maxclients");
Utils::Hook::Set<char*>(0x4D3756, "sv_maxclients"); Utils::Hook::Set<char*>(0x4D3756, "sv_maxclients");
Utils::Hook::Set<char*>(0x5E3772, "sv_maxclients"); Utils::Hook::Set<char*>(0x5E3772, "sv_maxclients");
// Unlatch maxclient dvars // Unlatch maxclient dvars
Utils::Hook::Xor<BYTE>(0x426187, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<BYTE>(0x426187, Game::dvar_flag::DVAR_FLAG_LATCHED);
Utils::Hook::Xor<BYTE>(0x4D374E, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<BYTE>(0x4D374E, Game::dvar_flag::DVAR_FLAG_LATCHED);
Utils::Hook::Xor<BYTE>(0x5E376A, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<BYTE>(0x5E376A, Game::dvar_flag::DVAR_FLAG_LATCHED);
Utils::Hook::Xor<DWORD>(0x4261A1, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<DWORD>(0x4261A1, Game::dvar_flag::DVAR_FLAG_LATCHED);
Utils::Hook::Xor<DWORD>(0x4D376D, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<DWORD>(0x4D376D, Game::dvar_flag::DVAR_FLAG_LATCHED);
Utils::Hook::Xor<DWORD>(0x5E3789, Game::dvar_flag::DVAR_FLAG_LATCHED); Utils::Hook::Xor<DWORD>(0x5E3789, Game::dvar_flag::DVAR_FLAG_LATCHED);
// Patch Live_PlayerHasLoopbackAddr // Patch Live_PlayerHasLoopbackAddr
//Utils::Hook::Set<DWORD>(0x418F30, 0x90C3C033); //Utils::Hook::Set<DWORD>(0x418F30, 0x90C3C033);
Command::Add("connect", [] (Command::Params* params) Command::Add("connect", [] (Command::Params* params)
{ {
if (params->length() < 2) if (params->length() < 2)
{ {
return; return;
} }
Party::Connect(Network::Address(params->get(1))); Party::Connect(Network::Address(params->get(1)));
}); });
Command::Add("reconnect", [] (Command::Params*) Command::Add("reconnect", [] (Command::Params*)
{ {
Party::Connect(Party::Container.target); Party::Connect(Party::Container.target);
}); });
Renderer::OnFrame([] () Renderer::OnFrame([] ()
{ {
if (Party::Container.valid) if (Party::Container.valid)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 5000) if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 5000)
{ {
Party::Container.valid = false; Party::Container.valid = false;
Party::ConnectError("Server connection timed out."); Party::ConnectError("Server connection timed out.");
} }
} }
if (Party::Container.awaitingPlaylist) if (Party::Container.awaitingPlaylist)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5000) if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5000)
{ {
Party::Container.awaitingPlaylist = false; Party::Container.awaitingPlaylist = false;
Party::ConnectError("Playlist request timed out."); Party::ConnectError("Playlist request timed out.");
} }
} }
}); });
// Basic info handler // Basic info handler
Network::Handle("getInfo", [] (Network::Address address, std::string data) Network::Handle("getInfo", [] (Network::Address address, std::string data)
{ {
int clientCount = 0; int clientCount = 0;
int maxclientCount = *Game::svs_numclients; int maxclientCount = *Game::svs_numclients;
if (maxclientCount) if (maxclientCount)
{ {
for (int i = 0; i < maxclientCount; ++i) for (int i = 0; i < maxclientCount; ++i)
{ {
if (Game::svs_clients[i].state >= 3) if (Game::svs_clients[i].state >= 3)
{ {
++clientCount; ++clientCount;
} }
} }
} }
else else
{ {
//maxclientCount = Dvar::Var("sv_maxclients").get<int>(); //maxclientCount = Dvar::Var("sv_maxclients").get<int>();
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00)); clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData_s*>(0x1081C00));
} }
Utils::InfoString info; Utils::InfoString info;
info.set("challenge", Utils::ParseChallenge(data)); info.set("challenge", Utils::ParseChallenge(data));
info.set("gamename", "IW4"); info.set("gamename", "IW4");
info.set("hostname", Dvar::Var("sv_hostname").get<const char*>()); info.set("hostname", Dvar::Var("sv_hostname").get<const char*>());
info.set("gametype", Dvar::Var("g_gametype").get<const char*>()); info.set("gametype", Dvar::Var("g_gametype").get<const char*>());
info.set("fs_game", Dvar::Var("fs_game").get<const char*>()); info.set("fs_game", Dvar::Var("fs_game").get<const char*>());
info.set("xuid", Utils::String::VA("%llX", Steam::SteamUser()->GetSteamID().Bits)); info.set("xuid", Utils::String::VA("%llX", Steam::SteamUser()->GetSteamID().Bits));
info.set("clients", Utils::String::VA("%i", clientCount)); info.set("clients", Utils::String::VA("%i", clientCount));
info.set("sv_maxclients", Utils::String::VA("%i", maxclientCount)); info.set("sv_maxclients", Utils::String::VA("%i", maxclientCount));
info.set("protocol", Utils::String::VA("%i", PROTOCOL)); info.set("protocol", Utils::String::VA("%i", PROTOCOL));
info.set("shortversion", SHORTVERSION); info.set("shortversion", SHORTVERSION);
info.set("checksum", Utils::String::VA("%d", Game::Sys_Milliseconds())); info.set("checksum", Utils::String::VA("%d", Game::Sys_Milliseconds()));
info.set("mapname", Dvar::Var("mapname").get<const char*>()); info.set("mapname", Dvar::Var("mapname").get<const char*>());
info.set("isPrivate", (Dvar::Var("g_password").get<std::string>().size() ? "1" : "0")); info.set("isPrivate", (Dvar::Var("g_password").get<std::string>().size() ? "1" : "0"));
info.set("hc", (Dvar::Var("g_hardcore").get<bool>() ? "1" : "0")); info.set("hc", (Dvar::Var("g_hardcore").get<bool>() ? "1" : "0"));
info.set("securityLevel", Utils::String::VA("%i", Dvar::Var("sv_securityLevel").get<int>())); info.set("securityLevel", Utils::String::VA("%i", Dvar::Var("sv_securityLevel").get<int>()));
info.set("sv_running", (Dvar::Var("sv_running").get<bool>() ? "1" : "0")); info.set("sv_running", (Dvar::Var("sv_running").get<bool>() ? "1" : "0"));
if (Dedicated::IsEnabled()) if (Dedicated::IsEnabled())
{ {
info.set("sv_motd", Dvar::Var("sv_motd").get<std::string>()); info.set("sv_motd", Dvar::Var("sv_motd").get<std::string>());
} }
// Ensure mapname is set // Ensure mapname is set
if (info.get("mapname").empty() || (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>() && !Dvar::Var("sv_running").get<bool>())) if (info.get("mapname").empty() || (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>() && !Dvar::Var("sv_running").get<bool>()))
{ {
info.set("mapname", Dvar::Var("ui_mapname").get<const char*>()); info.set("mapname", Dvar::Var("ui_mapname").get<const char*>());
} }
// Set matchtype // Set matchtype
// 0 - No match, connecting not possible // 0 - No match, connecting not possible
// 1 - Party, use Steam_JoinLobby to connect // 1 - Party, use Steam_JoinLobby to connect
// 2 - Match, use CL_ConnectFromParty to connect // 2 - Match, use CL_ConnectFromParty to connect
if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting
{ {
info.set("matchtype", "1"); info.set("matchtype", "1");
} }
else if (Dvar::Var("sv_running").get<bool>()) // Match hosting else if (Dvar::Var("sv_running").get<bool>()) // Match hosting
{ {
info.set("matchtype", "2"); info.set("matchtype", "2");
} }
else else
{ {
info.set("matchtype", "0"); info.set("matchtype", "0");
} }
Network::SendCommand(address, "infoResponse", "\\" + info.build()); Network::SendCommand(address, "infoResponse", "\\" + info.build());
}); });
Network::Handle("infoResponse", [] (Network::Address address, std::string data) Network::Handle("infoResponse", [] (Network::Address address, std::string data)
{ {
Utils::InfoString info(data); Utils::InfoString info(data);
// Handle connection // Handle connection
if (Party::Container.valid) if (Party::Container.valid)
{ {
if (Party::Container.target == address) if (Party::Container.target == address)
{ {
// Invalidate handler for future packets // Invalidate handler for future packets
Party::Container.valid = false; Party::Container.valid = false;
Party::Container.info = info; Party::Container.info = info;
Party::Container.matchType = atoi(info.get("matchtype").data()); Party::Container.matchType = atoi(info.get("matchtype").data());
uint32_t securityLevel = static_cast<uint32_t>(atoi(info.get("securityLevel").data())); uint32_t securityLevel = static_cast<uint32_t>(atoi(info.get("securityLevel").data()));
if (info.get("challenge") != Party::Container.challenge) std::string mod = Dvar::Var("fs_game").get<std::string>();
{
Party::ConnectError("Invalid join response: Challenge mismatch."); if (info.get("challenge") != Party::Container.challenge)
} {
else if (securityLevel > Auth::GetSecurityLevel()) Party::ConnectError("Invalid join response: Challenge mismatch.");
{ }
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel)); else if (securityLevel > Auth::GetSecurityLevel())
Command::Execute("closemenu popup_reconnectingtoparty"); {
Auth::IncreaseSecurityLevel(securityLevel, "reconnect"); //Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
} Command::Execute("closemenu popup_reconnectingtoparty");
else if (!Party::Container.matchType) Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
{ }
Party::ConnectError("Server is not hosting a match."); else if (!Party::Container.matchType)
} {
else if(Party::Container.matchType > 2 || Party::Container.matchType < 0) Party::ConnectError("Server is not hosting a match.");
{ }
Party::ConnectError("Invalid join response: Unknown matchtype"); else if(Party::Container.matchType > 2 || Party::Container.matchType < 0)
} {
else if(!info.get("fs_game").empty() && Utils::String::ToLower(Dvar::Var("fs_game").get<std::string>()) != Utils::String::ToLower(info.get("fs_game"))) Party::ConnectError("Invalid join response: Unknown matchtype");
{ }
Command::Execute("closemenu popup_reconnectingtoparty"); else if(!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
Download::InitiateClientDownload(info.get("fs_game")); {
} Command::Execute("closemenu popup_reconnectingtoparty");
else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty()) Download::InitiateClientDownload(info.get("fs_game"));
{ }
Dvar::Var("fs_game").set(""); else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
{
if (Dvar::Var("cl_modVidRestart").get<bool>()) Dvar::Var("fs_game").set("");
{
Command::Execute("vid_restart", false); if (Dvar::Var("cl_modVidRestart").get<bool>())
} {
Command::Execute("vid_restart", false);
Command::Execute("reconnect", false); }
}
else Command::Execute("reconnect", false);
{ }
Party::Container.motd = info.get("sv_motd"); else
{
if (Party::Container.matchType == 1) // Party Party::Container.motd = info.get("sv_motd");
{
// Send playlist request if (Party::Container.matchType == 1) // Party
Party::Container.requestTime = Game::Sys_Milliseconds(); {
Party::Container.awaitingPlaylist = true; // Send playlist request
Network::SendCommand(Party::Container.target, "getplaylist"); Party::Container.requestTime = Game::Sys_Milliseconds();
Party::Container.awaitingPlaylist = true;
// This is not a safe method Network::SendCommand(Party::Container.target, "getplaylist");
// TODO: Fix actual error!
if (Game::CL_IsCgameInitialized()) // This is not a safe method
{ // TODO: Fix actual error!
Command::Execute("disconnect", true); if (Game::CL_IsCgameInitialized())
} {
} Command::Execute("disconnect", true);
else if (Party::Container.matchType == 2) // Match }
{ }
if (atoi(Party::Container.info.get("clients").data()) >= atoi(Party::Container.info.get("sv_maxclients").data())) else if (Party::Container.matchType == 2) // Match
{ {
Party::ConnectError("@EXE_SERVERISFULL"); if (atoi(Party::Container.info.get("clients").data()) >= atoi(Party::Container.info.get("sv_maxclients").data()))
} {
if (Party::Container.info.get("mapname") == "" || Party::Container.info.get("gametype") == "") Party::ConnectError("@EXE_SERVERISFULL");
{ }
Party::ConnectError("Invalid map or gametype."); if (Party::Container.info.get("mapname") == "" || Party::Container.info.get("gametype") == "")
} {
else Party::ConnectError("Invalid map or gametype.");
{ }
Dvar::Var("xblive_privateserver").set(true); else
{
Game::Menus_CloseAll(Game::uiContext); Dvar::Var("xblive_privateserver").set(true);
Game::_XSESSION_INFO hostInfo; Game::Menus_CloseAll(Game::uiContext);
Game::CL_ConnectFromParty(0, &hostInfo, *Party::Container.target.get(), 0, 0, Party::Container.info.get("mapname").data(), Party::Container.info.get("gametype").data());
} Game::_XSESSION_INFO hostInfo;
} Game::CL_ConnectFromParty(0, &hostInfo, *Party::Container.target.get(), 0, 0, Party::Container.info.get("mapname").data(), Party::Container.info.get("gametype").data());
} }
} }
} }
}
ServerList::Insert(address, info); }
});
} ServerList::Insert(address, info);
});
Party::~Party() }
{
Party::LobbyMap.clear(); Party::~Party()
} {
} Party::LobbyMap.clear();
}
}

View File

@ -1,53 +1,53 @@
namespace Components namespace Components
{ {
class Party : public Component class Party : public Component
{ {
public: public:
Party(); Party();
~Party(); ~Party();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Party"; }; const char* getName() { return "Party"; };
#endif #endif
static Network::Address Target(); static Network::Address Target();
static void Connect(Network::Address target); static void Connect(Network::Address target);
static const char* GetLobbyInfo(SteamID lobby, std::string key); static const char* GetLobbyInfo(SteamID lobby, std::string key);
static void RemoveLobby(SteamID lobby); static void RemoveLobby(SteamID lobby);
static bool PlaylistAwaiting(); static bool PlaylistAwaiting();
static void PlaylistContinue(); static void PlaylistContinue();
static void PlaylistError(std::string error); static void PlaylistError(std::string error);
static void ConnectError(std::string message); static void ConnectError(std::string message);
static std::string GetMotd(); static std::string GetMotd();
private: private:
class JoinContainer class JoinContainer
{ {
public: public:
Network::Address target; Network::Address target;
std::string challenge; std::string challenge;
std::string motd; std::string motd;
DWORD joinTime; DWORD joinTime;
bool valid; bool valid;
int matchType; int matchType;
Utils::InfoString info; Utils::InfoString info;
// Party-specific stuff // Party-specific stuff
DWORD requestTime; DWORD requestTime;
bool awaitingPlaylist; bool awaitingPlaylist;
}; };
static JoinContainer Container; static JoinContainer Container;
static std::map<uint64_t, Network::Address> LobbyMap; static std::map<uint64_t, Network::Address> LobbyMap;
static SteamID GenerateLobbyId(); static SteamID GenerateLobbyId();
static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description); static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, Game::dvar_flag flag, const char* description);
static DWORD UIDvarIntStub(char* dvar); static DWORD UIDvarIntStub(char* dvar);
}; };
} }

View File

@ -1,33 +1,33 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::string PlayerName::PlayerNames[18]; std::string PlayerName::PlayerNames[18];
int PlayerName::GetClientName(int /*localClientNum*/, int index, char *buf, int size) int PlayerName::GetClientName(int /*localClientNum*/, int index, char *buf, int size)
{ {
if (index < 0 || index >= 18) return 0; if (index < 0 || index >= 18) return 0;
return strncpy_s(buf, size, PlayerName::PlayerNames[index].data(), PlayerName::PlayerNames[index].size()) == 0; return strncpy_s(buf, size, PlayerName::PlayerNames[index].data(), PlayerName::PlayerNames[index].size()) == 0;
} }
PlayerName::PlayerName() PlayerName::PlayerName()
{ {
if (0) // Disabled for now (comment out that line to enable it) if (0) // Disabled for now (comment out that line to enable it)
{ {
for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i)
{ {
PlayerName::PlayerNames[i] = "mumu"; PlayerName::PlayerNames[i] = "mumu";
} }
Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick(); Utils::Hook(Game::CL_GetClientName, PlayerName::GetClientName, HOOK_JUMP).install()->quick();
} }
} }
PlayerName::~PlayerName() PlayerName::~PlayerName()
{ {
for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i) for (int i = 0; i < ARRAY_SIZE(PlayerName::PlayerNames); ++i)
{ {
PlayerName::PlayerNames[i].clear(); PlayerName::PlayerNames[i].clear();
} }
} }
} }

View File

@ -1,18 +1,18 @@
namespace Components namespace Components
{ {
class PlayerName : public Component class PlayerName : public Component
{ {
public: public:
PlayerName(); PlayerName();
~PlayerName(); ~PlayerName();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "PlayerName"; }; const char* getName() { return "PlayerName"; };
#endif #endif
private: private:
static std::string PlayerNames[18]; static std::string PlayerNames[18];
static int GetClientName(int localClientNum, int index, char *buf, int size); static int GetClientName(int localClientNum, int index, char *buf, int size);
}; };
} }

View File

@ -1,184 +1,184 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::string Playlist::CurrentPlaylistBuffer; std::string Playlist::CurrentPlaylistBuffer;
std::string Playlist::ReceivedPlaylistBuffer; std::string Playlist::ReceivedPlaylistBuffer;
std::unordered_map<const void*, std::string> Playlist::MapRelocation; std::unordered_map<const void*, std::string> Playlist::MapRelocation;
void Playlist::LoadPlaylist() void Playlist::LoadPlaylist()
{ {
// Check if playlist already loaded // Check if playlist already loaded
if (Utils::Hook::Get<bool>(0x1AD3680)) return; if (Utils::Hook::Get<bool>(0x1AD3680)) return;
// Don't load playlists when dedi and no party // Don't load playlists when dedi and no party
if (Dedicated::IsEnabled() && !Dvar::Var("party_enable").get<bool>()) if (Dedicated::IsEnabled() && !Dvar::Var("party_enable").get<bool>())
{ {
Utils::Hook::Set<bool>(0x1AD3680, true); // Set received to true Utils::Hook::Set<bool>(0x1AD3680, true); // Set received to true
Dvar::Var("xblive_privateserver").set(true); Dvar::Var("xblive_privateserver").set(true);
return; return;
} }
Dvar::Var("xblive_privateserver").set(false); Dvar::Var("xblive_privateserver").set(false);
std::string playlistFilename = Dvar::Var("playlistFilename").get<char*>(); std::string playlistFilename = Dvar::Var("playlistFilename").get<char*>();
FileSystem::File playlist(playlistFilename); FileSystem::File playlist(playlistFilename);
if (playlist.exists()) if (playlist.exists())
{ {
Logger::Print("Parsing playlist '%s'...\n", playlist.getName().data()); Logger::Print("Parsing playlist '%s'...\n", playlist.getName().data());
Game::Playlist_ParsePlaylists(playlist.getBuffer().data()); Game::Playlist_ParsePlaylists(playlist.getBuffer().data());
Utils::Hook::Set<bool>(0x1AD3680, true); // Playlist loaded Utils::Hook::Set<bool>(0x1AD3680, true); // Playlist loaded
} }
else else
{ {
Logger::Print("Unable to load playlist '%s'!\n", playlist.getName().data()); Logger::Print("Unable to load playlist '%s'!\n", playlist.getName().data());
} }
} }
DWORD Playlist::StorePlaylistStub(const char** buffer) DWORD Playlist::StorePlaylistStub(const char** buffer)
{ {
Playlist::MapRelocation.clear(); Playlist::MapRelocation.clear();
Playlist::CurrentPlaylistBuffer = *buffer; Playlist::CurrentPlaylistBuffer = *buffer;
return Utils::Hook::Call<DWORD(const char**)>(0x4C0350)(buffer); return Utils::Hook::Call<DWORD(const char**)>(0x4C0350)(buffer);
} }
void Playlist::PlaylistRequest(Network::Address address, std::string data) void Playlist::PlaylistRequest(Network::Address address, std::string data)
{ {
Logger::Print("Received playlist request, sending currently stored buffer.\n"); Logger::Print("Received playlist request, sending currently stored buffer.\n");
std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer); std::string compressedList = Utils::Compression::ZLib::Compress(Playlist::CurrentPlaylistBuffer);
Proto::Party::Playlist list; Proto::Party::Playlist list;
list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList)); list.set_hash(Utils::Cryptography::JenkinsOneAtATime::Compute(compressedList));
list.set_buffer(compressedList); list.set_buffer(compressedList);
Network::SendCommand(address, "playlistResponse", list.SerializeAsString()); Network::SendCommand(address, "playlistResponse", list.SerializeAsString());
} }
void Playlist::PlaylistReponse(Network::Address address, std::string data) void Playlist::PlaylistReponse(Network::Address address, std::string data)
{ {
if (Party::PlaylistAwaiting()) if (Party::PlaylistAwaiting())
{ {
if (address == Party::Target()) if (address == Party::Target())
{ {
Proto::Party::Playlist list; Proto::Party::Playlist list;
if (!list.ParseFromString(data)) if (!list.ParseFromString(data))
{ {
Party::PlaylistError(Utils::String::VA("Received playlist response from %s, but it is invalid.", address.getCString())); Party::PlaylistError(Utils::String::VA("Received playlist response from %s, but it is invalid.", address.getCString()));
Playlist::ReceivedPlaylistBuffer.clear(); Playlist::ReceivedPlaylistBuffer.clear();
return; return;
} }
else else
{ {
// Generate buffer and hash // Generate buffer and hash
std::string compressedData(list.buffer()); std::string compressedData(list.buffer());
unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData); unsigned int hash = Utils::Cryptography::JenkinsOneAtATime::Compute(compressedData);
//Validate hashes //Validate hashes
if (hash != list.hash()) if (hash != list.hash())
{ {
Party::PlaylistError(Utils::String::VA("Received playlist response from %s, but the checksum did not match (%X != %X).", address.getCString(), list.hash(), hash)); Party::PlaylistError(Utils::String::VA("Received playlist response from %s, but the checksum did not match (%X != %X).", address.getCString(), list.hash(), hash));
Playlist::ReceivedPlaylistBuffer.clear(); Playlist::ReceivedPlaylistBuffer.clear();
return; return;
} }
// Decompress buffer // Decompress buffer
Playlist::ReceivedPlaylistBuffer = Utils::Compression::ZLib::Decompress(compressedData); Playlist::ReceivedPlaylistBuffer = Utils::Compression::ZLib::Decompress(compressedData);
// Load and continue connection // Load and continue connection
Logger::Print("Received playlist, loading and continuing connection...\n"); Logger::Print("Received playlist, loading and continuing connection...\n");
Game::Playlist_ParsePlaylists(Playlist::ReceivedPlaylistBuffer.data()); Game::Playlist_ParsePlaylists(Playlist::ReceivedPlaylistBuffer.data());
Party::PlaylistContinue(); Party::PlaylistContinue();
} }
} }
else else
{ {
Logger::Print("Received playlist from someone else than our target host, ignoring it.\n"); Logger::Print("Received playlist from someone else than our target host, ignoring it.\n");
} }
} }
else else
{ {
Logger::Print("Received stray playlist response, ignoring it.\n"); Logger::Print("Received stray playlist response, ignoring it.\n");
} }
} }
void Playlist::MapNameCopy(char *dest, const char *src, int destsize) void Playlist::MapNameCopy(char *dest, const char *src, int destsize)
{ {
Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, src, destsize); Utils::Hook::Call<void(char*, const char*, int)>(0x4D6F80)(dest, src, destsize);
Playlist::MapRelocation[dest] = src; Playlist::MapRelocation[dest] = src;
} }
void Playlist::SetMapName(const char* cvar, const char* value) void Playlist::SetMapName(const char* cvar, const char* value)
{ {
auto i = Playlist::MapRelocation.find(value); auto i = Playlist::MapRelocation.find(value);
if (i != Playlist::MapRelocation.end()) if (i != Playlist::MapRelocation.end())
{ {
value = i->second.data(); value = i->second.data();
} }
Game::Dvar_SetStringByName(cvar, value); Game::Dvar_SetStringByName(cvar, value);
} }
int Playlist::GetMapIndex(const char* mapname) int Playlist::GetMapIndex(const char* mapname)
{ {
auto i = Playlist::MapRelocation.find(mapname); auto i = Playlist::MapRelocation.find(mapname);
if (i != Playlist::MapRelocation.end()) if (i != Playlist::MapRelocation.end())
{ {
mapname = i->second.data(); mapname = i->second.data();
} }
return Game::Live_GetMapIndex(mapname); return Game::Live_GetMapIndex(mapname);
} }
Playlist::Playlist() Playlist::Playlist()
{ {
// Default playlists // Default playlists
Utils::Hook::Set<char*>(0x60B06E, "playlists_default.info"); Utils::Hook::Set<char*>(0x60B06E, "playlists_default.info");
// disable playlist download function // disable playlist download function
Utils::Hook::Set<BYTE>(0x4D4790, 0xC3); Utils::Hook::Set<BYTE>(0x4D4790, 0xC3);
// Load playlist, but don't delete it // Load playlist, but don't delete it
Utils::Hook::Nop(0x4D6EBB, 5); Utils::Hook::Nop(0x4D6EBB, 5);
Utils::Hook::Nop(0x4D6E67, 5); Utils::Hook::Nop(0x4D6E67, 5);
Utils::Hook::Nop(0x4D6E71, 2); Utils::Hook::Nop(0x4D6E71, 2);
// playlist dvar 'validity check' // playlist dvar 'validity check'
Utils::Hook::Set<BYTE>(0x4B1170, 0xC3); Utils::Hook::Set<BYTE>(0x4B1170, 0xC3);
// disable playlist checking // disable playlist checking
Utils::Hook::Set<BYTE>(0x5B69E9, 0xEB); // too new Utils::Hook::Set<BYTE>(0x5B69E9, 0xEB); // too new
Utils::Hook::Set<BYTE>(0x5B696E, 0xEB); // too old Utils::Hook::Set<BYTE>(0x5B696E, 0xEB); // too old
//Got playlists is true //Got playlists is true
//Utils::Hook::Set<bool>(0x1AD3680, true); //Utils::Hook::Set<bool>(0x1AD3680, true);
Utils::Hook(0x497DB5, Playlist::GetMapIndex, HOOK_CALL).install()->quick(); Utils::Hook(0x497DB5, Playlist::GetMapIndex, HOOK_CALL).install()->quick();
Utils::Hook(0x42A19D, Playlist::MapNameCopy, HOOK_CALL).install()->quick(); Utils::Hook(0x42A19D, Playlist::MapNameCopy, HOOK_CALL).install()->quick();
Utils::Hook(0x4A6FEE, Playlist::SetMapName, HOOK_CALL).install()->quick(); Utils::Hook(0x4A6FEE, Playlist::SetMapName, HOOK_CALL).install()->quick();
// Store playlist buffer on load // Store playlist buffer on load
Utils::Hook(0x42961C, Playlist::StorePlaylistStub, HOOK_CALL).install()->quick(); Utils::Hook(0x42961C, Playlist::StorePlaylistStub, HOOK_CALL).install()->quick();
//if (Dedicated::IsDedicated()) //if (Dedicated::IsDedicated())
{ {
// Custom playlist loading // Custom playlist loading
Utils::Hook(0x420B5A, Playlist::LoadPlaylist, HOOK_JUMP).install()->quick(); Utils::Hook(0x420B5A, Playlist::LoadPlaylist, HOOK_JUMP).install()->quick();
// disable playlist.ff loading function // disable playlist.ff loading function
Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3); Utils::Hook::Set<BYTE>(0x4D6E60, 0xC3);
} }
Network::Handle("getPlaylist", PlaylistRequest); Network::Handle("getPlaylist", PlaylistRequest);
Network::Handle("playlistResponse", PlaylistReponse); Network::Handle("playlistResponse", PlaylistReponse);
} }
Playlist::~Playlist() Playlist::~Playlist()
{ {
Playlist::MapRelocation.clear(); Playlist::MapRelocation.clear();
Playlist::CurrentPlaylistBuffer.clear(); Playlist::CurrentPlaylistBuffer.clear();
Playlist::ReceivedPlaylistBuffer.clear(); Playlist::ReceivedPlaylistBuffer.clear();
} }
} }

View File

@ -1,32 +1,32 @@
namespace Components namespace Components
{ {
class Playlist : public Component class Playlist : public Component
{ {
public: public:
typedef void(*Callback)(); typedef void(*Callback)();
Playlist(); Playlist();
~Playlist(); ~Playlist();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Playlist"; }; const char* getName() { return "Playlist"; };
#endif #endif
static void LoadPlaylist(); static void LoadPlaylist();
static std::string ReceivedPlaylistBuffer; static std::string ReceivedPlaylistBuffer;
private: private:
static std::string CurrentPlaylistBuffer; static std::string CurrentPlaylistBuffer;
static std::unordered_map<const void*, std::string> MapRelocation; static std::unordered_map<const void*, std::string> MapRelocation;
static DWORD StorePlaylistStub(const char** buffer); static DWORD StorePlaylistStub(const char** buffer);
static void PlaylistRequest(Network::Address address, std::string data); static void PlaylistRequest(Network::Address address, std::string data);
static void PlaylistReponse(Network::Address address, std::string data); static void PlaylistReponse(Network::Address address, std::string data);
static void MapNameCopy(char *dest, const char *src, int destsize); static void MapNameCopy(char *dest, const char *src, int destsize);
static void SetMapName(const char* cvar, const char* value); static void SetMapName(const char* cvar, const char* value);
static int GetMapIndex(const char* mapname); static int GetMapIndex(const char* mapname);
}; };
} }

View File

@ -1,38 +1,38 @@
namespace Components namespace Components
{ {
class QuickPatch : public Component class QuickPatch : public Component
{ {
public: public:
typedef void(Callback)(); typedef void(Callback)();
QuickPatch(); QuickPatch();
~QuickPatch(); ~QuickPatch();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "QuickPatch"; }; const char* getName() { return "QuickPatch"; };
#endif #endif
bool unitTest(); bool unitTest();
static void UnlockStats(); static void UnlockStats();
static void OnShutdown(Utils::Slot<Callback> callback); static void OnShutdown(Utils::Slot<Callback> callback);
static void OnFrame(Utils::Slot<Callback> callback); static void OnFrame(Utils::Slot<Callback> callback);
static void Once(Utils::Slot<Callback> callback); static void Once(Utils::Slot<Callback> callback);
private: private:
static Utils::Signal<Callback> ShutdownSignal; static Utils::Signal<Callback> ShutdownSignal;
static int64_t* GetStatsID(); static int64_t* GetStatsID();
static void ShutdownStub(int num); static void ShutdownStub(int num);
static void SelectStringTableEntryInDvarStub(); static void SelectStringTableEntryInDvarStub();
static int MsgReadBitsCompressCheckSV(const char *from, char *to, int size); static int MsgReadBitsCompressCheckSV(const char *from, char *to, int size);
static int MsgReadBitsCompressCheckCL(const char *from, char *to, int size); static int MsgReadBitsCompressCheckCL(const char *from, char *to, int size);
static void CompareMaterialStateBits(); static void CompareMaterialStateBits();
static void testFunc(); static void testFunc();
}; };
} }

View File

@ -1,169 +1,169 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
RCon::Container RCon::BackdoorContainer; RCon::Container RCon::BackdoorContainer;
Utils::Cryptography::ECC::Key RCon::BackdoorKey; Utils::Cryptography::ECC::Key RCon::BackdoorKey;
std::string RCon::Password; std::string RCon::Password;
RCon::RCon() RCon::RCon()
{ {
Command::Add("rcon", [] (Command::Params* params) Command::Add("rcon", [] (Command::Params* params)
{ {
if (params->length() < 2) return; if (params->length() < 2) return;
std::string operation = params->get(1); std::string operation = params->get(1);
if (operation == "login") if (operation == "login")
{ {
if (params->length() < 3) return; if (params->length() < 3) return;
RCon::Password = params->get(2); RCon::Password = params->get(2);
} }
else if (operation == "logout") else if (operation == "logout")
{ {
RCon::Password.clear(); RCon::Password.clear();
} }
else else
{ {
if (!RCon::Password.empty() && *reinterpret_cast<int*>(0xB2C540) >= 5) // Get our state if (!RCon::Password.empty() && *reinterpret_cast<int*>(0xB2C540) >= 5) // Get our state
{ {
Network::Address target(reinterpret_cast<Game::netadr_t*>(0xA5EA44)); Network::Address target(reinterpret_cast<Game::netadr_t*>(0xA5EA44));
if (target.isValid()) if (target.isValid())
{ {
Network::SendCommand(target, "rcon", RCon::Password + " " + params->join(1)); Network::SendCommand(target, "rcon", RCon::Password + " " + params->join(1));
} }
else else
{ {
Logger::Print("You are connected to an invalid server\n"); Logger::Print("You are connected to an invalid server\n");
} }
} }
else else
{ {
Logger::Print("You need to be logged in and connected to a server!\n"); Logger::Print("You need to be logged in and connected to a server!\n");
} }
} }
}); });
if (!Dedicated::IsEnabled()) return; if (!Dedicated::IsEnabled()) return;
// Load public key // Load public key
static uint8_t publicKey[] = static uint8_t publicKey[] =
{ {
0x04, 0x01, 0x9D, 0x18, 0x7F, 0x57, 0xD8, 0x95, 0x4C, 0xEE, 0xD0, 0x21, 0x04, 0x01, 0x9D, 0x18, 0x7F, 0x57, 0xD8, 0x95, 0x4C, 0xEE, 0xD0, 0x21,
0xB5, 0x00, 0x53, 0xEC, 0xEB, 0x54, 0x7C, 0x4C, 0x37, 0x18, 0x53, 0x89, 0xB5, 0x00, 0x53, 0xEC, 0xEB, 0x54, 0x7C, 0x4C, 0x37, 0x18, 0x53, 0x89,
0x40, 0x12, 0xF7, 0x08, 0x8D, 0x9A, 0x8D, 0x99, 0x9C, 0x79, 0x79, 0x59, 0x40, 0x12, 0xF7, 0x08, 0x8D, 0x9A, 0x8D, 0x99, 0x9C, 0x79, 0x79, 0x59,
0x6E, 0x32, 0x06, 0xEB, 0x49, 0x1E, 0x00, 0x99, 0x71, 0xCB, 0x4A, 0xE1, 0x6E, 0x32, 0x06, 0xEB, 0x49, 0x1E, 0x00, 0x99, 0x71, 0xCB, 0x4A, 0xE1,
0x90, 0xF1, 0x7C, 0xB7, 0x4D, 0x60, 0x88, 0x0A, 0xB7, 0xF3, 0xD7, 0x0D, 0x90, 0xF1, 0x7C, 0xB7, 0x4D, 0x60, 0x88, 0x0A, 0xB7, 0xF3, 0xD7, 0x0D,
0x4F, 0x08, 0x13, 0x7C, 0xEB, 0x01, 0xFF, 0x00, 0x32, 0xEE, 0xE6, 0x23, 0x4F, 0x08, 0x13, 0x7C, 0xEB, 0x01, 0xFF, 0x00, 0x32, 0xEE, 0xE6, 0x23,
0x07, 0xB1, 0xC2, 0x9E, 0x45, 0xD6, 0xD7, 0xBD, 0xED, 0x05, 0x23, 0xB5, 0x07, 0xB1, 0xC2, 0x9E, 0x45, 0xD6, 0xD7, 0xBD, 0xED, 0x05, 0x23, 0xB5,
0xE7, 0x83, 0xEF, 0xD7, 0x8E, 0x36, 0xDC, 0x16, 0x79, 0x74, 0xD1, 0xD5, 0xE7, 0x83, 0xEF, 0xD7, 0x8E, 0x36, 0xDC, 0x16, 0x79, 0x74, 0xD1, 0xD5,
0xBA, 0x2C, 0x4C, 0x28, 0x61, 0x29, 0x5C, 0x49, 0x7D, 0xD4, 0xB6, 0x56, 0xBA, 0x2C, 0x4C, 0x28, 0x61, 0x29, 0x5C, 0x49, 0x7D, 0xD4, 0xB6, 0x56,
0x17, 0x75, 0xF5, 0x2B, 0x58, 0xCD, 0x0D, 0x76, 0x65, 0x10, 0xF7, 0x51, 0x17, 0x75, 0xF5, 0x2B, 0x58, 0xCD, 0x0D, 0x76, 0x65, 0x10, 0xF7, 0x51,
0x69, 0x1D, 0xB9, 0x0F, 0x38, 0xF6, 0x53, 0x3B, 0xF7, 0xCE, 0x76, 0x4F, 0x69, 0x1D, 0xB9, 0x0F, 0x38, 0xF6, 0x53, 0x3B, 0xF7, 0xCE, 0x76, 0x4F,
0x08 0x08
}; };
RCon::BackdoorKey.set(std::string(reinterpret_cast<char*>(publicKey), sizeof(publicKey))); RCon::BackdoorKey.set(std::string(reinterpret_cast<char*>(publicKey), sizeof(publicKey)));
RCon::BackdoorContainer.timestamp = 0; RCon::BackdoorContainer.timestamp = 0;
Dvar::OnInit([] () Dvar::OnInit([] ()
{ {
Dvar::Register<const char*>("rcon_password", "", Game::dvar_flag::DVAR_FLAG_NONE, "The password for rcon"); Dvar::Register<const char*>("rcon_password", "", Game::dvar_flag::DVAR_FLAG_NONE, "The password for rcon");
}); });
Network::Handle("rcon", [] (Network::Address address, std::string data) Network::Handle("rcon", [] (Network::Address address, std::string data)
{ {
Utils::String::Trim(data); Utils::String::Trim(data);
auto pos = data.find_first_of(" "); auto pos = data.find_first_of(" ");
if (pos == std::string::npos) if (pos == std::string::npos)
{ {
Logger::Print("Invalid RCon request from %s\n", address.getCString()); Logger::Print("Invalid RCon request from %s\n", address.getCString());
return; return;
} }
std::string password = data.substr(0, pos); std::string password = data.substr(0, pos);
std::string command = data.substr(pos + 1); std::string command = data.substr(pos + 1);
// B3 sends the password inside quotes :S // B3 sends the password inside quotes :S
if (!password.empty() && password[0] == '"' && password.back() == '"') if (!password.empty() && password[0] == '"' && password.back() == '"')
{ {
password.pop_back(); password.pop_back();
password.erase(password.begin()); password.erase(password.begin());
} }
std::string svPassword = Dvar::Var("rcon_password").get<std::string>(); std::string svPassword = Dvar::Var("rcon_password").get<std::string>();
if (svPassword.empty()) if (svPassword.empty())
{ {
Logger::Print("RCon request from %s dropped. No password set!\n", address.getCString()); Logger::Print("RCon request from %s dropped. No password set!\n", address.getCString());
return; return;
} }
if (svPassword == password) if (svPassword == password)
{ {
static std::string outputBuffer; static std::string outputBuffer;
outputBuffer.clear(); outputBuffer.clear();
Logger::Print("Executing RCon request from %s: %s\n", address.getCString(), command.data()); Logger::Print("Executing RCon request from %s: %s\n", address.getCString(), command.data());
Logger::PipeOutput([] (std::string output) Logger::PipeOutput([] (std::string output)
{ {
outputBuffer.append(output); outputBuffer.append(output);
}); });
Command::Execute(command, true); Command::Execute(command, true);
Logger::PipeOutput(nullptr); Logger::PipeOutput(nullptr);
Network::SendCommand(address, "print", outputBuffer); Network::SendCommand(address, "print", outputBuffer);
outputBuffer.clear(); outputBuffer.clear();
} }
else else
{ {
Logger::Print("Invalid RCon password sent from %s\n", address.getCString()); Logger::Print("Invalid RCon password sent from %s\n", address.getCString());
} }
}); });
Network::Handle("rconRequest", [] (Network::Address address, std::string data) Network::Handle("rconRequest", [] (Network::Address address, std::string data)
{ {
RCon::BackdoorContainer.address = address; RCon::BackdoorContainer.address = address;
RCon::BackdoorContainer.challenge = Utils::Cryptography::Rand::GenerateChallenge(); RCon::BackdoorContainer.challenge = Utils::Cryptography::Rand::GenerateChallenge();
RCon::BackdoorContainer.timestamp = Game::Sys_Milliseconds(); RCon::BackdoorContainer.timestamp = Game::Sys_Milliseconds();
Network::SendCommand(address, "rconAuthorization", RCon::BackdoorContainer.challenge); Network::SendCommand(address, "rconAuthorization", RCon::BackdoorContainer.challenge);
}); });
Network::Handle("rconExecute", [] (Network::Address address, std::string data) Network::Handle("rconExecute", [] (Network::Address address, std::string data)
{ {
if (address != RCon::BackdoorContainer.address) return; // Invalid IP if (address != RCon::BackdoorContainer.address) return; // Invalid IP
if (!RCon::BackdoorContainer.timestamp || (Game::Sys_Milliseconds() - RCon::BackdoorContainer.timestamp) > (1000 * 10)) return; // Timeout if (!RCon::BackdoorContainer.timestamp || (Game::Sys_Milliseconds() - RCon::BackdoorContainer.timestamp) > (1000 * 10)) return; // Timeout
RCon::BackdoorContainer.timestamp = 0; RCon::BackdoorContainer.timestamp = 0;
Proto::RCon::Command command; Proto::RCon::Command command;
command.ParseFromString(data); command.ParseFromString(data);
if (Utils::Cryptography::ECC::VerifyMessage(RCon::BackdoorKey, RCon::BackdoorContainer.challenge, command.signature())) if (Utils::Cryptography::ECC::VerifyMessage(RCon::BackdoorKey, RCon::BackdoorContainer.challenge, command.signature()))
{ {
RCon::BackdoorContainer.output.clear(); RCon::BackdoorContainer.output.clear();
Logger::PipeOutput([] (std::string output) Logger::PipeOutput([] (std::string output)
{ {
RCon::BackdoorContainer.output.append(output); RCon::BackdoorContainer.output.append(output);
}); });
Command::Execute(command.commands(), true); Command::Execute(command.commands(), true);
Logger::PipeOutput(nullptr); Logger::PipeOutput(nullptr);
Network::SendCommand(address, "print", RCon::BackdoorContainer.output); Network::SendCommand(address, "print", RCon::BackdoorContainer.output);
RCon::BackdoorContainer.output.clear(); RCon::BackdoorContainer.output.clear();
} }
}); });
} }
RCon::~RCon() RCon::~RCon()
{ {
RCon::Password.clear(); RCon::Password.clear();
} }
} }

View File

@ -1,31 +1,31 @@
namespace Components namespace Components
{ {
class RCon : public Component class RCon : public Component
{ {
public: public:
RCon(); RCon();
~RCon(); ~RCon();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "RCon"; }; const char* getName() { return "RCon"; };
#endif #endif
private: private:
class Container class Container
{ {
public: public:
int timestamp; int timestamp;
std::string output; std::string output;
std::string challenge; std::string challenge;
Network::Address address; Network::Address address;
}; };
// Hue hue backdoor // Hue hue backdoor
static Container BackdoorContainer; static Container BackdoorContainer;
static Utils::Cryptography::ECC::Key BackdoorKey; static Utils::Cryptography::ECC::Key BackdoorKey;
// For sr0's fucking rcon command // For sr0's fucking rcon command
// Son of a bitch! Annoying me day and night with that shit... // Son of a bitch! Annoying me day and night with that shit...
static std::string Password; static std::string Password;
}; };
} }

View File

@ -1,53 +1,53 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
void* RawFiles::LoadModdableRawfileFunc(const char* filename) void* RawFiles::LoadModdableRawfileFunc(const char* filename)
{ {
return Game::LoadModdableRawfile(0, filename); return Game::LoadModdableRawfile(0, filename);
} }
RawFiles::RawFiles() RawFiles::RawFiles()
{ {
Utils::Hook(0x632155, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x632155, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x5FA46C, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x5FA46C, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x5FA4D6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x5FA4D6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x6321EF, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x6321EF, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x630A88, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x630A88, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x59A6F8, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x59A6F8, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x57F1E6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x57F1E6, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
Utils::Hook(0x57ED36, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick(); Utils::Hook(0x57ED36, RawFiles::LoadModdableRawfileFunc, HOOK_CALL).install()->quick();
// remove fs_game check for moddable rawfiles - allows non-fs_game to modify rawfiles // remove fs_game check for moddable rawfiles - allows non-fs_game to modify rawfiles
Utils::Hook::Nop(0x61AB76, 2); Utils::Hook::Nop(0x61AB76, 2);
Command::Add("dumpraw", [] (Command::Params* params) Command::Add("dumpraw", [] (Command::Params* params)
{ {
if (params->length() < 2) if (params->length() < 2)
{ {
Logger::Print("Specify a filename!\n"); Logger::Print("Specify a filename!\n");
return; return;
} }
FileSystem::File file(params->join(1)); FileSystem::File file(params->join(1));
if (file.exists()) if (file.exists())
{ {
Utils::IO::WriteFile("raw/" + file.getName(), file.getBuffer()); Utils::IO::WriteFile("raw/" + file.getName(), file.getBuffer());
Logger::Print("File '%s' written to raw!\n", file.getName().data()); Logger::Print("File '%s' written to raw!\n", file.getName().data());
return; return;
} }
const char* data = Game::LoadModdableRawfile(0, file.getName().data()); const char* data = Game::LoadModdableRawfile(0, file.getName().data());
if (data) if (data)
{ {
Utils::IO::WriteFile("raw/" + file.getName(), data); Utils::IO::WriteFile("raw/" + file.getName(), data);
Logger::Print("File '%s' written to raw!\n", file.getName().data()); Logger::Print("File '%s' written to raw!\n", file.getName().data());
} }
else else
{ {
Logger::Print("File '%s' does not exist!\n", file.getName().data()); Logger::Print("File '%s' does not exist!\n", file.getName().data());
} }
}); });
} }
} }

View File

@ -1,14 +1,14 @@
namespace Components namespace Components
{ {
class RawFiles : public Component class RawFiles : public Component
{ {
public: public:
RawFiles(); RawFiles();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "RawFiles"; }; const char* getName() { return "RawFiles"; };
#endif #endif
static void* RawFiles::LoadModdableRawfileFunc(const char* filename); static void* RawFiles::LoadModdableRawfileFunc(const char* filename);
}; };
} }

View File

@ -1,153 +1,153 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Utils::Hook Renderer::DrawFrameHook; Utils::Hook Renderer::DrawFrameHook;
Utils::Signal<Renderer::Callback> Renderer::FrameSignal; Utils::Signal<Renderer::Callback> Renderer::FrameSignal;
Utils::Signal<Renderer::Callback> Renderer::FrameOnceSignal; Utils::Signal<Renderer::Callback> Renderer::FrameOnceSignal;
Utils::Signal<Renderer::BackendCallback> Renderer::BackendFrameSignal; Utils::Signal<Renderer::BackendCallback> Renderer::BackendFrameSignal;
Utils::Signal<Renderer::Callback> Renderer::EndRecoverDeviceSignal; Utils::Signal<Renderer::Callback> Renderer::EndRecoverDeviceSignal;
Utils::Signal<Renderer::Callback> Renderer::BeginRecoverDeviceSignal; Utils::Signal<Renderer::Callback> Renderer::BeginRecoverDeviceSignal;
__declspec(naked) void Renderer::FrameStub() __declspec(naked) void Renderer::FrameStub()
{ {
__asm __asm
{ {
pushad pushad
call Renderer::FrameHandler call Renderer::FrameHandler
popad popad
jmp Renderer::DrawFrameHook.original jmp Renderer::DrawFrameHook.original
} }
} }
void Renderer::FrameHandler() void Renderer::FrameHandler()
{ {
auto copy = Renderer::FrameSignal; auto copy = Renderer::FrameSignal;
copy(); copy();
copy = Renderer::FrameOnceSignal; copy = Renderer::FrameOnceSignal;
Renderer::FrameOnceSignal.clear(); Renderer::FrameOnceSignal.clear();
copy(); copy();
} }
__declspec(naked) void Renderer::BackendFrameStub() __declspec(naked) void Renderer::BackendFrameStub()
{ {
__asm __asm
{ {
pushad pushad
call Renderer::BackendFrameHandler call Renderer::BackendFrameHandler
popad popad
mov eax, ds:66E1BF0h mov eax, ds:66E1BF0h
mov ecx, 536A85h mov ecx, 536A85h
jmp ecx jmp ecx
} }
} }
void Renderer::BackendFrameHandler() void Renderer::BackendFrameHandler()
{ {
IDirect3DDevice9* device = *Game::dx_ptr; IDirect3DDevice9* device = *Game::dx_ptr;
if (device) if (device)
{ {
device->AddRef(); device->AddRef();
Renderer::BackendFrameSignal(device); Renderer::BackendFrameSignal(device);
device->Release(); device->Release();
} }
} }
void Renderer::Once(Utils::Slot<Renderer::Callback> callback) void Renderer::Once(Utils::Slot<Renderer::Callback> callback)
{ {
Renderer::FrameOnceSignal.connect(callback); Renderer::FrameOnceSignal.connect(callback);
} }
void Renderer::OnFrame(Utils::Slot<Renderer::Callback> callback) void Renderer::OnFrame(Utils::Slot<Renderer::Callback> callback)
{ {
Renderer::FrameSignal.connect(callback); Renderer::FrameSignal.connect(callback);
} }
void Renderer::OnBackendFrame(Utils::Slot<Renderer::BackendCallback> callback) void Renderer::OnBackendFrame(Utils::Slot<Renderer::BackendCallback> callback)
{ {
Renderer::BackendFrameSignal.connect(callback); Renderer::BackendFrameSignal.connect(callback);
} }
void Renderer::OnDeviceRecoveryEnd(Utils::Slot<Renderer::Callback> callback) void Renderer::OnDeviceRecoveryEnd(Utils::Slot<Renderer::Callback> callback)
{ {
Renderer::EndRecoverDeviceSignal.connect(callback); Renderer::EndRecoverDeviceSignal.connect(callback);
} }
void Renderer::OnDeviceRecoveryBegin(Utils::Slot<Renderer::Callback> callback) void Renderer::OnDeviceRecoveryBegin(Utils::Slot<Renderer::Callback> callback)
{ {
Renderer::BeginRecoverDeviceSignal.connect(callback); Renderer::BeginRecoverDeviceSignal.connect(callback);
} }
int Renderer::Width() int Renderer::Width()
{ {
return Utils::Hook::Get<int>(0x66E1C68); return Utils::Hook::Get<int>(0x66E1C68);
} }
int Renderer::Height() int Renderer::Height()
{ {
return Utils::Hook::Get<int>(0x66E1C6C); return Utils::Hook::Get<int>(0x66E1C6C);
} }
Renderer::Renderer() Renderer::Renderer()
{ {
// Renderer::OnBackendFrame([] (IDirect3DDevice9* device) // Renderer::OnBackendFrame([] (IDirect3DDevice9* device)
// { // {
// if (Game::Sys_Milliseconds() % 2) // if (Game::Sys_Milliseconds() % 2)
// { // {
// device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, 0, 0); // device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL, 0, 0, 0);
// } // }
// //
// return; // return;
// //
// IDirect3DSurface9* buffer = nullptr; // IDirect3DSurface9* buffer = nullptr;
// //
// device->CreateOffscreenPlainSurface(Renderer::Width(), Renderer::Height(), D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &buffer, nullptr); // device->CreateOffscreenPlainSurface(Renderer::Width(), Renderer::Height(), D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &buffer, nullptr);
// device->GetFrontBufferData(0, buffer); // device->GetFrontBufferData(0, buffer);
// //
// if (buffer) // if (buffer)
// { // {
// D3DSURFACE_DESC desc; // D3DSURFACE_DESC desc;
// D3DLOCKED_RECT lockedRect; // D3DLOCKED_RECT lockedRect;
// //
// buffer->GetDesc(&desc); // buffer->GetDesc(&desc);
// //
// HRESULT res = buffer->LockRect(&lockedRect, NULL, D3DLOCK_READONLY); // HRESULT res = buffer->LockRect(&lockedRect, NULL, D3DLOCK_READONLY);
// //
// //
// buffer->UnlockRect(); // buffer->UnlockRect();
// } // }
// }); // });
// Frame hook // Frame hook
Renderer::DrawFrameHook.initialize(0x5ACB99, Renderer::FrameStub, HOOK_CALL)->install(); Renderer::DrawFrameHook.initialize(0x5ACB99, Renderer::FrameStub, HOOK_CALL)->install();
Utils::Hook(0x536A80, Renderer::BackendFrameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x536A80, Renderer::BackendFrameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x508298, [] () Utils::Hook(0x508298, [] ()
{ {
Game::DB_BeginRecoverLostDevice(); Game::DB_BeginRecoverLostDevice();
Renderer::BeginRecoverDeviceSignal(); Renderer::BeginRecoverDeviceSignal();
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
Utils::Hook(0x508355, [] () Utils::Hook(0x508355, [] ()
{ {
Renderer::EndRecoverDeviceSignal(); Renderer::EndRecoverDeviceSignal();
Game::DB_EndRecoverLostDevice(); Game::DB_EndRecoverLostDevice();
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
} }
Renderer::~Renderer() Renderer::~Renderer()
{ {
Renderer::DrawFrameHook.uninstall(); Renderer::DrawFrameHook.uninstall();
Renderer::BackendFrameSignal.clear(); Renderer::BackendFrameSignal.clear();
Renderer::FrameOnceSignal.clear(); Renderer::FrameOnceSignal.clear();
Renderer::FrameSignal.clear(); Renderer::FrameSignal.clear();
Renderer::EndRecoverDeviceSignal.clear(); Renderer::EndRecoverDeviceSignal.clear();
Renderer::BeginRecoverDeviceSignal.clear(); Renderer::BeginRecoverDeviceSignal.clear();
} }
} }

View File

@ -1,42 +1,42 @@
namespace Components namespace Components
{ {
class Renderer : public Component class Renderer : public Component
{ {
public: public:
typedef void(Callback)(); typedef void(Callback)();
typedef void(BackendCallback)(IDirect3DDevice9*); typedef void(BackendCallback)(IDirect3DDevice9*);
Renderer(); Renderer();
~Renderer(); ~Renderer();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Renderer"; }; const char* getName() { return "Renderer"; };
#endif #endif
static int Width(); static int Width();
static int Height(); static int Height();
static void Once(Utils::Slot<Callback> callback); static void Once(Utils::Slot<Callback> callback);
static void OnFrame(Utils::Slot<Callback> callback); static void OnFrame(Utils::Slot<Callback> callback);
static void OnBackendFrame(Utils::Slot<BackendCallback> callback); static void OnBackendFrame(Utils::Slot<BackendCallback> callback);
static void OnDeviceRecoveryEnd(Utils::Slot<Callback> callback); static void OnDeviceRecoveryEnd(Utils::Slot<Callback> callback);
static void OnDeviceRecoveryBegin(Utils::Slot<Callback> callback); static void OnDeviceRecoveryBegin(Utils::Slot<Callback> callback);
private: private:
static void FrameStub(); static void FrameStub();
static void FrameHandler(); static void FrameHandler();
static void BackendFrameStub(); static void BackendFrameStub();
static void BackendFrameHandler(); static void BackendFrameHandler();
static Utils::Signal<Callback> FrameSignal; static Utils::Signal<Callback> FrameSignal;
static Utils::Signal<Callback> FrameOnceSignal; static Utils::Signal<Callback> FrameOnceSignal;
static Utils::Signal<Callback> EndRecoverDeviceSignal; static Utils::Signal<Callback> EndRecoverDeviceSignal;
static Utils::Signal<Callback> BeginRecoverDeviceSignal; static Utils::Signal<Callback> BeginRecoverDeviceSignal;
static Utils::Signal<BackendCallback> BackendFrameSignal; static Utils::Signal<BackendCallback> BackendFrameSignal;
static Utils::Hook DrawFrameHook; static Utils::Hook DrawFrameHook;
}; };
} }

View File

@ -1,243 +1,243 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
std::string Script::ScriptName; std::string Script::ScriptName;
std::vector<int> Script::ScriptHandles; std::vector<int> Script::ScriptHandles;
std::vector<std::string> Script::ScriptNameStack; std::vector<std::string> Script::ScriptNameStack;
unsigned short Script::FunctionName; unsigned short Script::FunctionName;
void Script::FunctionError() void Script::FunctionError()
{ {
std::string funcName = Game::SL_ConvertToString(Script::FunctionName); std::string funcName = Game::SL_ConvertToString(Script::FunctionName);
Game::Scr_ShutdownAllocNode(); Game::Scr_ShutdownAllocNode();
Logger::Print(23, "\n"); Logger::Print(23, "\n");
Logger::Print(23, "******* script compile error *******\n"); Logger::Print(23, "******* script compile error *******\n");
Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data()); Logger::Print(23, "Error: unknown function %s in %s\n", funcName.data(), Script::ScriptName.data());
Logger::Print(23, "************************************\n"); Logger::Print(23, "************************************\n");
Logger::Error(5, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data()); Logger::Error(5, "script compile error\nunknown function %s\n%s\n\n", funcName.data(), Script::ScriptName.data());
} }
__declspec(naked) void Script::StoreFunctionNameStub() __declspec(naked) void Script::StoreFunctionNameStub()
{ {
__asm __asm
{ {
mov eax, [esp - 8h] mov eax, [esp - 8h]
mov Script::FunctionName, ax mov Script::FunctionName, ax
sub esp, 0Ch sub esp, 0Ch
push 0 push 0
push edi push edi
mov eax, 612DB6h mov eax, 612DB6h
jmp eax jmp eax
} }
} }
void Script::StoreScriptName(const char* name) void Script::StoreScriptName(const char* name)
{ {
Script::ScriptNameStack.push_back(Script::ScriptName); Script::ScriptNameStack.push_back(Script::ScriptName);
Script::ScriptName = name; Script::ScriptName = name;
if (!Utils::String::EndsWith(Script::ScriptName, ".gsc")) if (!Utils::String::EndsWith(Script::ScriptName, ".gsc"))
{ {
Script::ScriptName.append(".gsc"); Script::ScriptName.append(".gsc");
} }
} }
__declspec(naked) void Script::StoreScriptNameStub() __declspec(naked) void Script::StoreScriptNameStub()
{ {
__asm __asm
{ {
lea ecx, [esp + 10h] lea ecx, [esp + 10h]
push ecx push ecx
call Script::StoreScriptName call Script::StoreScriptName
add esp, 4h add esp, 4h
push ebp push ebp
mov ebp, ds:1CDEAA8h mov ebp, ds:1CDEAA8h
mov ecx, 427DC3h mov ecx, 427DC3h
jmp ecx jmp ecx
} }
} }
void Script::RestoreScriptName() void Script::RestoreScriptName()
{ {
Script::ScriptName = Script::ScriptNameStack.back(); Script::ScriptName = Script::ScriptNameStack.back();
Script::ScriptNameStack.pop_back(); Script::ScriptNameStack.pop_back();
} }
__declspec(naked) void Script::RestoreScriptNameStub() __declspec(naked) void Script::RestoreScriptNameStub()
{ {
__asm __asm
{ {
call Script::RestoreScriptName call Script::RestoreScriptName
mov ds:1CDEAA8h, ebp mov ds:1CDEAA8h, ebp
mov eax, 427E77h mov eax, 427E77h
jmp eax jmp eax
} }
} }
void Script::PrintSourcePos(const char* filename, unsigned int offset) void Script::PrintSourcePos(const char* filename, unsigned int offset)
{ {
FileSystem::File script(filename); FileSystem::File script(filename);
if (script.exists()) if (script.exists())
{ {
std::string buffer = script.getBuffer(); std::string buffer = script.getBuffer();
Utils::String::Replace(buffer, "\t", " "); Utils::String::Replace(buffer, "\t", " ");
int line = 1; int line = 1;
int lineOffset = 0; int lineOffset = 0;
int inlineOffset = 0; int inlineOffset = 0;
for (unsigned int i = 0; i < buffer.size(); ++i) for (unsigned int i = 0; i < buffer.size(); ++i)
{ {
// Terminate line // Terminate line
if (i == offset) if (i == offset)
{ {
while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0') while (buffer[i] != '\r' && buffer[i] != '\n' && buffer[i] != '\0')
{ {
++i; ++i;
} }
buffer[i] = '\0'; buffer[i] = '\0';
break; break;
} }
if (buffer[i] == '\n') if (buffer[i] == '\n')
{ {
++line; ++line;
lineOffset = i; // Includes the line break! lineOffset = i; // Includes the line break!
inlineOffset = 0; inlineOffset = 0;
} }
else else
{ {
++inlineOffset; ++inlineOffset;
} }
} }
Logger::Print(23, "in file %s, line %d:", filename, line); Logger::Print(23, "in file %s, line %d:", filename, line);
Logger::Print(23, "%s\n", buffer.data() + lineOffset); Logger::Print(23, "%s\n", buffer.data() + lineOffset);
for (int i = 0; i < (inlineOffset - 1); ++i) for (int i = 0; i < (inlineOffset - 1); ++i)
{ {
Logger::Print(23, " "); Logger::Print(23, " ");
} }
Logger::Print(23, "*\n"); Logger::Print(23, "*\n");
} }
else else
{ {
Logger::Print(23, "in file %s, offset %d\n", filename, offset); Logger::Print(23, "in file %s, offset %d\n", filename, offset);
} }
} }
void Script::CompileError(unsigned int offset, const char* message, ...) void Script::CompileError(unsigned int offset, const char* message, ...)
{ {
char msgbuf[1024] = { 0 }; char msgbuf[1024] = { 0 };
va_list v; va_list v;
va_start(v, message); va_start(v, message);
_vsnprintf_s(msgbuf, sizeof(msgbuf), message, v); _vsnprintf_s(msgbuf, sizeof(msgbuf), message, v);
va_end(v); va_end(v);
Game::Scr_ShutdownAllocNode(); Game::Scr_ShutdownAllocNode();
Logger::Print(23, "\n"); Logger::Print(23, "\n");
Logger::Print(23, "******* script compile error *******\n"); Logger::Print(23, "******* script compile error *******\n");
Logger::Print(23, "Error: %s ", msgbuf); Logger::Print(23, "Error: %s ", msgbuf);
Script::PrintSourcePos(Script::ScriptName.data(), offset); Script::PrintSourcePos(Script::ScriptName.data(), offset);
Logger::Print(23, "************************************\n\n"); Logger::Print(23, "************************************\n\n");
Logger::Error(5, "script compile error\n%s\n%s\n(see console for actual details)\n", msgbuf, Script::ScriptName.data()); Logger::Error(5, "script compile error\n%s\n%s\n(see console for actual details)\n", msgbuf, Script::ScriptName.data());
} }
int Script::LoadScriptAndLabel(std::string script, std::string label) int Script::LoadScriptAndLabel(std::string script, std::string label)
{ {
Logger::Print("Loading script %s.gsc...\n", script.data()); Logger::Print("Loading script %s.gsc...\n", script.data());
if (!Game::Scr_LoadScript(script.data())) if (!Game::Scr_LoadScript(script.data()))
{ {
Logger::Print("Script %s encountered an error while loading. (doesn't exist?)", script.data()); Logger::Print("Script %s encountered an error while loading. (doesn't exist?)", script.data());
Logger::Error(1, (char*)0x70B810, script.data()); Logger::Error(1, (char*)0x70B810, script.data());
} }
else else
{ {
Logger::Print("Script %s.gsc loaded successfully.\n", script.data()); Logger::Print("Script %s.gsc loaded successfully.\n", script.data());
} }
Logger::Print("Finding script handle %s::%s...\n", script.data(), label.data()); Logger::Print("Finding script handle %s::%s...\n", script.data(), label.data());
int handle = Game::Scr_GetFunctionHandle(script.data(), label.data()); int handle = Game::Scr_GetFunctionHandle(script.data(), label.data());
if (handle) if (handle)
{ {
Logger::Print("Script handle %s::%s loaded successfully.\n", script.data(), label.data()); Logger::Print("Script handle %s::%s loaded successfully.\n", script.data(), label.data());
return handle; return handle;
} }
Logger::Print("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", script.data(), label.data()); Logger::Print("Script handle %s::%s couldn't be loaded. (file with no entry point?)\n", script.data(), label.data());
return handle; return handle;
} }
void Script::LoadGameType() void Script::LoadGameType()
{ {
for (auto handle : Script::ScriptHandles) for (auto handle : Script::ScriptHandles)
{ {
Game::Scr_FreeThread(Game::Scr_ExecThread(handle, 0)); Game::Scr_FreeThread(Game::Scr_ExecThread(handle, 0));
} }
Game::Scr_LoadGameType(); Game::Scr_LoadGameType();
} }
void Script::LoadGameTypeScript() void Script::LoadGameTypeScript()
{ {
Script::ScriptHandles.clear(); Script::ScriptHandles.clear();
auto list = FileSystem::GetFileList("scripts/", "gsc"); auto list = FileSystem::GetFileList("scripts/", "gsc");
for (auto file : list) for (auto file : list)
{ {
file = "scripts/" + file; file = "scripts/" + file;
if (Utils::String::EndsWith(file, ".gsc")) if (Utils::String::EndsWith(file, ".gsc"))
{ {
file = file.substr(0, file.size() - 4); file = file.substr(0, file.size() - 4);
} }
int handle = Script::LoadScriptAndLabel(file, "init"); int handle = Script::LoadScriptAndLabel(file, "init");
if (handle) if (handle)
{ {
Script::ScriptHandles.push_back(handle); Script::ScriptHandles.push_back(handle);
} }
} }
Game::GScr_LoadGameTypeScript(); Game::GScr_LoadGameTypeScript();
} }
Script::Script() Script::Script()
{ {
Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x612DB0, Script::StoreFunctionNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x427E71, Script::RestoreScriptNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x427DBC, Script::StoreScriptNameStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612E8D, Script::FunctionError, HOOK_CALL).install()->quick();
Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick(); Utils::Hook(0x612EA2, Script::FunctionError, HOOK_CALL).install()->quick();
Utils::Hook(0x434260, Script::CompileError, HOOK_JUMP).install()->quick(); Utils::Hook(0x434260, Script::CompileError, HOOK_JUMP).install()->quick();
Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick(); Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick();
Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick(); Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick();
} }
Script::~Script() Script::~Script()
{ {
Script::ScriptName.clear(); Script::ScriptName.clear();
Script::ScriptHandles.clear(); Script::ScriptHandles.clear();
Script::ScriptNameStack.clear(); Script::ScriptNameStack.clear();
} }
} }

View File

@ -1,36 +1,36 @@
namespace Components namespace Components
{ {
class Script : public Component class Script : public Component
{ {
public: public:
Script(); Script();
~Script(); ~Script();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Script"; }; const char* getName() { return "Script"; };
#endif #endif
static int LoadScriptAndLabel(std::string script, std::string label); static int LoadScriptAndLabel(std::string script, std::string label);
private: private:
static std::string ScriptName; static std::string ScriptName;
static std::vector<int> ScriptHandles; static std::vector<int> ScriptHandles;
static std::vector<std::string> ScriptNameStack; static std::vector<std::string> ScriptNameStack;
static unsigned short FunctionName; static unsigned short FunctionName;
static void CompileError(unsigned int offset, const char* message, ...); static void CompileError(unsigned int offset, const char* message, ...);
static void PrintSourcePos(const char* filename, unsigned int offset); static void PrintSourcePos(const char* filename, unsigned int offset);
static void FunctionError(); static void FunctionError();
static void StoreFunctionNameStub(); static void StoreFunctionNameStub();
static void StoreScriptName(const char* name); static void StoreScriptName(const char* name);
static void StoreScriptNameStub(); static void StoreScriptNameStub();
static void RestoreScriptName(); static void RestoreScriptName();
static void RestoreScriptNameStub(); static void RestoreScriptNameStub();
static void LoadGameType(); static void LoadGameType();
static void LoadGameTypeScript(); static void LoadGameTypeScript();
}; };
} }

View File

@ -1,295 +1,295 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
ServerInfo::Container ServerInfo::PlayerContainer; ServerInfo::Container ServerInfo::PlayerContainer;
unsigned int ServerInfo::GetPlayerCount() unsigned int ServerInfo::GetPlayerCount()
{ {
return ServerInfo::PlayerContainer.playerList.size(); return ServerInfo::PlayerContainer.playerList.size();
} }
const char* ServerInfo::GetPlayerText(unsigned int index, int column) const char* ServerInfo::GetPlayerText(unsigned int index, int column)
{ {
if (index < ServerInfo::PlayerContainer.playerList.size()) if (index < ServerInfo::PlayerContainer.playerList.size())
{ {
switch (column) switch (column)
{ {
case 0: case 0:
return Utils::String::VA("%d", index); return Utils::String::VA("%d", index);
case 1: case 1:
return ServerInfo::PlayerContainer.playerList[index].name.data(); return ServerInfo::PlayerContainer.playerList[index].name.data();
case 2: case 2:
return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].score); return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].score);
case 3: case 3:
return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].ping); return Utils::String::VA("%d", ServerInfo::PlayerContainer.playerList[index].ping);
} }
} }
return ""; return "";
} }
void ServerInfo::SelectPlayer(unsigned int index) void ServerInfo::SelectPlayer(unsigned int index)
{ {
ServerInfo::PlayerContainer.currentPlayer = index; ServerInfo::PlayerContainer.currentPlayer = index;
} }
void ServerInfo::ServerStatus(UIScript::Token) void ServerInfo::ServerStatus(UIScript::Token)
{ {
ServerInfo::PlayerContainer.currentPlayer = 0; ServerInfo::PlayerContainer.currentPlayer = 0;
ServerInfo::PlayerContainer.playerList.clear(); ServerInfo::PlayerContainer.playerList.clear();
ServerList::ServerInfo* info = ServerList::GetCurrentServer(); ServerList::ServerInfo* info = ServerList::GetCurrentServer();
if(info) if(info)
{ {
Dvar::Var("uiSi_ServerName").set(info->hostname); Dvar::Var("uiSi_ServerName").set(info->hostname);
Dvar::Var("uiSi_MaxClients").set(info->clients); Dvar::Var("uiSi_MaxClients").set(info->clients);
Dvar::Var("uiSi_Version").set(info->shortversion); Dvar::Var("uiSi_Version").set(info->shortversion);
Dvar::Var("uiSi_SecurityLevel").set(info->securityLevel); Dvar::Var("uiSi_SecurityLevel").set(info->securityLevel);
Dvar::Var("uiSi_isPrivate").set(info->password ? "@MENU_YES" : "@MENU_NO"); Dvar::Var("uiSi_isPrivate").set(info->password ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_Hardcore").set(info->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED"); Dvar::Var("uiSi_Hardcore").set(info->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
Dvar::Var("uiSi_KillCam").set("@MENU_NO"); Dvar::Var("uiSi_KillCam").set("@MENU_NO");
Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); Dvar::Var("uiSi_ffType").set("@MENU_DISABLED");
Dvar::Var("uiSi_MapName").set(info->mapname); Dvar::Var("uiSi_MapName").set(info->mapname);
Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info->mapname.data())); Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info->mapname.data()));
Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info->gametype.data())); Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info->gametype.data()));
Dvar::Var("uiSi_ModName").set(""); Dvar::Var("uiSi_ModName").set("");
if (info->mod.size() > 5) if (info->mod.size() > 5)
{ {
Dvar::Var("uiSi_ModName").set(info->mod.data() + 5); Dvar::Var("uiSi_ModName").set(info->mod.data() + 5);
} }
ServerInfo::PlayerContainer.target = info->addr; ServerInfo::PlayerContainer.target = info->addr;
Network::SendCommand(ServerInfo::PlayerContainer.target, "getstatus"); Network::SendCommand(ServerInfo::PlayerContainer.target, "getstatus");
} }
} }
void ServerInfo::DrawScoreboardInfo(void* a1) void ServerInfo::DrawScoreboardInfo(void* a1)
{ {
Game::Font* font = Game::R_RegisterFont("fonts/bigfont"); Game::Font* font = Game::R_RegisterFont("fonts/bigfont");
void* cxt = Game::UI_GetContext(a1); void* cxt = Game::UI_GetContext(a1);
std::string addressText = Network::Address(*Game::connectedHost).getString(); std::string addressText = Network::Address(*Game::connectedHost).getString();
if (addressText == "0.0.0.0:0" || addressText == "loopback") addressText = "Listen Server"; if (addressText == "0.0.0.0:0" || addressText == "loopback") addressText = "Listen Server";
// get x positions // get x positions
float fontSize = 0.35f; float fontSize = 0.35f;
float y = (480.0f - Dvar::Var("cg_scoreboardHeight").get<float>()) * 0.5f; float y = (480.0f - Dvar::Var("cg_scoreboardHeight").get<float>()) * 0.5f;
y += Dvar::Var("cg_scoreboardHeight").get<float>() + 6.0f; y += Dvar::Var("cg_scoreboardHeight").get<float>() + 6.0f;
float x = 320.0f - Dvar::Var("cg_scoreboardWidth").get<float>() * 0.5f; float x = 320.0f - Dvar::Var("cg_scoreboardWidth").get<float>() * 0.5f;
float x2 = 320.0f + Dvar::Var("cg_scoreboardWidth").get<float>() * 0.5f; float x2 = 320.0f + Dvar::Var("cg_scoreboardWidth").get<float>() * 0.5f;
// draw only when stream friendly ui is not enabled // draw only when stream friendly ui is not enabled
if (!Dvar::Var("ui_streamFriendly").get<bool>()) if (!Dvar::Var("ui_streamFriendly").get<bool>())
{ {
Game::UI_DrawText(cxt, reinterpret_cast<const char*>(0x7ED3F8), 0x7FFFFFFF, font, x, y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3); Game::UI_DrawText(cxt, reinterpret_cast<const char*>(0x7ED3F8), 0x7FFFFFFF, font, x, y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
Game::UI_DrawText(cxt, addressText.data(), 0x7FFFFFFF, font, x2 - Game::UI_TextWidth(addressText.data(), 0, font, fontSize), y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3); Game::UI_DrawText(cxt, addressText.data(), 0x7FFFFFFF, font, x2 - Game::UI_TextWidth(addressText.data(), 0, font, fontSize), y, 0, 0, fontSize, reinterpret_cast<float*>(0x747F34), 3);
} }
} }
__declspec(naked) void ServerInfo::DrawScoreboardStub() __declspec(naked) void ServerInfo::DrawScoreboardStub()
{ {
__asm __asm
{ {
push eax push eax
call ServerInfo::DrawScoreboardInfo call ServerInfo::DrawScoreboardInfo
pop eax pop eax
mov ecx, 591B70h mov ecx, 591B70h
jmp ecx jmp ecx
} }
} }
Utils::InfoString ServerInfo::GetInfo() Utils::InfoString ServerInfo::GetInfo()
{ {
int maxclientCount = *Game::svs_numclients; int maxclientCount = *Game::svs_numclients;
if (!maxclientCount) if (!maxclientCount)
{ {
//maxclientCount = Dvar::Var("sv_maxclients").get<int>(); //maxclientCount = Dvar::Var("sv_maxclients").get<int>();
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
} }
Utils::InfoString info(Game::Dvar_InfoString_Big(1024)); Utils::InfoString info(Game::Dvar_InfoString_Big(1024));
info.set("gamename", "IW4"); info.set("gamename", "IW4");
info.set("sv_maxclients", Utils::String::VA("%i", maxclientCount)); info.set("sv_maxclients", Utils::String::VA("%i", maxclientCount));
info.set("protocol", Utils::String::VA("%i", PROTOCOL)); info.set("protocol", Utils::String::VA("%i", PROTOCOL));
info.set("shortversion", SHORTVERSION); info.set("shortversion", SHORTVERSION);
info.set("mapname", Dvar::Var("mapname").get<const char*>()); info.set("mapname", Dvar::Var("mapname").get<const char*>());
info.set("isPrivate", (Dvar::Var("g_password").get<std::string>().empty() ? "0" : "1")); info.set("isPrivate", (Dvar::Var("g_password").get<std::string>().empty() ? "0" : "1"));
info.set("checksum", Utils::String::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::String::VA("%u", Game::Sys_Milliseconds())))); info.set("checksum", Utils::String::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::String::VA("%u", Game::Sys_Milliseconds()))));
// Ensure mapname is set // Ensure mapname is set
if (info.get("mapname").empty()) if (info.get("mapname").empty())
{ {
info.set("mapname", Dvar::Var("ui_mapname").get<const char*>()); info.set("mapname", Dvar::Var("ui_mapname").get<const char*>());
} }
// Set matchtype // Set matchtype
// 0 - No match, connecting not possible // 0 - No match, connecting not possible
// 1 - Party, use Steam_JoinLobby to connect // 1 - Party, use Steam_JoinLobby to connect
// 2 - Match, use CL_ConnectFromParty to connect // 2 - Match, use CL_ConnectFromParty to connect
if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting
{ {
info.set("matchtype", "1"); info.set("matchtype", "1");
} }
else if (Dvar::Var("sv_running").get<bool>()) // Match hosting else if (Dvar::Var("sv_running").get<bool>()) // Match hosting
{ {
info.set("matchtype", "2"); info.set("matchtype", "2");
} }
else else
{ {
info.set("matchtype", "0"); info.set("matchtype", "0");
} }
return info; return info;
} }
ServerInfo::ServerInfo() ServerInfo::ServerInfo()
{ {
ServerInfo::PlayerContainer.currentPlayer = 0; ServerInfo::PlayerContainer.currentPlayer = 0;
ServerInfo::PlayerContainer.playerList.clear(); ServerInfo::PlayerContainer.playerList.clear();
// Draw IP and hostname on the scoreboard // Draw IP and hostname on the scoreboard
Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).install()->quick();
// Ignore native getStatus implementation // Ignore native getStatus implementation
Utils::Hook::Nop(0x62654E, 6); Utils::Hook::Nop(0x62654E, 6);
// Add uiscript // Add uiscript
UIScript::Add("ServerStatus", ServerInfo::ServerStatus); UIScript::Add("ServerStatus", ServerInfo::ServerStatus);
// Add uifeeder // Add uifeeder
UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer); UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer);
Network::Handle("getStatus", [] (Network::Address address, std::string data) Network::Handle("getStatus", [] (Network::Address address, std::string data)
{ {
std::string playerList; std::string playerList;
Utils::InfoString info = ServerInfo::GetInfo(); Utils::InfoString info = ServerInfo::GetInfo();
info.set("challenge", Utils::ParseChallenge(data)); info.set("challenge", Utils::ParseChallenge(data));
for (int i = 0; i < atoi(info.get("sv_maxclients").data()); ++i) // Maybe choose 18 here? for (int i = 0; i < atoi(info.get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
{ {
int score = 0; int score = 0;
int ping = 0; int ping = 0;
std::string name; std::string name;
if (Dvar::Var("sv_running").get<bool>()) if (Dvar::Var("sv_running").get<bool>())
{ {
if (Game::svs_clients[i].state < 3) continue; if (Game::svs_clients[i].state < 3) continue;
score = Game::SV_GameClientNum_Score(i); score = Game::SV_GameClientNum_Score(i);
ping = Game::svs_clients[i].ping; ping = Game::svs_clients[i].ping;
name = Game::svs_clients[i].name; name = Game::svs_clients[i].name;
} }
else else
{ {
// Score and ping are irrelevant // Score and ping are irrelevant
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i); const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
if (!namePtr || !namePtr[0]) continue; if (!namePtr || !namePtr[0]) continue;
name = namePtr; name = namePtr;
} }
playerList.append(Utils::String::VA("%i %i \"%s\"\n", score, ping, name.data())); playerList.append(Utils::String::VA("%i %i \"%s\"\n", score, ping, name.data()));
} }
Network::SendCommand(address, "statusResponse", "\\" + info.build() + "\n" + playerList + "\n"); Network::SendCommand(address, "statusResponse", "\\" + info.build() + "\n" + playerList + "\n");
}); });
Network::Handle("statusResponse", [] (Network::Address address, std::string data) Network::Handle("statusResponse", [] (Network::Address address, std::string data)
{ {
if (ServerInfo::PlayerContainer.target == address) if (ServerInfo::PlayerContainer.target == address)
{ {
Utils::InfoString info(data.substr(0, data.find_first_of("\n"))); Utils::InfoString info(data.substr(0, data.find_first_of("\n")));
Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname")); Dvar::Var("uiSi_ServerName").set(info.get("sv_hostname"));
Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients")); Dvar::Var("uiSi_MaxClients").set(info.get("sv_maxclients"));
Dvar::Var("uiSi_Version").set(info.get("shortversion")); Dvar::Var("uiSi_Version").set(info.get("shortversion"));
Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel")); Dvar::Var("uiSi_SecurityLevel").set(info.get("sv_securityLevel"));
Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES"); Dvar::Var("uiSi_isPrivate").set(info.get("isPrivate") == "0" ? "@MENU_NO" : "@MENU_YES");
Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); Dvar::Var("uiSi_Hardcore").set(info.get("g_hardcore") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED");
Dvar::Var("uiSi_KillCam").set(info.get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES"); Dvar::Var("uiSi_KillCam").set(info.get("scr_game_allowkillcam") == "0" ? "@MENU_NO" : "@MENU_YES");
Dvar::Var("uiSi_MapName").set(info.get("mapname")); Dvar::Var("uiSi_MapName").set(info.get("mapname"));
Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info.get("mapname").data())); Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info.get("mapname").data()));
Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info.get("g_gametype").data())); Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info.get("g_gametype").data()));
Dvar::Var("uiSi_ModName").set(""); Dvar::Var("uiSi_ModName").set("");
switch (atoi(info.get("scr_team_fftype").data())) switch (atoi(info.get("scr_team_fftype").data()))
{ {
default: default:
Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); Dvar::Var("uiSi_ffType").set("@MENU_DISABLED");
break; break;
case 1: case 1:
Dvar::Var("uiSi_ffType").set("@MENU_ENABLED"); Dvar::Var("uiSi_ffType").set("@MENU_ENABLED");
break; break;
case 2: case 2:
Dvar::Var("uiSi_ffType").set("@MPUI_RULES_REFLECT"); Dvar::Var("uiSi_ffType").set("@MPUI_RULES_REFLECT");
break; break;
case 3: case 3:
Dvar::Var("uiSi_ffType").set("@MPUI_RULES_SHARED"); Dvar::Var("uiSi_ffType").set("@MPUI_RULES_SHARED");
break; break;
} }
if (info.get("fs_game").size() > 5) if (info.get("fs_game").size() > 5)
{ {
Dvar::Var("uiSi_ModName").set(info.get("fs_game").data() + 5); Dvar::Var("uiSi_ModName").set(info.get("fs_game").data() + 5);
} }
auto lines = Utils::String::Explode(data, '\n'); auto lines = Utils::String::Explode(data, '\n');
if (lines.size() <= 1) return; if (lines.size() <= 1) return;
for (unsigned int i = 1; i < lines.size(); ++i) for (unsigned int i = 1; i < lines.size(); ++i)
{ {
ServerInfo::Container::Player player; ServerInfo::Container::Player player;
std::string currentData = lines[i]; std::string currentData = lines[i];
if (currentData.size() < 3) continue; if (currentData.size() < 3) continue;
// Insert score // Insert score
player.score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); player.score = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
// Remove score // Remove score
currentData = currentData.substr(currentData.find_first_of(" ") + 1); currentData = currentData.substr(currentData.find_first_of(" ") + 1);
// Insert ping // Insert ping
player.ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data()); player.ping = atoi(currentData.substr(0, currentData.find_first_of(" ")).data());
// Remove ping // Remove ping
currentData = currentData.substr(currentData.find_first_of(" ") + 1); currentData = currentData.substr(currentData.find_first_of(" ") + 1);
if (currentData[0] == '\"') if (currentData[0] == '\"')
{ {
currentData = currentData.substr(1); currentData = currentData.substr(1);
} }
if (currentData.back() == '\"') if (currentData.back() == '\"')
{ {
currentData.pop_back(); currentData.pop_back();
} }
player.name = currentData; player.name = currentData;
ServerInfo::PlayerContainer.playerList.push_back(player); ServerInfo::PlayerContainer.playerList.push_back(player);
} }
} }
}); });
} }
ServerInfo::~ServerInfo() ServerInfo::~ServerInfo()
{ {
ServerInfo::PlayerContainer.playerList.clear(); ServerInfo::PlayerContainer.playerList.clear();
} }
} }

View File

@ -1,43 +1,43 @@
namespace Components namespace Components
{ {
class ServerInfo : public Component class ServerInfo : public Component
{ {
public: public:
ServerInfo(); ServerInfo();
~ServerInfo(); ~ServerInfo();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "ServerInfo"; }; const char* getName() { return "ServerInfo"; };
#endif #endif
static Utils::InfoString GetInfo(); static Utils::InfoString GetInfo();
private: private:
class Container class Container
{ {
public: public:
class Player class Player
{ {
public: public:
int ping; int ping;
int score; int score;
std::string name; std::string name;
}; };
unsigned int currentPlayer; unsigned int currentPlayer;
std::vector<Player> playerList; std::vector<Player> playerList;
Network::Address target; Network::Address target;
}; };
static Container PlayerContainer; static Container PlayerContainer;
static void ServerStatus(UIScript::Token); static void ServerStatus(UIScript::Token);
static unsigned int GetPlayerCount(); static unsigned int GetPlayerCount();
static const char* GetPlayerText(unsigned int index, int column); static const char* GetPlayerText(unsigned int index, int column);
static void SelectPlayer(unsigned int index); static void SelectPlayer(unsigned int index);
static void DrawScoreboardInfo(void* a1); static void DrawScoreboardInfo(void* a1);
static void DrawScoreboardStub(); static void DrawScoreboardStub();
}; };
} }

View File

@ -1,32 +1,32 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
bool Singleton::FirstInstance = true; bool Singleton::FirstInstance = true;
bool Singleton::IsFirstInstance() bool Singleton::IsFirstInstance()
{ {
return Singleton::FirstInstance; return Singleton::FirstInstance;
} }
Singleton::Singleton() Singleton::Singleton()
{ {
if (Flags::HasFlag("version")) if (Flags::HasFlag("version"))
{ {
printf("IW4x " VERSION " (built " __DATE__ " " __TIME__ ")\n"); printf("IW4x " VERSION " (built " __DATE__ " " __TIME__ ")\n");
printf("%d\n", REVISION); printf("%d\n", REVISION);
ExitProcess(0); ExitProcess(0);
} }
Console::FreeNativeConsole(); Console::FreeNativeConsole();
if (Loader::PerformingUnitTests() || Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return; if (Loader::PerformingUnitTests() || Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return;
Singleton::FirstInstance = (CreateMutexA(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS); Singleton::FirstInstance = (CreateMutexA(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS);
if (!Singleton::FirstInstance && !ConnectProtocol::Used() && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) if (!Singleton::FirstInstance && !ConnectProtocol::Used() && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO)
{ {
ExitProcess(0); ExitProcess(0);
} }
} }
} }

View File

@ -1,17 +1,17 @@
namespace Components namespace Components
{ {
class Singleton : public Component class Singleton : public Component
{ {
public: public:
Singleton(); Singleton();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "Singleton"; }; const char* getName() { return "Singleton"; };
#endif #endif
static bool IsFirstInstance(); static bool IsFirstInstance();
private: private:
static bool FirstInstance; static bool FirstInstance;
}; };
} }

View File

@ -1,86 +1,86 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
int SlowMotion::Delay = 0; int SlowMotion::Delay = 0;
void SlowMotion::ApplySlowMotion(int timePassed) void SlowMotion::ApplySlowMotion(int timePassed)
{ {
if (SlowMotion::Delay <= 0) if (SlowMotion::Delay <= 0)
{ {
Utils::Hook::Call<void(int)>(0x60B2D0)(timePassed); Utils::Hook::Call<void(int)>(0x60B2D0)(timePassed);
} }
else else
{ {
SlowMotion::Delay -= timePassed; SlowMotion::Delay -= timePassed;
} }
} }
__declspec(naked) void SlowMotion::ApplySlowMotionStub() __declspec(naked) void SlowMotion::ApplySlowMotionStub()
{ {
__asm __asm
{ {
pushad pushad
push [esp + 20h] push [esp + 20h]
call SlowMotion::ApplySlowMotion call SlowMotion::ApplySlowMotion
pop ecx pop ecx
popad popad
retn retn
} }
} }
void SlowMotion::SetSlowMotion() void SlowMotion::SetSlowMotion()
{ {
int duration = 1000; int duration = 1000;
float start = Game::Scr_GetFloat(0); float start = Game::Scr_GetFloat(0);
float end = 1.0f; float end = 1.0f;
if (Game::Scr_GetNumParam() >= 2) if (Game::Scr_GetNumParam() >= 2)
{ {
end = Game::Scr_GetFloat(1); end = Game::Scr_GetFloat(1);
} }
if (Game::Scr_GetNumParam() >= 3) if (Game::Scr_GetNumParam() >= 3)
{ {
duration = static_cast<int>(Game::Scr_GetFloat(2) * 1000.0); duration = static_cast<int>(Game::Scr_GetFloat(2) * 1000.0);
} }
int delay = 0; int delay = 0;
if (start > end) if (start > end)
{ {
if (duration < 150) if (duration < 150)
{ {
delay = duration; delay = duration;
} }
else else
{ {
delay = 150; delay = 150;
} }
} }
duration = duration - delay; duration = duration - delay;
Game::Com_SetSlowMotion(start, end, duration); Game::Com_SetSlowMotion(start, end, duration);
SlowMotion::Delay = delay; SlowMotion::Delay = delay;
// set snapshot num to 1 behind (T6 does this, why shouldn't we?) // set snapshot num to 1 behind (T6 does this, why shouldn't we?)
for (int i = 0; i < *Game::svs_numclients; ++i) for (int i = 0; i < *Game::svs_numclients; ++i)
{ {
Game::svs_clients[i].snapNum = (*reinterpret_cast<DWORD*>(0x31D9384)) - 1; Game::svs_clients[i].snapNum = (*reinterpret_cast<DWORD*>(0x31D9384)) - 1;
} }
} }
SlowMotion::SlowMotion() SlowMotion::SlowMotion()
{ {
if (Dedicated::IsEnabled()) if (Dedicated::IsEnabled())
{ {
SlowMotion::Delay = 0; SlowMotion::Delay = 0;
Utils::Hook(0x5F5FF2, SlowMotion::SetSlowMotion, HOOK_JUMP).install()->quick(); Utils::Hook(0x5F5FF2, SlowMotion::SetSlowMotion, HOOK_JUMP).install()->quick();
Utils::Hook(0x60B38A, SlowMotion::ApplySlowMotionStub, HOOK_CALL).install()->quick(); Utils::Hook(0x60B38A, SlowMotion::ApplySlowMotionStub, HOOK_CALL).install()->quick();
} }
} }
} }

View File

@ -1,22 +1,22 @@
#define BUTTON_FLAG_LEANLEFT 0x40 #define BUTTON_FLAG_LEANLEFT 0x40
#define BUTTON_FLAG_LEANRIGHT 0x80 #define BUTTON_FLAG_LEANRIGHT 0x80
namespace Components namespace Components
{ {
class SlowMotion : public Component class SlowMotion : public Component
{ {
public: public:
SlowMotion(); SlowMotion();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "SlowMotion"; }; const char* getName() { return "SlowMotion"; };
#endif #endif
private: private:
static int Delay; static int Delay;
static void SetSlowMotion(); static void SetSlowMotion();
static void ApplySlowMotion(int timePassed); static void ApplySlowMotion(int timePassed);
static void ApplySlowMotionStub(); static void ApplySlowMotionStub();
}; };
} }

View File

@ -1,98 +1,98 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Utils::Memory::Allocator StringTable::MemAllocator; Utils::Memory::Allocator StringTable::MemAllocator;
std::unordered_map<std::string, Game::StringTable*> StringTable::StringTableMap; std::unordered_map<std::string, Game::StringTable*> StringTable::StringTableMap;
int StringTable::Hash(const char* data) int StringTable::Hash(const char* data)
{ {
int hash = 0; int hash = 0;
while (*data != 0) while (*data != 0)
{ {
hash = tolower(*data) + (31 * hash); hash = tolower(*data) + (31 * hash);
++data; ++data;
} }
return hash; return hash;
} }
Game::StringTable* StringTable::LoadObject(std::string filename) Game::StringTable* StringTable::LoadObject(std::string filename)
{ {
filename = Utils::String::ToLower(filename); filename = Utils::String::ToLower(filename);
Game::StringTable* table = nullptr; Game::StringTable* table = nullptr;
FileSystem::File rawTable(filename); FileSystem::File rawTable(filename);
if (rawTable.exists()) if (rawTable.exists())
{ {
Utils::CSV parsedTable(rawTable.getBuffer(), false, false); Utils::CSV parsedTable(rawTable.getBuffer(), false, false);
table = StringTable::MemAllocator.allocate<Game::StringTable>(); table = StringTable::MemAllocator.allocate<Game::StringTable>();
if (table) if (table)
{ {
table->name = StringTable::MemAllocator.duplicateString(filename); table->name = StringTable::MemAllocator.duplicateString(filename);
table->columnCount = parsedTable.getColumns(); table->columnCount = parsedTable.getColumns();
table->rowCount = parsedTable.getRows(); table->rowCount = parsedTable.getRows();
table->values = StringTable::MemAllocator.allocateArray<Game::StringTableCell>(table->columnCount * table->rowCount); table->values = StringTable::MemAllocator.allocateArray<Game::StringTableCell>(table->columnCount * table->rowCount);
if (!table->values) if (!table->values)
{ {
return nullptr; return nullptr;
} }
for (int i = 0; i < table->rowCount; ++i) for (int i = 0; i < table->rowCount; ++i)
{ {
for (int j = 0; j < table->columnCount; ++j) for (int j = 0; j < table->columnCount; ++j)
{ {
std::string value = parsedTable.getElementAt(i, j); std::string value = parsedTable.getElementAt(i, j);
Game::StringTableCell* cell = &table->values[i * table->columnCount + j]; Game::StringTableCell* cell = &table->values[i * table->columnCount + j];
cell->hash = StringTable::Hash(value.data()); cell->hash = StringTable::Hash(value.data());
cell->string = StringTable::MemAllocator.duplicateString(value); cell->string = StringTable::MemAllocator.duplicateString(value);
//if (!cell->string) cell->string = ""; // We have to assume it allocated successfully //if (!cell->string) cell->string = ""; // We have to assume it allocated successfully
} }
} }
StringTable::StringTableMap[filename] = table; StringTable::StringTableMap[filename] = table;
} }
} }
else else
{ {
StringTable::StringTableMap[filename] = nullptr; StringTable::StringTableMap[filename] = nullptr;
} }
return table; return table;
} }
StringTable::StringTable() StringTable::StringTable()
{ {
AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRINGTABLE, [] (Game::XAssetType, std::string filename) AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_STRINGTABLE, [] (Game::XAssetType, std::string filename)
{ {
Game::XAssetHeader header = { 0 }; Game::XAssetHeader header = { 0 };
filename = Utils::String::ToLower(filename); filename = Utils::String::ToLower(filename);
if (StringTable::StringTableMap.find(filename) != StringTable::StringTableMap.end()) if (StringTable::StringTableMap.find(filename) != StringTable::StringTableMap.end())
{ {
header.stringTable = StringTable::StringTableMap[filename]; header.stringTable = StringTable::StringTableMap[filename];
} }
else else
{ {
header.stringTable = StringTable::LoadObject(filename); header.stringTable = StringTable::LoadObject(filename);
} }
return header; return header;
}); });
} }
StringTable::~StringTable() StringTable::~StringTable()
{ {
StringTable::StringTableMap.clear(); StringTable::StringTableMap.clear();
StringTable::MemAllocator.clear(); StringTable::MemAllocator.clear();
} }
} }

View File

@ -1,20 +1,20 @@
namespace Components namespace Components
{ {
class StringTable : public Component class StringTable : public Component
{ {
public: public:
StringTable(); StringTable();
~StringTable(); ~StringTable();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "StringTable"; }; const char* getName() { return "StringTable"; };
#endif #endif
private: private:
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static std::unordered_map<std::string, Game::StringTable*> StringTableMap; static std::unordered_map<std::string, Game::StringTable*> StringTableMap;
static int Hash(const char* data); static int Hash(const char* data);
static Game::StringTable* LoadObject(std::string filename); static Game::StringTable* LoadObject(std::string filename);
}; };
} }

View File

@ -1,218 +1,218 @@
#include "STDInclude.hpp" #include "STDInclude.hpp"
namespace Components namespace Components
{ {
Utils::Memory::Allocator StructuredData::MemAllocator; Utils::Memory::Allocator StructuredData::MemAllocator;
const char* StructuredData::EnumTranslation[ENUM_MAX] = const char* StructuredData::EnumTranslation[ENUM_MAX] =
{ {
"features", "features",
"weapons", "weapons",
"attachements", "attachements",
"challenges", "challenges",
"camos", "camos",
"perks", "perks",
"killstreaks", "killstreaks",
"accolades", "accolades",
"cardicons", "cardicons",
"cardtitles", "cardtitles",
"cardnameplates", "cardnameplates",
"teams", "teams",
"gametypes" "gametypes"
}; };
void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries) void StructuredData::PatchPlayerDataEnum(Game::StructuredDataDef* data, StructuredData::PlayerDataType type, std::vector<std::string>& entries)
{ {
if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return; if (!data || type >= StructuredData::PlayerDataType::ENUM_MAX) return;
Game::StructuredDataEnum* dataEnum = &data->enums[type]; Game::StructuredDataEnum* dataEnum = &data->enums[type];
// Build index-sorted data vector // Build index-sorted data vector
std::vector<const char*> dataVector; std::vector<const char*> dataVector;
for (int i = 0; i < dataEnum->numIndices; ++i) for (int i = 0; i < dataEnum->numIndices; ++i)
{ {
int index = 0; int index = 0;
for (; index < dataEnum->numIndices; ++index) for (; index < dataEnum->numIndices; ++index)
{ {
if (dataEnum->indices[index].index == i) if (dataEnum->indices[index].index == i)
{ {
break; break;
} }
} }
dataVector.push_back(dataEnum->indices[index].key); dataVector.push_back(dataEnum->indices[index].key);
} }
// Rebase or add new entries // Rebase or add new entries
for (auto entry : entries) for (auto entry : entries)
{ {
const char* value = nullptr; const char* value = nullptr;
for (auto i = dataVector.begin(); i != dataVector.end(); ++i) for (auto i = dataVector.begin(); i != dataVector.end(); ++i)
{ {
if (*i == entry) if (*i == entry)
{ {
value = *i; value = *i;
dataVector.erase(i); dataVector.erase(i);
Logger::Print("Playerdatadef entry '%s' will be rebased!\n", value); Logger::Print("Playerdatadef entry '%s' will be rebased!\n", value);
break; break;
} }
} }
if (!value) value = StructuredData::MemAllocator.duplicateString(entry); if (!value) value = StructuredData::MemAllocator.duplicateString(entry);
dataVector.push_back(value); dataVector.push_back(value);
} }
// Map data back to the game structure // Map data back to the game structure
Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnumEntry>(dataVector.size()); Game::StructuredDataEnumEntry* indices = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnumEntry>(dataVector.size());
for (unsigned int i = 0; i < dataVector.size(); ++i) for (unsigned int i = 0; i < dataVector.size(); ++i)
{ {
indices[i].index = i; indices[i].index = i;
indices[i].key = dataVector[i]; indices[i].key = dataVector[i];
} }
// Sort alphabetically // Sort alphabetically
qsort(indices, dataVector.size(), sizeof(Game::StructuredDataEnumEntry), [] (const void* first, const void* second) qsort(indices, dataVector.size(), sizeof(Game::StructuredDataEnumEntry), [] (const void* first, const void* second)
{ {
const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first); const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first);
const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second); const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second);
return std::string(entry1->key).compare(entry2->key); return std::string(entry1->key).compare(entry2->key);
}); });
// Apply our patches // Apply our patches
dataEnum->numIndices = dataVector.size(); dataEnum->numIndices = dataVector.size();
dataEnum->indices = indices; dataEnum->indices = indices;
} }
StructuredData::StructuredData() StructuredData::StructuredData()
{ {
// Only execute this when building zones // Only execute this when building zones
if (!ZoneBuilder::IsEnabled()) return; if (!ZoneBuilder::IsEnabled()) return;
AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* /*restrict*/) AssetHandler::OnLoad([] (Game::XAssetType type, Game::XAssetHeader asset, std::string filename, bool* /*restrict*/)
{ {
// Only intercept playerdatadef loading // Only intercept playerdatadef loading
if (filename != "mp/playerdata.def" || type != Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF) return; if (filename != "mp/playerdata.def" || type != Game::XAssetType::ASSET_TYPE_STRUCTUREDDATADEF) return;
// Store asset // Store asset
Game::StructuredDataDefSet* data = asset.structuredData; Game::StructuredDataDefSet* data = asset.structuredData;
if (!data) return; if (!data) return;
if (data->count != 1) if (data->count != 1)
{ {
Logger::Error("PlayerDataDefSet contains more than 1 definition!"); Logger::Error("PlayerDataDefSet contains more than 1 definition!");
return; return;
} }
if (data->data[0].version != 155) if (data->data[0].version != 155)
{ {
Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!"); Logger::Error("Initial PlayerDataDef is not version 155, patching not possible!");
return; return;
} }
std::map<int, std::vector<std::vector<std::string>>> patchDefinitions; std::map<int, std::vector<std::vector<std::string>>> patchDefinitions;
// First check if all versions are present // First check if all versions are present
for (int i = 156;; ++i) for (int i = 156;; ++i)
{ {
FileSystem::File definition(Utils::String::VA("%s/%d.json", filename.data(), i)); FileSystem::File definition(Utils::String::VA("%s/%d.json", filename.data(), i));
if (!definition.exists()) break; if (!definition.exists()) break;
std::vector<std::vector<std::string>> enumContainer; std::vector<std::vector<std::string>> enumContainer;
std::string errors; std::string errors;
json11::Json defData = json11::Json::parse(definition.getBuffer(), errors); json11::Json defData = json11::Json::parse(definition.getBuffer(), errors);
if (!errors.empty()) if (!errors.empty())
{ {
Logger::Error("Parsing patch file '%s' for PlayerDataDef version %d failed: %s", definition.getName().data(), i, errors.data()); Logger::Error("Parsing patch file '%s' for PlayerDataDef version %d failed: %s", definition.getName().data(), i, errors.data());
return; return;
} }
if (!defData.is_object()) if (!defData.is_object())
{ {
Logger::Error("PlayerDataDef patch for version %d is invalid!", i); Logger::Error("PlayerDataDef patch for version %d is invalid!", i);
return; return;
} }
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType) for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
{ {
auto enumData = defData[StructuredData::EnumTranslation[pType]]; auto enumData = defData[StructuredData::EnumTranslation[pType]];
std::vector<std::string> entryData; std::vector<std::string> entryData;
if (enumData.is_array()) if (enumData.is_array())
{ {
for (auto rawEntry : enumData.array_items()) for (auto rawEntry : enumData.array_items())
{ {
if (rawEntry.is_string()) if (rawEntry.is_string())
{ {
entryData.push_back(rawEntry.string_value()); entryData.push_back(rawEntry.string_value());
} }
} }
} }
enumContainer.push_back(entryData); enumContainer.push_back(entryData);
} }
patchDefinitions[i] = enumContainer; patchDefinitions[i] = enumContainer;
} }
// Nothing to patch // Nothing to patch
if (patchDefinitions.empty()) return; if (patchDefinitions.empty()) return;
// Reallocate the definition // Reallocate the definition
Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size()); Game::StructuredDataDef* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->count + patchDefinitions.size());
std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count); std::memcpy(&newData[patchDefinitions.size()], data->data, sizeof Game::StructuredDataDef * data->count);
// Prepare the buffers // Prepare the buffers
for (unsigned int i = 0; i < patchDefinitions.size(); ++i) for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
{ {
std::memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef); std::memcpy(&newData[i], data->data, sizeof Game::StructuredDataDef);
newData[i].version = (patchDefinitions.size() - i) + 155; newData[i].version = (patchDefinitions.size() - i) + 155;
// Reallocate the enum array // Reallocate the enum array
Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->data->numEnums); Game::StructuredDataEnum* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->data->numEnums);
std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums); std::memcpy(newEnums, data->data->enums, sizeof Game::StructuredDataEnum * data->data->numEnums);
newData[i].enums = newEnums; newData[i].enums = newEnums;
} }
// Apply new data // Apply new data
data->data = newData; data->data = newData;
data->count += patchDefinitions.size(); data->count += patchDefinitions.size();
// Patch the definition // Patch the definition
for (int i = 0; i < data->count; ++i) for (int i = 0; i < data->count; ++i)
{ {
// No need to patch version 155 // No need to patch version 155
if (newData[i].version == 155) continue; if (newData[i].version == 155) continue;
if(patchDefinitions.find(newData[i].version) != patchDefinitions.end()) if(patchDefinitions.find(newData[i].version) != patchDefinitions.end())
{ {
auto patchData = patchDefinitions[newData[i].version]; auto patchData = patchDefinitions[newData[i].version];
// Invalid patch data // Invalid patch data
if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX) if (patchData.size() != StructuredData::PlayerDataType::ENUM_MAX)
{ {
Logger::Error("PlayerDataDef patch for version %d wasn't parsed correctly!", newData[i].version); Logger::Error("PlayerDataDef patch for version %d wasn't parsed correctly!", newData[i].version);
continue; continue;
} }
// Apply the patch data // Apply the patch data
for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType) for (unsigned int pType = 0; pType < StructuredData::PlayerDataType::ENUM_MAX; ++pType)
{ {
if (!patchData[pType].empty()) if (!patchData[pType].empty())
{ {
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]); StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
} }
} }
} }
} }
}); });
} }
StructuredData::~StructuredData() StructuredData::~StructuredData()
{ {
StructuredData::MemAllocator.clear(); StructuredData::MemAllocator.clear();
} }
} }

View File

@ -1,37 +1,37 @@
namespace Components namespace Components
{ {
class StructuredData : public Component class StructuredData : public Component
{ {
public: public:
enum PlayerDataType enum PlayerDataType
{ {
ENUM_FEATURES, ENUM_FEATURES,
ENUM_WEAPONS, ENUM_WEAPONS,
ENUM_ATTACHEMENTS, ENUM_ATTACHEMENTS,
ENUM_CHALLENGES, ENUM_CHALLENGES,
ENUM_CAMOS, ENUM_CAMOS,
ENUM_PERKS, ENUM_PERKS,
ENUM_KILLSTREAKS, ENUM_KILLSTREAKS,
ENUM_ACCOLADES, ENUM_ACCOLADES,
ENUM_CARDICONS, ENUM_CARDICONS,
ENUM_CARDTITLES, ENUM_CARDTITLES,
ENUM_CARDNAMEPLATES, ENUM_CARDNAMEPLATES,
ENUM_TEAMS, ENUM_TEAMS,
ENUM_GAMETYPES, ENUM_GAMETYPES,
ENUM_MAX ENUM_MAX
}; };
StructuredData(); StructuredData();
~StructuredData(); ~StructuredData();
#if defined(DEBUG) || defined(FORCE_UNIT_TESTS) #if defined(DEBUG) || defined(FORCE_UNIT_TESTS)
const char* getName() { return "StructuredData"; }; const char* getName() { return "StructuredData"; };
#endif #endif
private: private:
static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector<std::string>& entries); static void PatchPlayerDataEnum(Game::StructuredDataDef* data, PlayerDataType type, std::vector<std::string>& entries);
static Utils::Memory::Allocator MemAllocator; static Utils::Memory::Allocator MemAllocator;
static const char* EnumTranslation[ENUM_MAX]; static const char* EnumTranslation[ENUM_MAX];
}; };
} }

Some files were not shown because too many files have changed in this diff Show More