diff --git a/address.h b/address.h deleted file mode 100644 index c951431..0000000 --- a/address.h +++ /dev/null @@ -1,164 +0,0 @@ -#pragma once - -intptr_t Deref(intptr_t addr) -{ - return *(intptr_t*)addr; -} - -struct Offset -{ - intptr_t offs; - ModuleName mod; - - Offset(ModuleName _mod, intptr_t _offs) - { - offs = _offs; - mod = _mod; - } - - intptr_t Get() { return modules[mod].base + offs; } - intptr_t Deref() { return ::Deref(modules[mod].base + offs); } - - const Offset& operator=( const intptr_t _offs ) - { - offs = _offs; - return *this; - } -}; - -struct AddressBase; -typedef std::vector AddressList; -const int maxAddresses = 2; - -struct AddressBase -{ - virtual bool Find() = 0; -}; - -template -struct AddressInfo : public AddressBase -{ - typedef void (*callback)(AddressInfo& addr, ModuleName mod); - - const char* name; - const char* sig; - size_t len; - const char* mask; - addrtype addr[maxAddresses]; - ModuleName mod[maxAddresses]; - callback onFind; - - AddressInfo(const char* _name, const char* _sig, size_t _len, const char* _mask, - ModuleName _mod1, ModuleName _mod2, AddressList& list, callback _onFind = nullptr ) - { - name = _name; - sig = _sig; - len = _len; - mask = _mask; - memset(addr, 0, sizeof(addr)); - mod[0] = _mod1; - mod[1] = _mod2; - onFind = _onFind; - list.push_back(this); - } - - virtual bool Find() - { - int foundAddr = 0; - for (int m = 0; m < maxAddresses; m++) - { - ModuleName curmod = mod[m]; - if (curmod == MOD_INVALID) - continue; - - ModuleInfo& info = modules[curmod]; - - intptr_t ptr = 0; - intptr_t end = info.base + info.size - len; - - for (intptr_t i = info.base; i < end; i++) - { - bool found = true; - for (size_t j = 0; j < len; j++) - { - if (mask) - found &= (mask[j] == '?') || (sig[j] == *(char*)(i + j)); - else - found &= (sig[j] == *(char*)(i + j)); - - } - - if (found) - { - ptr = i; - foundAddr++; - Log(Color(0, 255, 255, 255), "Signature %s found at 0x%X in %s.%s\n", - name, ptr, info.name, "dll"); - break; - } - } - - addr[m] = (addrtype)ptr; - if (ptr) - { - if (onFind) - onFind(*this, curmod); - } - } - - if (foundAddr == 0) - { - Log(Color(255, 0, 0, 255), "Failed to find signature for %s\n", name); - } - - return foundAddr != 0; - } - - addrtype& Resolve(intptr_t address) - { - for (int k = 0; k < maxAddresses; k++) - if (modules[mod[k]].ValidAddress(address)) - return addr[k]; - UNREACHABLE; - } - - constexpr addrtype& operator[](ModuleName m) - { - for (int k = 0; k < maxAddresses; k++) - if (mod[k] == m) - return addr[k]; - UNREACHABLE; - } -}; - -std::vector addresses; - -#define CHECK_SIG(name, sig, mask) static_assert(sizeof(#sig) == sizeof(#mask), "Mismatch in signature/mask length for " name) - -#define ADDR(var, name, mod, sig, mask) \ -AddressInfo address_##var = {name, #sig, sizeof(#sig) - 1, #mask, mod, MOD_INVALID, addresses}; \ -CHECK_SIG(name, sig, mask); - -#define ADDR_GAME(var, name, sig, mask) \ -AddressInfo address_##var = {name, #sig, sizeof(#sig) - 1, #mask, MOD_CLIENT, MOD_SERVER, addresses}; \ -CHECK_SIG(name, sig, mask); - -#define ADDR_CALLBACK(var, name, mod, sig, mask, callback) \ -AddressInfo address_##var = {name, #sig, sizeof(#sig) - 1, #mask, mod, MOD_INVALID, addresses, callback}; \ -CHECK_SIG(name, sig, mask); - -#define DETOUR_LOAD(addrtype) \ -for (int k = 0; k < maxAddresses; k++) \ - if (address_##addrtype.addr[k]) DetourAttach(&(LPVOID&)address_##addrtype.addr[k], &hook_##addrtype); - -#define DETOUR_LOAD_GAME(addrtype) \ -if (address_##addrtype[MOD_CLIENT]) DetourAttach(&(LPVOID&)address_##addrtype[MOD_CLIENT], &hook_client_##addrtype); \ -if (address_##addrtype[MOD_SERVER]) DetourAttach(&(LPVOID&)address_##addrtype[MOD_SERVER], &hook_server_##addrtype); - -#define DETOUR_UNLOAD(addrtype) \ -for (int k = 0; k < maxAddresses; k++) \ -if (address_##addrtype.addr[k]) DetourDetach(&(LPVOID&)address_##addrtype.addr[k], &hook_##addrtype); - -#define DETOUR_UNLOAD_GAME(addrtype) \ -if (address_##addrtype[MOD_CLIENT]) DetourDetach(&(LPVOID&)address_##addrtype[MOD_CLIENT], &hook_client_##addrtype); \ -if (address_##addrtype[MOD_SERVER]) DetourDetach(&(LPVOID&)address_##addrtype[MOD_SERVER], &hook_server_##addrtype); \ No newline at end of file diff --git a/custom_items_games.cpp b/custom_items_games.cpp new file mode 100644 index 0000000..6e4f2d1 --- /dev/null +++ b/custom_items_games.cpp @@ -0,0 +1,433 @@ +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "detours/detours.h" + +#define PLUGIN_NAME "[Custom Items Game] " + +#define CUSTOM_ITEMS_GAME "scripts/items/items_game_custom.txt" +#define CUSTOM_ITEMS_GAME_SIG CUSTOM_ITEMS_GAME ".sig" + +#define INTERFACEVERSION_IPLUGIN "ISERVERPLUGINCALLBACKS003" +#define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" + +#define SIG(x) Sig({#x, sizeof(#x) - 1}) +#define SIG_WILDCARD 0x2A + +struct Sig { const char* sig; size_t len; }; + +class edict_t; +class CCommand; +enum EQueryCvarValueStatus; +typedef void* (*CreateInterfaceFn)(const char* pName, int* pReturnCode); +typedef int QueryCvarCookie_t; +enum PluginResult { PLUGIN_CONTINUE, PLUGIN_OVERRIDE, PLUGIN_STOP }; +enum InterfaceResult { IFACE_OK, IFACE_FAILED }; + +typedef void* FileHandle_t; +enum FileSystemSeek_t { FILESYSTEM_SEEK_HEAD, FILESYSTEM_SEEK_CURRENT, FILESYSTEM_SEEK_TAIL }; + +struct Color { unsigned char r, g, b, a; }; +typedef void (*ConColorMsg)(const Color& clr, const char* msg, ...); +ConColorMsg Log = nullptr; + +struct CPlugin +{ + virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory); + virtual void Unload(void); + virtual void Pause(void) {} + virtual void UnPause(void) {} + virtual const char* GetPluginDescription(void) { return "Custom Items Game"; } + virtual void LevelInit(char const* pMapName) {} + virtual void ServerActivate(edict_t* pEdictList, int edictCount, int clientMax) {} + virtual void GameFrame(bool simulating) {} + virtual void LevelShutdown(void) {} + virtual void ClientActive(edict_t* pEntity) {} + virtual void ClientDisconnect(edict_t* pEntity) {} + virtual void ClientPutInServer(edict_t* pEntity, char const* playername) {} + virtual void SetCommandClient(int index) {} + virtual void ClientSettingsChanged(edict_t* pEdict) {} + virtual PluginResult ClientConnect(bool* bAllowConnect, edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) { return PLUGIN_CONTINUE; } + virtual PluginResult ClientCommand(edict_t* pEntity, const CCommand& args) { return PLUGIN_CONTINUE; } + virtual PluginResult NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) { return PLUGIN_CONTINUE; } + virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t* pPlayerEntity, EQueryCvarValueStatus eStatus, const char* pCvarName, const char* pCvarValue) {} + virtual void OnEdictAllocated(edict_t* edict) {} + virtual void OnEdictFreed(const edict_t* edict) {} +} plugin; + +struct IBaseFileSystem +{ + virtual int Read(void* pOutput, int size, FileHandle_t file) = 0; + virtual int Write(void const* pInput, int size, FileHandle_t file) = 0; + virtual FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pathID = 0) = 0; + virtual void Close(FileHandle_t file) = 0; + virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) = 0; + virtual unsigned int Tell(FileHandle_t file) = 0; + virtual unsigned int Size(FileHandle_t file) = 0; + virtual unsigned int Size(const char* pFileName, const char* pPathID = 0) = 0; + virtual void Flush(FileHandle_t file) = 0; + virtual bool Precache(const char* pFileName, const char* pPathID = 0) = 0; + virtual bool FileExists(const char* pFileName, const char* pPathID = 0) = 0; +} *filesystem = NULL; + +extern "C" __declspec(dllexport) void* CreateInterface(const char* pName, int* pReturnCode) +{ + if (!strcmp(INTERFACEVERSION_IPLUGIN, pName)) + { + if (pReturnCode) *pReturnCode = IFACE_OK; + return &plugin; + } + if (pReturnCode) *pReturnCode = IFACE_FAILED; + return NULL; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + return TRUE; +} + +static bool FindLog() +{ + HMODULE Handle = LoadLibrary("tier0.dll"); + if (!Handle) + return false; +#ifdef _WIN64 + Log = (ConColorMsg)GetProcAddress(Handle, "?ConColorMsg@@YAXAEBVColor@@PEBDZZ"); +#else + Log = (ConColorMsg)GetProcAddress(Handle, "?ConColorMsg@@YAXABVColor@@PBDZZ"); +#endif + FreeLibrary(Handle); + return Log != NULL; +} + +static void* FindSignature(const MODULEINFO& info, const Sig& sig) +{ + uintptr_t start = (uintptr_t)info.lpBaseOfDll; + uintptr_t end = start + info.SizeOfImage - sig.len; + + for (uintptr_t i = start; i < end; i++) + { + bool found = true; + for (size_t j = 0; j < sig.len; j++) + found &= (sig.sig[j] == SIG_WILDCARD) || (sig.sig[j] == *(char*)(i + j)); + if (found) + return (void*)i; + } + + return NULL; +} + +static bool IsDemoBranch() +{ + FileHandle_t f = filesystem->Open("steam.inf", "r"); + if (!f) + { + Log({ 255, 0, 0, 255 }, PLUGIN_NAME "Failed to open steam.inf\n"); + return false; + } + + bool demo_branch = false; + bool patch_version = false; + + char buffer[256]; + filesystem->Read(buffer, sizeof(buffer), f); + + char* p = strtok(buffer, "=\r\n"); + while (p) + { + if (patch_version) + { + if (atoi(p) <= 8207200) + demo_branch = true; + break; + } + + if (!strcmp(p, "PatchVersion")) + patch_version = true; + + p = strtok(NULL, "=\r\n"); + } + + filesystem->Close(f); + return demo_branch; +} + +static bool CheckCustomItemsGame() +{ + static bool foundCustom = true, check = true; + if (check) + { + check = false; + if (!filesystem->FileExists(CUSTOM_ITEMS_GAME)) + { + Log({ 255, 0, 127, 255 }, + PLUGIN_NAME "Server: %s not found, loading default items_game.txt ...\n", CUSTOM_ITEMS_GAME); + foundCustom = false; + } + if (!filesystem->FileExists(CUSTOM_ITEMS_GAME_SIG)) + { + Log({ 255, 0, 127, 255 }, + PLUGIN_NAME "Server: %s not found, loading default items_game.txt ...\n", CUSTOM_ITEMS_GAME_SIG); + foundCustom = false; + } + } + return foundCustom; +} + +typedef void* (*func_econItemSystem)(); +func_econItemSystem server_econItemSystem = NULL; + +typedef bool (*func_crypto_verifySignature)(uint8_t*, uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*); +func_crypto_verifySignature client_crypto_verifySignature = NULL; +func_crypto_verifySignature server_crypto_verifySignature = NULL; +bool hook_crypto_verifySignature(uint8_t*, uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*) +{ + return true; +} + +#ifdef _WIN64 +typedef void(__fastcall* func_econItemSchema_init)(void*, const char*, const char*, void*); +func_econItemSchema_init client_econItemSchema_init = NULL; +func_econItemSchema_init server_econItemSchema_init = NULL; +void __fastcall hook_client_econItemSchema_init(void* thisptr, const char* filename, const char* pathid, void* errors) +{ + if (CheckCustomItemsGame()) + filename = CUSTOM_ITEMS_GAME; + client_econItemSchema_init(thisptr, filename, pathid, errors); +} +void __fastcall hook_server_econItemSchema_init(void* thisptr, const char* filename, const char* pathid, void* errors) +{ + if (CheckCustomItemsGame()) + filename = CUSTOM_ITEMS_GAME; + server_econItemSchema_init(thisptr, filename, pathid, errors); +} + +// filename arg is inlined +typedef void(__fastcall* func_econItemSystem_parseItemSchemaFile)(void*); +func_econItemSystem_parseItemSchemaFile server_econItemSystem_parseItemSchemaFile = NULL; +func_econItemSystem_parseItemSchemaFile client_econItemSystem_parseItemSchemaFile = NULL; +void __fastcall hook_server_econItemSystem_parseItemSchemaFile(void* thisptr) +{ + if (CheckCustomItemsGame()) + { + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Server: loading %s...\n", CUSTOM_ITEMS_GAME); + } + server_econItemSystem_parseItemSchemaFile(thisptr); +} +void __fastcall hook_client_econItemSystem_parseItemSchemaFile(void* thisptr) +{ + if (CheckCustomItemsGame()) + { + hook_server_econItemSystem_parseItemSchemaFile(server_econItemSystem()); + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Client: Loading %s...\n", CUSTOM_ITEMS_GAME); + } + client_econItemSystem_parseItemSchemaFile(thisptr); +} + +typedef bool(__fastcall* func_gcUpdateItemSchema_runJob)(void*, void*); +func_gcUpdateItemSchema_runJob client_gcUpdateItemSchema_runJob = NULL; +func_gcUpdateItemSchema_runJob server_gcUpdateItemSchema_runJob = NULL; +bool __fastcall hook_client_gcUpdateItemSchema_runJob(void* thisptr, void* packet) +{ + if (CheckCustomItemsGame()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Blocked item schema update from GC\n"); + else if (IsDemoBranch()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Forcefully blocked item schema update from GC (demo branch detected)\n"); + else + client_gcUpdateItemSchema_runJob(thisptr, packet); + return true; +} +bool __fastcall hook_server_gcUpdateItemSchema_runJob(void* thisptr, void* packet) +{ + if (CheckCustomItemsGame()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Blocked item schema update from GC\n"); + else if (IsDemoBranch()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Forcefully blocked item schema update from GC (demo branch detected)\n"); + else + server_gcUpdateItemSchema_runJob(thisptr, packet); + return true; +} +#else +typedef void(__fastcall* func_econItemSystem_parseItemSchemaFile)(void*, void*, const char*); +func_econItemSystem_parseItemSchemaFile server_econItemSystem_parseItemSchemaFile = NULL; +func_econItemSystem_parseItemSchemaFile client_econItemSystem_parseItemSchemaFile = NULL; +void __fastcall hook_server_econItemSystem_parseItemSchemaFile(void* thisptr, void* edx, const char* filename) +{ + if (CheckCustomItemsGame()) + { + filename = CUSTOM_ITEMS_GAME; + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Server: loading %s...\n", filename); + } + server_econItemSystem_parseItemSchemaFile(thisptr, edx, filename); +} +void __fastcall hook_client_econItemSystem_parseItemSchemaFile(void* thisptr, void* edx, const char* filename) +{ + if (CheckCustomItemsGame()) + { + filename = CUSTOM_ITEMS_GAME; + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Client: Loading %s...\n", filename); + hook_server_econItemSystem_parseItemSchemaFile(server_econItemSystem(), edx, filename); + } + client_econItemSystem_parseItemSchemaFile(thisptr, edx, filename); +} + +typedef bool(__fastcall* func_gcUpdateItemSchema_runJob)(void*, void*, void*); +func_gcUpdateItemSchema_runJob client_gcUpdateItemSchema_runJob = NULL; +func_gcUpdateItemSchema_runJob server_gcUpdateItemSchema_runJob = NULL; +bool __fastcall hook_client_gcUpdateItemSchema_runJob(void* thisptr, void* edx, void* packet) +{ + if (CheckCustomItemsGame()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Blocked item schema update from GC\n"); + else if (IsDemoBranch()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Forcefully blocked item schema update from GC (demo branch detected)\n"); + else + client_gcUpdateItemSchema_runJob(thisptr, edx, packet); + return true; +} +bool __fastcall hook_server_gcUpdateItemSchema_runJob(void* thisptr, void* edx, void* packet) +{ + if (CheckCustomItemsGame()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Blocked item schema update from GC\n"); + else if (IsDemoBranch()) + Log({ 0, 255, 127, 255 }, PLUGIN_NAME "Forcefully blocked item schema update from GC (demo branch detected)\n"); + else + server_gcUpdateItemSchema_runJob(thisptr, edx, packet); + return true; +} +#endif + +static bool FindSignatures() +{ + Log({ 0, 255, 0, 255 }, PLUGIN_NAME "Finding signatures...\n"); + + const char* client_name = "client.dll", *server_name = "server.dll"; + MODULEINFO client_info, server_info; + HMODULE client, server; + + client = GetModuleHandle(client_name); + if (!client) + { + Log({ 255, 0, 0, 255 }, PLUGIN_NAME "Failed to get module info for %s\n", client_name); + return false; + } + + server = GetModuleHandle(server_name); + if (!server) + { + Log({ 255, 0, 0, 255 }, PLUGIN_NAME "Failed to get module info for %s\n", server_name); + return false; + } + + GetModuleInformation(GetCurrentProcess(), client, &client_info, sizeof(client_info)); + GetModuleInformation(GetCurrentProcess(), server, &server_info, sizeof(server_info)); + +#ifdef _WIN64 + Sig sig_econItemSystem = SIG(\x48\x83\xEC\x2A\x48\x8B\x05\x2A\x2A\x2A\x2A\x48\x85\xC0\x75\x2A\xB9); + Sig sig_crypto_verifySignature = SIG(\x48\x89\x5C\x24\x2A\x4C\x89\x44\x24\x2A\x89\x54\x24\x2A\x48\x89\x4C\x24); + Sig sig_econItemSchema_init = SIG(\x48\x89\x5C\x24\x2A\x48\x89\x74\x24\x2A\x48\x89\x7C\x24\x2A\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x2A\x2A\x2A\x2A\x48\x81\xEC\x2A\x2A\x2A\x2A\x48\x8B\x01\x49\x8B\xD9); + Sig sig_econItemSystem_parseItemSchemaFile = SIG(\x48\x89\x5C\x24\x2A\x57\x48\x83\xEC\x2A\x48\x8B\x41\x2A\x4C\x8D\x4C\x24); + Sig sig_gcUpdateItemSchema_runJob = SIG(\x48\x8B\xC4\x48\x83\xEC\x2A\x48\x89\x58\x2A\x48\x89\x68\x2A\x48\x8B\xEA\x48\x89\x70\x2A\x48\x89\x78); +#else + Sig sig_econItemSystem = SIG(\xA1\x2A\x2A\x2A\x2A\x85\xC0\x75\x2A\x56); + Sig sig_crypto_verifySignature = SIG(\x55\x8B\xEC\x6A\xFF\x68\x2A\x2A\x2A\x2A\x64\xA1\x00\x00\x00\x00\x50\x64\x89\x25\x00\x00\x00\x00\x81\xEC\xCC\x00\x00\x00); + Sig sig_econItemSystem_parseItemSchemaFile = SIG(\x55\x8B\xEC\x83\xEC\x14\x8B\x41\x04\x8D\x55\xEC\x83\xC1\x04\xC7\x45\xEC\x00\x00\x00\x00\x52\x68\x2A\x2A\x2A\x2A); + Sig sig_gcUpdateItemSchema_runJob = SIG(\x55\x8B\xEC\x83\xEC\x1C\x53\x57\x8B\xF9\x8D\x4D\xE4); +#endif + + server_econItemSystem = (func_econItemSystem)FindSignature(server_info, sig_econItemSystem); + + client_crypto_verifySignature = (func_crypto_verifySignature)FindSignature(client_info, sig_crypto_verifySignature); + server_crypto_verifySignature = (func_crypto_verifySignature)FindSignature(server_info, sig_crypto_verifySignature); +#ifdef _WIN64 + client_econItemSchema_init = (func_econItemSchema_init)FindSignature(client_info, sig_econItemSchema_init); + server_econItemSchema_init = (func_econItemSchema_init)FindSignature(server_info, sig_econItemSchema_init); +#endif + client_econItemSystem_parseItemSchemaFile = (func_econItemSystem_parseItemSchemaFile)FindSignature(client_info, sig_econItemSystem_parseItemSchemaFile); + server_econItemSystem_parseItemSchemaFile = (func_econItemSystem_parseItemSchemaFile)FindSignature(server_info, sig_econItemSystem_parseItemSchemaFile); + client_gcUpdateItemSchema_runJob = (func_gcUpdateItemSchema_runJob)FindSignature(client_info, sig_gcUpdateItemSchema_runJob); + server_gcUpdateItemSchema_runJob = (func_gcUpdateItemSchema_runJob)FindSignature(server_info, sig_gcUpdateItemSchema_runJob); + + if (!server_econItemSystem + || !client_crypto_verifySignature || !server_crypto_verifySignature +#ifdef _WIN64 + || !client_econItemSchema_init || !server_econItemSchema_init +#endif + || !client_econItemSystem_parseItemSchemaFile || !server_econItemSystem_parseItemSchemaFile + || !client_gcUpdateItemSchema_runJob || !server_gcUpdateItemSchema_runJob + ) + { + Log({ 255, 0, 0, 255 }, PLUGIN_NAME "Failed to find required signatures\n"); + return false; + } + + return true; +} + +static void LoadDetours() +{ + Log({ 0, 255, 0, 255 }, PLUGIN_NAME "Loading detours...\n"); + + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourAttach(&client_crypto_verifySignature, hook_crypto_verifySignature); + DetourAttach(&server_crypto_verifySignature, hook_crypto_verifySignature); +#ifdef _WIN64 + DetourAttach(&client_econItemSchema_init, hook_client_econItemSchema_init); + DetourAttach(&server_econItemSchema_init, hook_server_econItemSchema_init); +#endif + DetourAttach(&client_econItemSystem_parseItemSchemaFile, hook_client_econItemSystem_parseItemSchemaFile); + DetourAttach(&server_econItemSystem_parseItemSchemaFile, hook_server_econItemSystem_parseItemSchemaFile); + DetourAttach(&client_gcUpdateItemSchema_runJob, hook_client_gcUpdateItemSchema_runJob); + DetourAttach(&server_gcUpdateItemSchema_runJob, hook_server_gcUpdateItemSchema_runJob); + + DetourTransactionCommit(); +} + +static void UnloadDetours() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + + DetourDetach(&client_crypto_verifySignature, hook_crypto_verifySignature); + DetourDetach(&server_crypto_verifySignature, hook_crypto_verifySignature); +#ifdef _WIN64 + DetourDetach(&client_econItemSchema_init, hook_client_econItemSchema_init); + DetourDetach(&server_econItemSchema_init, hook_server_econItemSchema_init); +#endif + DetourDetach(&client_econItemSystem_parseItemSchemaFile, hook_client_econItemSystem_parseItemSchemaFile); + DetourDetach(&server_econItemSystem_parseItemSchemaFile, hook_server_econItemSystem_parseItemSchemaFile); + DetourDetach(&client_gcUpdateItemSchema_runJob, hook_client_gcUpdateItemSchema_runJob); + DetourDetach(&server_gcUpdateItemSchema_runJob, hook_server_gcUpdateItemSchema_runJob); + + DetourTransactionCommit(); +} + +bool CPlugin::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) +{ + if (!FindLog()) + return false; + + filesystem = (IBaseFileSystem*)interfaceFactory(BASEFILESYSTEM_INTERFACE_VERSION, NULL); + if (!filesystem) + { + Log({ 255, 0, 0, 255 }, PLUGIN_NAME "Failed to find filesystem\n"); + return false; + } + + FindSignatures(); + + LoadDetours(); + + Log({ 0, 255, 0, 255 }, PLUGIN_NAME "Loaded plugin successfully\n"); + return true; +} + +void CPlugin::Unload() +{ + UnloadDetours(); +} \ No newline at end of file diff --git a/custom_items_games.sln b/custom_items_games.sln index 03e58f0..1000099 100644 --- a/custom_items_games.sln +++ b/custom_items_games.sln @@ -1,25 +1,31 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.3.32922.545 +VisualStudioVersion = 17.10.34916.146 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "custom_items_games", "custom_items_games.vcxproj", "{7657A3ED-0F27-49A7-8967-AB3D2755732C}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "custom_items_games", "custom_items_games.vcxproj", "{776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 + Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7657A3ED-0F27-49A7-8967-AB3D2755732C}.Debug|x86.ActiveCfg = Release|Win32 - {7657A3ED-0F27-49A7-8967-AB3D2755732C}.Debug|x86.Build.0 = Release|Win32 - {7657A3ED-0F27-49A7-8967-AB3D2755732C}.Release|x86.ActiveCfg = Release|Win32 - {7657A3ED-0F27-49A7-8967-AB3D2755732C}.Release|x86.Build.0 = Release|Win32 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Debug|x64.ActiveCfg = Debug|x64 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Debug|x64.Build.0 = Debug|x64 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Debug|x86.ActiveCfg = Debug|Win32 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Debug|x86.Build.0 = Debug|Win32 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Release|x64.ActiveCfg = Release|x64 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Release|x64.Build.0 = Release|x64 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Release|x86.ActiveCfg = Release|Win32 + {776AB4BA-B724-4AE7-ACFE-6E375E0DEC80}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {ADAC55E2-8E9D-408D-8563-4264BA8205C3} + SolutionGuid = {8B9CF3C8-9478-4EFF-A41B-AFAD5A043175} EndGlobalSection EndGlobal diff --git a/custom_items_games.vcxproj b/custom_items_games.vcxproj index bb1e96a..312da3f 100644 --- a/custom_items_games.vcxproj +++ b/custom_items_games.vcxproj @@ -18,22 +18,10 @@ x64 - - - - - - - - - - - - - 16.0 + 17.0 Win32Proj - {7657a3ed-0f27-49a7-8967-ab3d2755732c} + {776ab4ba-b724-4ae7-acfe-6e375e0dec80} customitemsgames 10.0 @@ -82,17 +70,33 @@ + + $(ProjectName)_64 + ..\..\Program Files %28x86%29\Steam\steamapps\common\Team Fortress 2\tf\addons\ + + + $(ProjectName)_64 + ..\..\Program Files %28x86%29\Steam\steamapps\common\Team Fortress 2\tf\addons\ + + + $(ProjectName)_32 + ..\..\Program Files %28x86%29\Steam\steamapps\common\Team Fortress 2\tf\addons\ + + + $(ProjectName)_32 + ..\..\Program Files %28x86%29\Steam\steamapps\common\Team Fortress 2\tf\addons\ + Level3 true - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true - $(CoreLibraryDependencies);%(AdditionalDependencies);detours.lib + detours/detours.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) @@ -101,7 +105,7 @@ true true true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -109,19 +113,20 @@ true true true - $(CoreLibraryDependencies);%(AdditionalDependencies);detours.lib + detours/detours.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) Level3 true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true Console true + detours/x64/detours.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) @@ -130,7 +135,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true @@ -138,8 +143,12 @@ true true true + detours/x64/detours.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + + + diff --git a/detours.h b/detours/detours.h similarity index 100% rename from detours.h rename to detours/detours.h diff --git a/detours.lib b/detours/detours.lib similarity index 72% rename from detours.lib rename to detours/detours.lib index d95e028..ff1d0b9 100644 Binary files a/detours.lib and b/detours/detours.lib differ diff --git a/detours/detours.pdb b/detours/detours.pdb new file mode 100644 index 0000000..a2d9f5b Binary files /dev/null and b/detours/detours.pdb differ diff --git a/detours/x64/detours.lib b/detours/x64/detours.lib new file mode 100644 index 0000000..816a3bf Binary files /dev/null and b/detours/x64/detours.lib differ diff --git a/detours/x64/detours.pdb b/detours/x64/detours.pdb new file mode 100644 index 0000000..b2fb8ab Binary files /dev/null and b/detours/x64/detours.pdb differ diff --git a/filesystem.h b/filesystem.h deleted file mode 100644 index ea061f2..0000000 --- a/filesystem.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#define BASEFILESYSTEM_INTERFACE_VERSION "VBaseFileSystem011" - -typedef void* FileHandle_t; -enum FileSystemSeek_t -{ - FILESYSTEM_SEEK_HEAD = SEEK_SET, - FILESYSTEM_SEEK_CURRENT = SEEK_CUR, - FILESYSTEM_SEEK_TAIL = SEEK_END, -}; - -class IBaseFileSystem -{ -public: - virtual int Read(void* pOutput, int size, FileHandle_t file) = 0; - virtual int Write(void const* pInput, int size, FileHandle_t file) = 0; - virtual FileHandle_t Open(const char* pFileName, const char* pOptions, const char* pathID = 0) = 0; - virtual void Close(FileHandle_t file) = 0; - virtual void Seek(FileHandle_t file, int pos, FileSystemSeek_t seekType) = 0; - virtual unsigned int Tell(FileHandle_t file) = 0; - virtual unsigned int Size(FileHandle_t file) = 0; - virtual unsigned int Size(const char* pFileName, const char* pPathID = 0) = 0; - virtual void Flush(FileHandle_t file) = 0; - virtual bool Precache(const char* pFileName, const char* pPathID = 0) = 0; - virtual bool FileExists(const char* pFileName, const char* pPathID = 0) = 0; -}; \ No newline at end of file diff --git a/functions.h b/functions.h deleted file mode 100644 index bdb126b..0000000 --- a/functions.h +++ /dev/null @@ -1,132 +0,0 @@ -#define CUSTOM_ITEMS_GAME "scripts/items/items_game_custom.txt" -#define CUSTOM_ITEMS_GAME_SIG CUSTOM_ITEMS_GAME ".sig" - -extern IBaseFileSystem* filesystem; - -typedef intptr_t (*econItemSystem)(); -ADDR( - econItemSystem, - "CTFItemSystem", - MOD_SERVER, - \xA1\x2A\x2A\x2A\x2A\x85\xC0\x75\x2A\x56, - x????xxx?x -); - -bool customItemsGameFound = false; - -bool helper_check_custom_itemsgame() -{ - bool foundCustom = true; - if (!filesystem->FileExists(CUSTOM_ITEMS_GAME)) - { - Log(Color(255, 0, 127, 255), "Server: %s not found, loading default items_game.txt ...\n", CUSTOM_ITEMS_GAME); - foundCustom = false; - } - if (!filesystem->FileExists(CUSTOM_ITEMS_GAME_SIG)) - { - Log(Color(255, 0, 127, 255), "Server: %s not found, loading default items_game.txt ...\n", CUSTOM_ITEMS_GAME_SIG); - foundCustom = false; - } - customItemsGameFound = foundCustom; - return foundCustom; -} - -typedef bool (*crypto_verifySignature)(uint8_t*, uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*); -ADDR_GAME( - crypto_verifySignature, - "CCrypto::RSAVerifySignatureSHA256", - \x55\x8B\xEC\x6A\xFF\x68\x2A\x2A\x2A\x2A\x64\xA1\x00\x00\x00\x00\x50\x64\x89\x25\x00\x00\x00\x00\x81\xEC\xCC\x00\x00\x00, - xxxxxx????xxxxxxxxxxxxxxxxxxxx -); -bool hook_crypto_verifySignature(uint8_t*, uint8_t, uint8_t*, uint8_t, uint8_t*, uint8_t*) -{ - return true; -} - -typedef void (__fastcall *econItemSystem_parseItemSchemaFile)(intptr_t, void*, const char*); -ADDR_GAME( - econItemSystem_parseItemSchemaFile, - "CEconItemSystem::ParseItemSchemaFile", - \x55\x8B\xEC\x83\xEC\x14\x8B\x41\x04\x8D\x55\xEC\x83\xC1\x04\xC7\x45\xEC\x00\x00\x00\x00\x52\x68\x2A\x2A\x2A\x2A, - xxxxxxxxxxxxxxxxxxxxxxxx???? -); -void __fastcall hook_server_econItemSystem_parseItemSchemaFile(intptr_t thisptr, void* edx, const char* filename) -{ - if (helper_check_custom_itemsgame()) - { - filename = CUSTOM_ITEMS_GAME; - Log(Color(0, 255, 127, 255), "Server: loading %s...\n", filename); - } - - address_econItemSystem_parseItemSchemaFile[MOD_SERVER](thisptr, edx, filename); -} -void __fastcall hook_client_econItemSystem_parseItemSchemaFile(intptr_t thisptr, void* edx, const char* filename) -{ - if (helper_check_custom_itemsgame()) - { - filename = CUSTOM_ITEMS_GAME; - hook_server_econItemSystem_parseItemSchemaFile(address_econItemSystem[MOD_SERVER](), edx, filename); - Log(Color(0, 255, 127, 255), "Client: Loading %s...\n", filename); - } - address_econItemSystem_parseItemSchemaFile[MOD_CLIENT](thisptr, edx, filename); -} - -bool is_demo_branch() -{ - FileHandle_t f = filesystem->Open("steam.inf", "r"); - if (!f) - { - Log(Color(255, 0, 0, 255), "Failed to open steam.inf\n"); - return false; - } - - bool demo_branch = false; - bool patch_version = false; - - char buffer[256]; - filesystem->Read(buffer, sizeof(buffer), f); - - char* p = strtok(buffer, "=\r\n"); - while (p) - { - if (patch_version) - { - if (atoi(p) <= 8207200) - demo_branch = true; - break; - } - - if (!strcmp(p, "PatchVersion")) - patch_version = true; - - p = strtok(NULL, "=\r\n"); - } - - filesystem->Close(f); - return demo_branch; -} - -typedef bool (__fastcall* gcUpdateItemSchema_runJob)(intptr_t, void*, void*); -ADDR_GAME( - gcUpdateItemSchema_runJob, - "CGCUpdateItemSchema::BYieldingRunGCJob", - \x55\x8B\xEC\x83\xEC\x1C\x53\x57\x8B\xF9\x8D\x4D\xE4, - xxxxxxxxxxxxx -); -void __fastcall hook_gcUpdateItemSchema_runJob(intptr_t thisptr, void* edx, void* packet) -{ - if (customItemsGameFound) - { - Log(Color(0, 255, 127, 255), "Blocked item schema update from GC\n"); - } - else if (is_demo_branch()) - { - Log(Color(0, 255, 127, 255), "Forcefully blocked item schema update from GC (demo branch detected)\n"); - } - else - { - address_gcUpdateItemSchema_runJob.Resolve(Deref(thisptr))(thisptr, edx, packet); - } -} - -#pragma optimize("", on) \ No newline at end of file diff --git a/helpers.h b/helpers.h deleted file mode 100644 index 551e523..0000000 --- a/helpers.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -struct Color -{ - Color(unsigned char _r, unsigned char _g, unsigned char _b, unsigned char _a) - { - r = _r; - g = _g; - b = _b; - a = _a; - } - - unsigned char r; - unsigned char g; - unsigned char b; - unsigned char a; -}; - -#define UNREACHABLE __assume(0) - -#define PLUGIN_NAME "[Custom Items Game] " - -typedef void (*ConColorMsg)(const Color& clr, const char* msg, ...); -ConColorMsg LogFunc = nullptr; - -#define Log(clr, msg, ...) \ -LogFunc(clr, PLUGIN_NAME); \ -LogFunc(clr, msg, __VA_ARGS__); \ No newline at end of file diff --git a/module.h b/module.h deleted file mode 100644 index 189b566..0000000 --- a/module.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -enum ModuleName -{ - MOD_INVALID = -1, - - MOD_CLIENT, - MOD_SERVER, - //MOD_ENGINE, - - MOD_MAX, -}; - -struct ModuleInfo -{ - const char* name; - intptr_t base; - intptr_t size; - - bool Find() - { - char modName[MAX_PATH]; - sprintf(modName, "%s.%s", name, "dll"); - - MODULEINFO modinfo = { 0 }; - HMODULE module = GetModuleHandle(modName); - - if (!module) - { - Log(Color(255, 0, 0, 255), "Failed to get module info for %s\n", modName); - return false; - } - - GetModuleInformation(GetCurrentProcess(), module, &modinfo, sizeof(MODULEINFO)); - base = (intptr_t)modinfo.lpBaseOfDll; - size = (intptr_t)modinfo.SizeOfImage; - - Log(Color(255, 100, 200, 255), "Found module info for %s: Start: 0x%X End: 0x%X (%X)\n", - modName, base, base + size, size); - return true; - } - - bool ValidAddress(intptr_t addr) - { - return (addr > base) && (addr < (base + size)); - } -}; - -#define MODULE(name) #name, 0, 0 - -ModuleInfo modules[MOD_MAX] = -{ - MODULE(client), - MODULE(server), - //MODULE(engine), -}; \ No newline at end of file diff --git a/plugin.cpp b/plugin.cpp deleted file mode 100644 index a9787d0..0000000 --- a/plugin.cpp +++ /dev/null @@ -1,156 +0,0 @@ -#include -#include - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include "detours.h" - -#include "plugin.h" -#include "filesystem.h" - -#include "helpers.h" -#include "module.h" -#include "address.h" -#include "functions.h" - -class CPlugin : public IPlugin -{ -public: - virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory); - virtual void Unload(void); - virtual void Pause(void) {} - virtual void UnPause(void) {} - virtual const char* GetPluginDescription(void) { return "Schema Sig Bypasser"; } - virtual void LevelInit(char const* pMapName) {} - virtual void ServerActivate(edict_t* pEdictList, int edictCount, int clientMax) {} - virtual void GameFrame(bool simulating) {} - virtual void LevelShutdown(void) {} - virtual void ClientActive(edict_t* pEntity) {} - virtual void ClientDisconnect(edict_t* pEntity) {} - virtual void ClientPutInServer(edict_t* pEntity, char const* playername) {} - virtual void SetCommandClient(int index) {} - virtual void ClientSettingsChanged(edict_t* pEdict) {} - virtual PluginResult ClientConnect(bool* bAllowConnect, edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) { return PLUGIN_CONTINUE; } - virtual PluginResult ClientCommand(edict_t* pEntity, const CCommand& args) { return PLUGIN_CONTINUE; } - virtual PluginResult NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) { return PLUGIN_CONTINUE; } - virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t* pPlayerEntity, EQueryCvarValueStatus eStatus, const char* pCvarName, const char* pCvarValue) {} - virtual void OnEdictAllocated(edict_t* edict) {} - virtual void OnEdictFreed(const edict_t* edict) {} - - bool FindLog(); - bool FindModules(); - bool FindAddresses(); - void LoadDetours(); - void UnloadDetours(); -}; - -CPlugin g_Plugin; - -IBaseFileSystem* filesystem = nullptr; - -extern "C" __declspec(dllexport) void* CreateInterface(const char* pName, int* pReturnCode) -{ - if (!strcmp(INTERFACEVERSION_IPLUGIN, pName)) - { - if (pReturnCode) - *pReturnCode = IFACE_OK; - return static_cast(&g_Plugin); - } - - if (pReturnCode) - *pReturnCode = IFACE_FAILED; - return nullptr; -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - return TRUE; -} - -bool CPlugin::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) -{ - if (!FindLog()) - { - Log(Color(255, 0, 0, 255), "Failed to find logging func\n"); - return false; - } - - filesystem = (IBaseFileSystem*)interfaceFactory(BASEFILESYSTEM_INTERFACE_VERSION, NULL); - if (!filesystem) - { - Log(Color(255, 0, 0, 255), "Failed to find filesystem\n"); - return false; - } - - if (!FindModules()) - return false; - - if (!FindAddresses()) - return false; - - LoadDetours(); - - Log(Color(0, 255, 0, 255), "Loaded plugin successfully\n"); - - return true; -} - -void CPlugin::Unload() -{ - UnloadDetours(); -} - -bool CPlugin::FindLog() -{ - HMODULE Handle = LoadLibrary("tier0.dll"); - if (!Handle) - return false; - - LogFunc = (ConColorMsg)GetProcAddress(Handle, "?ConColorMsg@@YAXABVColor@@PBDZZ"); - if (!LogFunc) - return false; - - FreeLibrary(Handle); - return true; -} - -bool CPlugin::FindModules() -{ - bool failed = false; - for (ModuleInfo& mod : modules) - failed |= !mod.Find(); - return !failed; -} - -bool CPlugin::FindAddresses() -{ - bool failed = false; - for (AddressBase* addr : addresses) - failed |= !addr->Find(); - return !failed; -} - -void CPlugin::LoadDetours() -{ - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DETOUR_LOAD(crypto_verifySignature); - DETOUR_LOAD(gcUpdateItemSchema_runJob); - DETOUR_LOAD_GAME(econItemSystem_parseItemSchemaFile); - - DetourTransactionCommit(); -} - -void CPlugin::UnloadDetours() -{ - DetourTransactionBegin(); - DetourUpdateThread(GetCurrentThread()); - - DETOUR_UNLOAD(crypto_verifySignature); - DETOUR_UNLOAD(gcUpdateItemSchema_runJob); - DETOUR_UNLOAD_GAME(econItemSystem_parseItemSchemaFile); - - DetourTransactionCommit(); -} \ No newline at end of file diff --git a/plugin.h b/plugin.h deleted file mode 100644 index 20c6854..0000000 --- a/plugin.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#define INTERFACEVERSION_IPLUGIN "ISERVERPLUGINCALLBACKS003" - -class edict_t; -class CCommand; -enum EQueryCvarValueStatus; - -typedef void* (*CreateInterfaceFn)(const char *pName, int *pReturnCode); -typedef int QueryCvarCookie_t; - -enum PluginResult -{ - PLUGIN_CONTINUE = 0, - PLUGIN_OVERRIDE, - PLUGIN_STOP -}; - -enum InterfaceResult -{ - IFACE_OK = 0, - IFACE_FAILED -}; - -class IPlugin -{ -public: - virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) = 0; - virtual void Unload(void) = 0; - virtual void Pause(void) = 0; - virtual void UnPause(void) = 0; - virtual const char* GetPluginDescription(void) = 0; - virtual void LevelInit(char const* pMapName) = 0; - virtual void ServerActivate(edict_t* pEdictList, int edictCount, int clientMax) = 0; - virtual void GameFrame(bool simulating) = 0; - virtual void LevelShutdown(void) = 0; - virtual void ClientActive(edict_t* pEntity) = 0; - virtual void ClientDisconnect(edict_t* pEntity) = 0; - virtual void ClientPutInServer(edict_t* pEntity, char const* playername) = 0; - virtual void SetCommandClient(int index) = 0; - virtual void ClientSettingsChanged(edict_t* pEdict) = 0; - virtual PluginResult ClientConnect(bool* bAllowConnect, edict_t* pEntity, const char* pszName, const char* pszAddress, char* reject, int maxrejectlen) = 0; - virtual PluginResult ClientCommand(edict_t* pEntity, const CCommand& args) = 0; - virtual PluginResult NetworkIDValidated(const char* pszUserName, const char* pszNetworkID) = 0; - virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t* pPlayerEntity, EQueryCvarValueStatus eStatus, const char* pCvarName, const char* pCvarValue) = 0; - virtual void OnEdictAllocated(edict_t* edict) = 0; - virtual void OnEdictFreed(const edict_t* edict) = 0; -};