- rewrote internal convar hooking mechanism to prevent crashes and potential "race conditions"

- sharesys is now the first thing to run, so g_pCoreIdent is valid EVERYWHERE
- added internal convar hooking funcs for timersys

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401776
This commit is contained in:
David Anderson 2007-12-06 03:28:02 +00:00
parent 9ab9eba5d7
commit d78d7ab960
8 changed files with 115 additions and 81 deletions

View File

@ -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<IConVarChangeListener *>::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<ConVar *>(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<ConVar *>(pConVar)->GetString(), "Good night, talking desk lamp.") == 0)
&& strcmp(pConVar->GetString(), "Good night, talking desk lamp.") == 0)
{
_IntExt_EnableYamagrams();
}

View File

@ -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<IConVarChangeListener *> 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

View File

@ -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:

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -54,7 +54,7 @@ IdentityToken_t *ShareSystem::CreateCoreIdentity()
return CreateIdentity(m_CoreType, this);
}
void ShareSystem::OnSourceModStartup(bool late)
void ShareSystem::Initialize()
{
TypeAccess sec;

View File

@ -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);