diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index 061010cf..ae3f1f38 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -340,6 +340,10 @@ 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; + + UpdateValveGlobals(); + const char *name; char key[32]; int count, n = 1; @@ -472,10 +476,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..1fa7a815 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -32,10 +32,15 @@ #include "extension.h" #include "vhelpers.h" -void **g_pGameRules = NULL; -void *g_EntList = NULL; +static void *s_pGameRules = nullptr; +static void **g_ppGameRules = nullptr; +void *g_EntList = nullptr; CBaseHandle g_ResourceEntity; +void *GameRules() +{ + return g_ppGameRules ? *g_ppGameRules : s_pGameRules; +} void InitializeValveGlobals() { @@ -52,7 +57,7 @@ void InitializeValveGlobals() char *addr; if (g_pGameConf->GetMemSig("g_pGameRules", (void **)&addr) && addr) { - g_pGameRules = reinterpret_cast(addr); + g_ppGameRules = reinterpret_cast(addr); } else if (g_pGameConf->GetMemSig("CreateGameRulesObject", (void **)&addr) && addr) { @@ -61,7 +66,83 @@ void InitializeValveGlobals() { return; } - g_pGameRules = *reinterpret_cast(addr + offset); + g_ppGameRules = *reinterpret_cast(addr + offset); + } +} + +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; iGetProp(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 nullptr; +} + +void UpdateValveGlobals() +{ + s_pGameRules = nullptr; + + const char *pszNetClass = g_pGameConf->GetKeyValue("GameRulesProxy"); + const char *pszDTName = g_pGameConf->GetKeyValue("GameRulesDataTable"); + if (pszNetClass && pszDTName) + { + sm_sendprop_info_t info; + ServerClass *sc = UTIL_FindServerClass(pszNetClass); + + if (sc && UTIL_FindDataTable(sc->m_pTable, pszDTName, &info)) + { + auto proxyFn = info.prop->GetDataTableProxyFn(); + if (proxyFn) + { + CSendProxyRecipients recp; + s_pGameRules = proxyFn(nullptr, nullptr, nullptr, &recp, 0); + } + } } } diff --git a/extensions/sdktools/vglobals.h b/extensions/sdktools/vglobals.h index 5cc2081e..1b6e045f 100644 --- a/extensions/sdktools/vglobals.h +++ b/extensions/sdktools/vglobals.h @@ -32,13 +32,14 @@ #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 UpdateValveGlobals(); void GetIServer(); +void *GameRules(); void GetResourceEntity(); 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" } } }