From 939b10bd8e9654da78b1cbcf1ca1824adb429b38 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings <nshastings@gmail.com> Date: Sat, 13 Dec 2014 15:48:51 -0500 Subject: [PATCH 1/3] Refactor SDKTools to not expose gamerules ptr ptr outside of vglobals.cpp. --- extensions/sdktools/extension.cpp | 7 ++- extensions/sdktools/extension.h | 5 ++ extensions/sdktools/gamerulesnatives.cpp | 58 ++++++++++++------------ extensions/sdktools/vcaller.cpp | 17 +++---- extensions/sdktools/vglobals.cpp | 12 +++-- extensions/sdktools/vglobals.h | 2 +- 6 files changed, 54 insertions(+), 47 deletions(-) diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index 061010cf..05a8bb7e 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -340,6 +340,8 @@ bool SDKTools::RegisterConCommandBase(ConCommandBase *pVar) bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) { + m_bAnyLevelInited = true; + const char *name; char key[32]; int count, n = 1; @@ -472,10 +474,7 @@ public: virtual void *GetGameRules() { - if (!g_pGameRules) - return NULL; - - return *g_pGameRules; + return GameRules(); } } g_SDKTools_API; diff --git a/extensions/sdktools/extension.h b/extensions/sdktools/extension.h index 97b9f45b..00144e4f 100644 --- a/extensions/sdktools/extension.h +++ b/extensions/sdktools/extension.h @@ -107,6 +107,11 @@ public: //ICommandTargetProcessor public: bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); +public: + bool HasAnyLevelInited() { return m_bAnyLevelInited; } + +private: + bool m_bAnyLevelInited = false; }; extern SDKTools g_SdkTools; diff --git a/extensions/sdktools/gamerulesnatives.cpp b/extensions/sdktools/gamerulesnatives.cpp index 8a7ad34e..98cd2a4a 100644 --- a/extensions/sdktools/gamerulesnatives.cpp +++ b/extensions/sdktools/gamerulesnatives.cpp @@ -163,7 +163,9 @@ static cell_t GameRules_GetProp(IPluginContext *pContext, const cell_t *params) int bit_count; bool is_unsigned; - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + void *pGameRules = GameRules(); + + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); @@ -185,8 +187,6 @@ static cell_t GameRules_GetProp(IPluginContext *pContext, const cell_t *params) bit_count = params[2] * 8; } - void *pGameRules = *g_pGameRules; - if (bit_count >= 17) { return *(int32_t *)((intptr_t)pGameRules + offset); @@ -232,11 +232,13 @@ static cell_t GameRules_SetProp(IPluginContext *pContext, const cell_t *params) if (params[5] == 0) sendChange = false; + void *pGameRules = GameRules(); + CBaseEntity *pProxy = NULL; if (sendChange && ((pProxy = GetGameRulesProxyEnt()) == NULL)) return pContext->ThrowNativeError("Couldn't find gamerules proxy entity"); - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed"); pContext->LocalToString(params[1], &prop); @@ -250,8 +252,6 @@ static cell_t GameRules_SetProp(IPluginContext *pContext, const cell_t *params) } #endif - void *pGameRules = *g_pGameRules; - if (bit_count < 1) { bit_count = params[3] * 8; @@ -304,15 +304,15 @@ static cell_t GameRules_GetPropFloat(IPluginContext *pContext, const cell_t *par int offset; int bit_count; - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + void *pGameRules = GameRules(); + + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Float, "float"); - void *pGameRules = *g_pGameRules; - float val = *(float *)((intptr_t)pGameRules + offset); return sp_ftoc(val); @@ -329,18 +329,19 @@ static cell_t GameRules_SetPropFloat(IPluginContext *pContext, const cell_t *par if (params[4] == 0) sendChange = false; + void *pGameRules = GameRules(); + CBaseEntity *pProxy = NULL; if (sendChange && ((pProxy = GetGameRulesProxyEnt()) == NULL)) return pContext->ThrowNativeError("Couldn't find gamerules proxy entity."); - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Float, "float"); - void *pGameRules = *g_pGameRules; float newVal = sp_ctof(params[2]); *(float *)((intptr_t)pGameRules + offset) = newVal; @@ -361,15 +362,15 @@ static cell_t GameRules_GetPropEnt(IPluginContext *pContext, const cell_t *param int offset; int bit_count; - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + void *pGameRules = GameRules(); + + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Int, "Integer"); - void *pGameRules = *g_pGameRules; - CBaseHandle &hndl = *(CBaseHandle *)((intptr_t)pGameRules + offset); CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(hndl.GetEntryIndex()); @@ -392,19 +393,19 @@ static cell_t GameRules_SetPropEnt(IPluginContext *pContext, const cell_t *param if (params[4] == 0) sendChange = false; + void *pGameRules = GameRules(); + CBaseEntity *pProxy = NULL; if (sendChange && ((pProxy = GetGameRulesProxyEnt()) == NULL)) return pContext->ThrowNativeError("Couldn't find gamerules proxy entity."); - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Int, "integer"); - void *pGameRules = *g_pGameRules; - CBaseHandle &hndl = *(CBaseHandle *)((intptr_t)pGameRules + offset); CBaseEntity *pOther; @@ -451,15 +452,15 @@ static cell_t GameRules_GetPropVector(IPluginContext *pContext, const cell_t *pa int offset; int bit_count; - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + void *pGameRules = GameRules(); + + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Vector, "vector"); - void *pGameRules = *g_pGameRules; - Vector *v = (Vector *)((intptr_t)pGameRules + offset); cell_t *vec; @@ -483,19 +484,19 @@ static cell_t GameRules_SetPropVector(IPluginContext *pContext, const cell_t *pa if (params[4] == 0) sendChange = false; + void *pGameRules = GameRules(); + CBaseEntity *pProxy = NULL; if (sendChange && ((pProxy = GetGameRulesProxyEnt()) == NULL)) return pContext->ThrowNativeError("Couldn't find gamerules proxy entity."); - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); FIND_PROP_SEND(DPT_Vector, "vector"); - void *pGameRules = *g_pGameRules; - Vector *v = (Vector *)((intptr_t)pGameRules + offset); cell_t *vec; @@ -523,7 +524,9 @@ static cell_t GameRules_GetPropString(IPluginContext *pContext, const cell_t *pa char *prop; int offset; - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + void *pGameRules = GameRules(); + + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); @@ -544,8 +547,6 @@ static cell_t GameRules_GetPropString(IPluginContext *pContext, const cell_t *pa DPT_String); } - void *pGameRules = *g_pGameRules; - size_t len; const char *src; @@ -585,11 +586,13 @@ static cell_t GameRules_SetPropString(IPluginContext *pContext, const cell_t *pa if (params[3] == 0) sendChange = false; + void *pGameRules = GameRules(); + CBaseEntity *pProxy = NULL; if (sendChange && ((pProxy = GetGameRulesProxyEnt()) == NULL)) return pContext->ThrowNativeError("Couldn't find gamerules proxy entity."); - if (!g_pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) + if (!pGameRules || !g_szGameRulesProxy || !strcmp(g_szGameRulesProxy, "")) return pContext->ThrowNativeError("Gamerules lookup failed."); pContext->LocalToString(params[1], &prop); @@ -610,7 +613,6 @@ static cell_t GameRules_SetPropString(IPluginContext *pContext, const cell_t *pa DPT_String); } - void *pGameRules = *g_pGameRules; maxlen = DT_MAX_STRING_BUFFERSIZE; char *src; diff --git a/extensions/sdktools/vcaller.cpp b/extensions/sdktools/vcaller.cpp index 9cf6af65..ebcfe186 100644 --- a/extensions/sdktools/vcaller.cpp +++ b/extensions/sdktools/vcaller.cpp @@ -320,20 +320,17 @@ static cell_t SDKCall(IPluginContext *pContext, const cell_t *params) break; case ValveCall_GameRules: { - if (g_pGameRules == NULL) + void *pGameRules = GameRules(); + if (pGameRules == NULL) { vc->stk_put(ptr); - return pContext->ThrowNativeError("GameRules unsupported or not available; file a bug report"); - } - void *gamerules = *g_pGameRules; - - if (gamerules == NULL) - { - vc->stk_put(ptr); - return pContext->ThrowNativeError("GameRules not available before map is loaded"); + if (g_SdkTools.HasAnyLevelInited()) + return pContext->ThrowNativeError("GameRules unsupported or not available; file a bug report"); + else + return pContext->ThrowNativeError("GameRules not available before map is loaded"); } - *(void **)ptr = gamerules; + *(void **)ptr = pGameRules; } break; case ValveCall_EntityList: diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 54b533bd..1526dc12 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -32,10 +32,14 @@ #include "extension.h" #include "vhelpers.h" -void **g_pGameRules = NULL; -void *g_EntList = NULL; +static void **g_ppGameRules = nullptr; +void *g_EntList = nullptr; CBaseHandle g_ResourceEntity; +void *GameRules() +{ + return g_ppGameRules ? *g_ppGameRules : g_ppGameRules; +} void InitializeValveGlobals() { @@ -52,7 +56,7 @@ void InitializeValveGlobals() char *addr; if (g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) && addr) { - g_pGameRules = reinterpret_cast<void **>(addr); + g_ppGameRules = reinterpret_cast<void **>(addr); } else if (g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) && addr) { @@ -61,7 +65,7 @@ void InitializeValveGlobals() { return; } - g_pGameRules = *reinterpret_cast<void ***>(addr + offset); + g_ppGameRules = *reinterpret_cast<void ***>(addr + offset); } } diff --git a/extensions/sdktools/vglobals.h b/extensions/sdktools/vglobals.h index 5cc2081e..773e9d80 100644 --- a/extensions/sdktools/vglobals.h +++ b/extensions/sdktools/vglobals.h @@ -32,13 +32,13 @@ #ifndef _INCLUDE_SDKTOOLS_VGLOBALS_H_ #define _INCLUDE_SDKTOOLS_VGLOBALS_H_ -extern void **g_pGameRules; extern void *g_EntList; extern CBaseHandle g_ResourceEntity; void InitializeValveGlobals(); void GetIServer(); +void *GameRules(); void GetResourceEntity(); From 88cb74213c06e73fd0f7e0470301ff1ccf15ebbd Mon Sep 17 00:00:00 2001 From: Nicholas Hastings <nshastings@gmail.com> Date: Sat, 13 Dec 2014 16:35:32 -0500 Subject: [PATCH 2/3] Add support for getting g_pGameRules without a byte signature / symbol. --- extensions/sdktools/extension.cpp | 2 + extensions/sdktools/vglobals.cpp | 78 ++++++++++++++++++++++++++++- extensions/sdktools/vglobals.h | 1 + gamedata/sdktools.games/game.tf.txt | 1 + 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index 05a8bb7e..ae3f1f38 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -342,6 +342,8 @@ bool SDKTools::LevelInit(char const *pMapName, char const *pMapEntities, char co { m_bAnyLevelInited = true; + UpdateValveGlobals(); + const char *name; char key[32]; int count, n = 1; diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 1526dc12..2c581130 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -32,13 +32,14 @@ #include "extension.h" #include "vhelpers.h" +static void *s_pGameRules = nullptr; static void **g_ppGameRules = nullptr; void *g_EntList = nullptr; CBaseHandle g_ResourceEntity; void *GameRules() { - return g_ppGameRules ? *g_ppGameRules : g_ppGameRules; + return g_ppGameRules ? *g_ppGameRules : s_pGameRules; } void InitializeValveGlobals() @@ -69,6 +70,81 @@ void InitializeValveGlobals() } } +static bool UTIL_FindDataTable(SendTable *pTable, + const char *name, + sm_sendprop_info_t *info, + unsigned int offset = 0) +{ + const char *pname; + int props = pTable->GetNumProps(); + SendProp *prop; + SendTable *table; + + for (int i = 0; i<props; i++) + { + prop = pTable->GetProp(i); + + if ((table = prop->GetDataTable()) != NULL) + { + pname = prop->GetName(); + if (pname && strcmp(name, pname) == 0) + { + info->prop = prop; + info->actual_offset = offset + info->prop->GetOffset(); + return true; + } + + if (UTIL_FindDataTable(table, + name, + info, + offset + prop->GetOffset()) + ) + { + return true; + } + } + } + + return false; +} + +static ServerClass *UTIL_FindServerClass(const char *classname) +{ + ServerClass *sc = gamedll->GetAllServerClasses(); + while (sc) + { + if (strcmp(classname, sc->GetName()) == 0) + { + return sc; + } + sc = sc->m_pNext; + } + + return NULL; +} + +void UpdateValveGlobals() +{ + s_pGameRules = nullptr; + + const char *pszNetClass = g_pGameConf->GetKeyValue("GameRulesProxy"); + const char *pszDTName = g_pGameConf->GetKeyValue("GameRulesDataTable"); + if (pszNetClass && pszDTName) + { + ServerClass *sc = UTIL_FindServerClass(pszNetClass); + sm_sendprop_info_t info; + if (UTIL_FindDataTable(sc->m_pTable, pszDTName, &info)) + { + auto proxyFn = info.prop->GetDataTableProxyFn(); + if (proxyFn) + { + CSendProxyRecipients recp; + s_pGameRules = proxyFn(nullptr, nullptr, nullptr, &recp, 0); + } + } + } +} + size_t UTIL_StringToSignature(const char *str, char buffer[], size_t maxlength) { size_t real_bytes = 0; diff --git a/extensions/sdktools/vglobals.h b/extensions/sdktools/vglobals.h index 773e9d80..1b6e045f 100644 --- a/extensions/sdktools/vglobals.h +++ b/extensions/sdktools/vglobals.h @@ -37,6 +37,7 @@ extern void *g_EntList; extern CBaseHandle g_ResourceEntity; void InitializeValveGlobals(); +void UpdateValveGlobals(); void GetIServer(); void *GameRules(); diff --git a/gamedata/sdktools.games/game.tf.txt b/gamedata/sdktools.games/game.tf.txt index 62fd79f1..bba489f8 100644 --- a/gamedata/sdktools.games/game.tf.txt +++ b/gamedata/sdktools.games/game.tf.txt @@ -111,6 +111,7 @@ "Keys" { "GameRulesProxy" "CTFGameRulesProxy" + "GameRulesDataTable" "tf_gamerules_data" } } } From 0d67bcc5baa6ba254944fd56da89e6606cdf745f Mon Sep 17 00:00:00 2001 From: Nicholas Hastings <nshastings@gmail.com> Date: Sun, 14 Dec 2014 15:21:54 -0500 Subject: [PATCH 3/3] Add null-check on serverclass in gamerules lookup. --- extensions/sdktools/vglobals.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 2c581130..1fa7a815 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -120,7 +120,7 @@ static ServerClass *UTIL_FindServerClass(const char *classname) sc = sc->m_pNext; } - return NULL; + return nullptr; } void UpdateValveGlobals() @@ -131,9 +131,10 @@ void UpdateValveGlobals() const char *pszDTName = g_pGameConf->GetKeyValue("GameRulesDataTable"); if (pszNetClass && pszDTName) { - ServerClass *sc = UTIL_FindServerClass(pszNetClass); sm_sendprop_info_t info; - if (UTIL_FindDataTable(sc->m_pTable, pszDTName, &info)) + ServerClass *sc = UTIL_FindServerClass(pszNetClass); + + if (sc && UTIL_FindDataTable(sc->m_pTable, pszDTName, &info)) { auto proxyFn = info.prop->GetDataTableProxyFn(); if (proxyFn)