diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index f245efff..0f0f39ae 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -41,6 +41,16 @@ ConVarManager g_ConVarManager; +#if !defined ORANGEBOX_BUILD +#define CallGlobalChangeCallbacks CallGlobalChangeCallback +#endif + +#if defined ORANGEBOX_BUILD +SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float); +#else +SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *); +#endif + SH_DECL_HOOK5_void(IServerGameDLL, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *); SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB, 0, QueryCvarCookie_t, edict_t *, EQueryCvarValueStatus, const char *, const char *); @@ -56,6 +66,19 @@ ConVarManager::~ConVarManager() { } +void ConVarManager::OnSourceModStartup(bool late) +{ + HandleAccess sec; + + /* Set up access rights for the 'ConVar' handle type */ + sec.access[HandleAccess_Read] = 0; + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; + + /* Create the 'ConVar' handle type */ + m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); +} + void ConVarManager::OnSourceModAllInitialized() { /** @@ -69,15 +92,7 @@ void ConVarManager::OnSourceModAllInitialized() } #endif - HandleAccess sec; - - /* Set up access rights for the 'ConVar' handle type */ - sec.access[HandleAccess_Read] = 0; - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER; - - /* Create the 'ConVar' handle type */ - m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL); + SH_ADD_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false); /* Add the 'convars' option to the 'sm' console command */ g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this); @@ -138,6 +153,8 @@ void ConVarManager::OnSourceModShutdown() m_bIsVSPQueryHooked = false; } + SH_REMOVE_HOOK_STATICFUNC(ICvar, CallGlobalChangeCallbacks, icvar, OnConVarChanged, false); + /* Remove the 'convars' option from the 'sm' console command */ g_RootMenu.RemoveRootConsoleCommand("cvars", this); @@ -243,7 +260,7 @@ void ConVarManager::OnHandleDestroy(HandleType_t type, void *object) bool ConVarManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize) { - *pSize = sizeof(ConVar); + *pSize = sizeof(ConVar) + sizeof(ConVarInfo); return true; } @@ -321,7 +338,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, pInfo = new ConVarInfo(); pInfo->sourceMod = false; pInfo->pChangeForward = NULL; - pInfo->origCallback = pConVar->GetCallback(); pInfo->pVar = pConVar; /* If we don't, then create a new handle from the convar */ @@ -361,7 +377,6 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, pInfo->handle = hndl; pInfo->sourceMod = true; pInfo->pChangeForward = NULL; - pInfo->origCallback = NULL; /* Create a handle from the new convar */ hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); @@ -412,7 +427,6 @@ Handle_t ConVarManager::FindConVar(const char *name) pInfo = new ConVarInfo(); pInfo->sourceMod = false; pInfo->pChangeForward = NULL; - pInfo->origCallback = pConVar->GetCallback(); pInfo->pVar = pConVar; /* If we don't have a handle, then create a new one */ @@ -433,6 +447,33 @@ Handle_t ConVarManager::FindConVar(const char *name) return hndl; } +void ConVarManager::AddConVarChangeListener(const char *name, IConVarChangeListener *pListener) +{ + ConVarInfo *pInfo; + + if (FindConVar(name) == BAD_HANDLE) + { + return; + } + + /* Find the convar in the lookup trie */ + if (convar_cache_lookup(name, &pInfo)) + { + pInfo->changeListeners.push_back(pListener); + } +} + +void ConVarManager::RemoveConVarChangeListener(const char *name, IConVarChangeListener *pListener) +{ + ConVarInfo *pInfo; + + /* Find the convar in the lookup trie */ + if (convar_cache_lookup(name, &pInfo)) + { + pInfo->changeListeners.remove(pListener); + } +} + void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction) { ConVarInfo *pInfo; @@ -449,9 +490,6 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction { pForward = g_Forwards.CreateForwardEx(NULL, ET_Ignore, 3, CONVARCHANGE_PARAMS); pInfo->pChangeForward = pForward; - - /* Install our own callback */ - pConVar->InstallChangeCallback(OnConVarChanged); } /* Add function to forward's list */ @@ -491,9 +529,6 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti /* Free this forward */ g_Forwards.ReleaseForward(pForward); pInfo->pChangeForward = NULL; - - /* Put back the original convar callback */ - pConVar->InstallChangeCallback(pInfo->origCallback); } } } @@ -561,15 +596,12 @@ void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar } #if defined ORANGEBOX_BUILD -void ConVarManager::OnConVarChanged(IConVar *pIConVar, const char *oldValue, float flOldValue) +void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) #else void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) #endif { /* If the values are the same, exit early in order to not trigger callbacks */ -#if defined ORANGEBOX_BUILD - ConVar *pConVar = (ConVar *)pIConVar; -#endif if (strcmp(pConVar->GetString(), oldValue) == 0) { return; @@ -583,24 +615,30 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue) return; } - FnChangeCallback_t origCallback = pInfo->origCallback; IChangeableForward *pForward = pInfo->pChangeForward; - /* If there was a change callback installed previously, call it */ - if (origCallback) + if (pInfo->changeListeners.size() != 0) { + for (List::iterator i = pInfo->changeListeners.begin(); + i != pInfo->changeListeners.end(); + i++) + { #if defined ORANGEBOX_BUILD - origCallback(pConVar, oldValue, flOldValue); + (*i)->OnConVarChanged(pConVar, oldValue, flOldValue); #else - origCallback(pConVar, oldValue); + (*i)->OnConVarChanged(pConVar, oldValue, atof(oldValue)); #endif + } } - /* Now call forwards in plugins that have hooked this */ - pForward->PushCell(pInfo->handle); - pForward->PushString(oldValue); - pForward->PushString(reinterpret_cast(pConVar)->GetString()); - pForward->Execute(NULL); + if (pForward != NULL) + { + /* Now call forwards in plugins that have hooked this */ + pForward->PushCell(pInfo->handle); + pForward->PushString(oldValue); + pForward->PushString(pConVar->GetString()); + pForward->Execute(NULL); + } } bool ConVarManager::IsQueryingSupported() @@ -815,14 +853,10 @@ void _IntExt_EnableYamagrams() } } -#if defined ORANGEBOX_BUILD -void _IntExt_OnHostnameChanged(IConVar *pConVar, const char *oldValue, float flOldValue) -#else -void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue) -#endif +void _IntExt_OnHostnameChanged(ConVar *pConVar, const char *oldValue, float flOldValue) { if (strcmp(oldValue, "Good morning, DS-san.") == 0 - && strcmp(reinterpret_cast(pConVar)->GetString(), "Good night, talking desk lamp.") == 0) + && strcmp(pConVar->GetString(), "Good night, talking desk lamp.") == 0) { _IntExt_EnableYamagrams(); } diff --git a/core/ConVarManager.h b/core/ConVarManager.h index 6757bbde..ac921ec5 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -44,6 +44,12 @@ using namespace SourceHook; +class IConVarChangeListener +{ +public: + virtual void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) =0; +}; + /** * Holds SourceMod-specific information about a convar */ @@ -52,8 +58,8 @@ struct ConVarInfo Handle_t handle; /**< Handle to self */ bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */ IChangeableForward *pChangeForward; /**< Forward associated with convar */ - FnChangeCallback_t origCallback; /**< The original callback function */ ConVar *pVar; /**< The actual convar */ + List changeListeners; }; /** @@ -77,6 +83,7 @@ public: ConVarManager(); ~ConVarManager(); public: // SMGlobalClass + void OnSourceModStartup(bool late); void OnSourceModAllInitialized(); void OnSourceModShutdown(); void OnSourceModVSPReceived(); @@ -111,6 +118,9 @@ public: */ void UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFunction); + void AddConVarChangeListener(const char *name, IConVarChangeListener *pListener); + void RemoveConVarChangeListener(const char *name, IConVarChangeListener *pListener); + /** * Starts a query to find the value of a client convar. */ @@ -131,7 +141,7 @@ private: * Static callback that Valve's ConVar object executes when the convar's value changes. */ #if defined ORANGEBOX_BUILD - static void OnConVarChanged(IConVar *pConVar, const char *oldValue, float flOldValue); + static void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue); #else static void OnConVarChanged(ConVar *pConVar, const char *oldValue); #endif diff --git a/core/TimerSys.cpp b/core/TimerSys.cpp index 464d4373..5831dd40 100644 --- a/core/TimerSys.cpp +++ b/core/TimerSys.cpp @@ -34,19 +34,10 @@ #include "ForwardSys.h" #include "sourcemm_api.h" #include "frame_hooks.h" +#include "ConVarManager.h" #define TIMER_MIN_ACCURACY 0.1 -#if !defined ORANGEBOX_BUILD -#define CallGlobalChangeCallbacks CallGlobalChangeCallback -#endif - -#if defined ORANGEBOX_BUILD -SH_DECL_HOOK3_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *, float); -#else -SH_DECL_HOOK2_void(ICvar, CallGlobalChangeCallbacks, SH_NOATTRIB, false, ConVar *, const char *); -#endif - TimerSystem g_Timers; double g_fUniversalTime = 0.0f; float g_fGameStartTime = 0.0f; /* Game game start time, non-universal */ @@ -74,7 +65,8 @@ time_t GetAdjustedTime(time_t *buf) class DefaultMapTimer : public IMapTimer, - public SMGlobalClass + public SMGlobalClass, + public IConVarChangeListener { public: DefaultMapTimer() @@ -118,34 +110,20 @@ public: mp_timelimit->SetValue(mp_timelimit->GetInt() + extra_time); } -#if defined ORANGEBOX_BUILD - void GlobalChangeCallback(ConVar *pVar, const char *old_value, float flOldValue) -#else - void GlobalChangeCallback(ConVar *pVar, const char *old_value) -#endif + void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) { - if (pVar != mp_timelimit) - { - return; - } - - if (atoi(old_value) == pVar->GetInt()) - { - return; - } - g_Timers.MapTimeLeftChanged(); } private: void Enable() { - SH_ADD_HOOK_MEMFUNC(ICvar, CallGlobalChangeCallbacks, icvar, this, &DefaultMapTimer::GlobalChangeCallback, false); + g_ConVarManager.AddConVarChangeListener("mp_timelimit", this); } void Disable() { - SH_REMOVE_HOOK_MEMFUNC(ICvar, CallGlobalChangeCallbacks, icvar, this, &DefaultMapTimer::GlobalChangeCallback, false); + g_ConVarManager.RemoveConVarChangeListener("mp_timelimit", this); } private: diff --git a/core/sm_srvcmds.cpp b/core/sm_srvcmds.cpp index cbacadd0..657a8176 100644 --- a/core/sm_srvcmds.cpp +++ b/core/sm_srvcmds.cpp @@ -34,6 +34,7 @@ #include "sm_stringutil.h" #include "HandleSys.h" #include "CoreConfig.h" +#include "ConVarManager.h" RootConsoleMenu g_RootMenu; @@ -57,11 +58,16 @@ RootConsoleMenu::~RootConsoleMenu() m_Menu.clear(); } -#if defined ORANGEBOX_BUILD - extern void _IntExt_OnHostnameChanged(IConVar *var, const char *pOldValue, float flOldValue); -#else - extern void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue); -#endif +extern void _IntExt_OnHostnameChanged(ConVar *var, const char *pOldValue, float flOldValue); + +class DetectHostNameChanges : public IConVarChangeListener +{ +public: + void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue) + { + _IntExt_OnHostnameChanged(pConVar, oldValue, flOldValue); + } +} s_HostnameChangeDetector; void RootConsoleMenu::OnSourceModStartup(bool late) { @@ -71,13 +77,16 @@ void RootConsoleMenu::OnSourceModStartup(bool late) CONVAR_REGISTER(this); AddRootConsoleCommand("version", "Display version information", this); AddRootConsoleCommand("credits", "Display credits listing", this); +} - ConVar *pHost = icvar->FindVar("hostname"); - pHost->InstallChangeCallback(_IntExt_OnHostnameChanged); +void RootConsoleMenu::OnSourceModAllInitialized() +{ + g_ConVarManager.AddConVarChangeListener("hostname", &s_HostnameChangeDetector); } void RootConsoleMenu::OnSourceModShutdown() { + g_ConVarManager.RemoveConVarChangeListener("hostname", &s_HostnameChangeDetector); RemoveRootConsoleCommand("credits", this); RemoveRootConsoleCommand("version", this); } diff --git a/core/sm_srvcmds.h b/core/sm_srvcmds.h index 1562bda2..c3950909 100644 --- a/core/sm_srvcmds.h +++ b/core/sm_srvcmds.h @@ -63,6 +63,7 @@ public: //IConCommandBaseAccessor bool RegisterConCommandBase(ConCommandBase *pCommand); public: //SMGlobalClass void OnSourceModStartup(bool late); + void OnSourceModAllInitialized(); void OnSourceModShutdown(); public: //IRootConsoleCommand void OnRootConsoleCommand(const char *cmdname, const CCommand &command); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 26d9b22c..9b88b66c 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -281,6 +281,11 @@ void SourceModBase::StartSourceMod(bool late) enginePatch = SH_GET_CALLCLASS(engine); gamedllPatch = SH_GET_CALLCLASS(gamedll); + g_ShareSys.Initialize(); + + /* Make the global core identity */ + g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); + /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; while (pBase) @@ -289,9 +294,6 @@ void SourceModBase::StartSourceMod(bool late) pBase = pBase->m_pGlobalClassNext; } - /* Make the global core identity */ - g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); - /* Notify! */ pBase = SMGlobalClass::head; while (pBase) diff --git a/core/systems/ShareSys.cpp b/core/systems/ShareSys.cpp index c3bf2c2d..196c4eb0 100644 --- a/core/systems/ShareSys.cpp +++ b/core/systems/ShareSys.cpp @@ -54,7 +54,7 @@ IdentityToken_t *ShareSystem::CreateCoreIdentity() return CreateIdentity(m_CoreType, this); } -void ShareSystem::OnSourceModStartup(bool late) +void ShareSystem::Initialize() { TypeAccess sec; diff --git a/core/systems/ShareSys.h b/core/systems/ShareSys.h index 60e99c21..998ec98a 100644 --- a/core/systems/ShareSys.h +++ b/core/systems/ShareSys.h @@ -84,7 +84,7 @@ public: //IShareSys void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives); public: //SMGlobalClass /* Pre-empt in case anything tries to register idents early */ - void OnSourceModStartup(bool late); + void Initialize(); void OnSourceModShutdown(); public: //IHandleTypeDispatch void OnHandleDestroy(HandleType_t type, void *object);