diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 33cd1e1e..71d64401 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -119,14 +119,31 @@ bool UTIL_VerifySignature(const void *addr, const char *sig, size_t len) } #if defined PLATFORM_WINDOWS +#define FAKECLIENT_KEY "CreateFakeClient_Windows" +#elif defined PLATFORM_LINUX +#define FAKECLIENT_KEY "CreateFakeClient_Linux" +#elif defined PLATFORM_APPLE +#define FAKECLIENT_KEY "CreateFakeClient_Mac" +#else +#error "Unsupported platform" +#endif + void GetIServer() { + void *addr; const char *sigstr; char sig[32]; size_t siglen; int offset; void *vfunc = NULL; + /* Use the symbol if it exists */ + if (g_pGameConf->GetMemSig("sv", &addr) && addr) + { + iserver = reinterpret_cast(addr); + return; + } + #if defined METAMOD_PLAPI_VERSION || PLAPI_VERSION >= 11 /* Get the CreateFakeClient function pointer */ if (!(vfunc=SH_GET_ORIG_VFNPTR_ENTRY(engine, &IVEngineServer::CreateFakeClient))) @@ -147,7 +164,7 @@ void GetIServer() #endif /* Get signature string for IVEngineServer::CreateFakeClient() */ - sigstr = g_pGameConf->GetKeyValue("CreateFakeClient_Windows"); + sigstr = g_pGameConf->GetKeyValue(FAKECLIENT_KEY); if (!sigstr) { @@ -172,18 +189,6 @@ void GetIServer() /* Finally we have the interface we were looking for */ iserver = *reinterpret_cast(reinterpret_cast(vfunc) + offset); } -#elif defined PLATFORM_POSIX -void GetIServer() -{ - void *addr; - if (!g_pGameConf->GetMemSig("sv", &addr) || !addr) - { - return; - } - - iserver = reinterpret_cast(addr); -} -#endif void GetResourceEntity() { diff --git a/extensions/sdktools/vhelpers.cpp b/extensions/sdktools/vhelpers.cpp index 43e09084..09b7df01 100644 --- a/extensions/sdktools/vhelpers.cpp +++ b/extensions/sdktools/vhelpers.cpp @@ -533,11 +533,26 @@ CEntityFactoryDictionary *GetEntityFactoryDictionary() retData.type = PassType_Basic; void *addr; - if (g_pGameConf->GetMemSig("EntityFactory", &addr) && addr != NULL) + if (!g_pGameConf->GetMemSig("EntityFactory", &addr) || !addr) { - pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); + int offset; + + if (!g_pGameConf->GetMemSig("EntityFactoryCaller", &addr) || !addr) + return NULL; + + if (!g_pGameConf->GetOffset("EntityFactoryCallOffset", &offset)) + return NULL; + + // Get relative offset to function + int32_t funcOffset = *(int32_t *)((intptr_t)addr + offset); + + // Get real address of function + // Address of signature + offset of relative offset + sizeof(int32_t) offset + relative offset + addr = (void *)((intptr_t)addr + offset + 4 + funcOffset); } + pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); + if (pWrapper) { void *returnData = NULL; diff --git a/gamedata/sdktools.games/engine.dota.txt b/gamedata/sdktools.games/engine.dota.txt index bc980d13..9ca41e21 100644 --- a/gamedata/sdktools.games/engine.dota.txt +++ b/gamedata/sdktools.games/engine.dota.txt @@ -146,6 +146,7 @@ * here. */ "CreateFakeClient_Windows" "\x55\x8B\xEC\x56\xFF\x75\x0C\xB9\x2A\x2A\x2A\x2A\xE8" + "CreateFakeClient_Linux" "\x55\x89\xE5\x83\xEC\x2A\x8B\x45\x10\x89\x5D\xF8\x89\x75\xFC\x8B\x5D\x08\xC7\x04\x24\x2A\x2A\x2A\x2A\x89" } "Offsets" @@ -154,6 +155,7 @@ "sv" { "windows" "8" + "linux" "21" } } @@ -186,7 +188,6 @@ "EntityFactory" { "library" "server" - // "linux" "" // TODO "mac" "@_Z23EntityFactoryDictionaryv" } @@ -196,6 +197,13 @@ "library" "server" "windows" "\xFF\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xC8\xC7" } + + // EntityFactoryDictionary is difficult to find on Linux due to multiple matches. This finds a caller of it instead. + "EntityFactoryCaller" + { + "library" "server" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x89\x45" + } } "Offsets" @@ -204,6 +212,12 @@ { "windows" "4" } + + // This is the offset into the address found by the EntityFactoryCaller signature. + "EntityFactoryCallOffset" + { + "linux" "10" + } } }