- added new system for detecting convar/concmd removals in one nice place
authorDavid Anderson <dvander@alliedmods.net>
Tue Oct 16 01:17:08 2007 +0000 (2007-10-16)
changeset 15826f18465dd9f9
parent 1581 2562512b4a44
child 1583 1b92a3e4b962
- added new system for detecting convar/concmd removals in one nice place
- convar code overhaul - reorganized handle contents to make removal easier
core/ConVarManager.cpp
core/ConVarManager.h
core/concmd_cleaner.cpp
core/concmd_cleaner.h
core/msvc8/sourcemod_mm.vcproj
core/smn_console.cpp
core/sourcemm_api.cpp
core/sourcemm_api.h
     1.1 --- a/core/ConVarManager.cpp	Mon Oct 15 22:15:22 2007 +0000
     1.2 +++ b/core/ConVarManager.cpp	Tue Oct 16 01:17:08 2007 +0000
     1.3 @@ -37,6 +37,7 @@
     1.4  #include "sm_srvcmds.h"
     1.5  #include "sm_stringutil.h"
     1.6  #include <sh_vector.h>
     1.7 +#include <sm_trie_tpl.h>
     1.8  
     1.9  ConVarManager g_ConVarManager;
    1.10  
    1.11 @@ -45,31 +46,14 @@
    1.12  
    1.13  const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
    1.14  typedef List<const ConVar *> ConVarList;
    1.15 +KTrie<ConVarInfo *> convar_cache;
    1.16  
    1.17  ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
    1.18  {
    1.19 -#if PLAPI_VERSION < 12
    1.20 -	m_IgnoreHandle = false;
    1.21 -#endif
    1.22 -
    1.23 -	/* Create a convar lookup trie */
    1.24 -	m_ConVarCache = sm_trie_create();
    1.25  }
    1.26  
    1.27  ConVarManager::~ConVarManager()
    1.28  {
    1.29 -	List<ConVarInfo *>::iterator iter;
    1.30 -
    1.31 -	/* Destroy our convar lookup trie */
    1.32 -	sm_trie_destroy(m_ConVarCache);
    1.33 -
    1.34 -	/* Destroy all the ConVarInfo structures */
    1.35 -	for (iter = m_ConVars.begin(); iter != m_ConVars.end(); iter++)
    1.36 -	{
    1.37 -		delete (*iter);
    1.38 -	}
    1.39 -
    1.40 -	m_ConVars.clear();
    1.41  }
    1.42  
    1.43  void ConVarManager::OnSourceModAllInitialized()
    1.44 @@ -101,6 +85,48 @@
    1.45  
    1.46  void ConVarManager::OnSourceModShutdown()
    1.47  {
    1.48 +	List<ConVarInfo *>::iterator iter = m_ConVars.begin();
    1.49 +	HandleSecurity sec(NULL, g_pCoreIdent);
    1.50 +
    1.51 +	/* Iterate list of ConVarInfo structures, remove every one of them */
    1.52 +	while (iter != m_ConVars.end())
    1.53 +	{
    1.54 +		ConVarInfo *pInfo = (*iter);
    1.55 +
    1.56 +		iter = m_ConVars.erase(iter);
    1.57 +
    1.58 +		g_HandleSys.FreeHandle(pInfo->handle, &sec);
    1.59 +		if (pInfo->pChangeForward != NULL)
    1.60 +		{
    1.61 +			g_Forwards.ReleaseForward(pInfo->pChangeForward);
    1.62 +		}
    1.63 +		if (pInfo->sourceMod)
    1.64 +		{
    1.65 +			/* If we created it, we won't be tracking it, therefore it is 
    1.66 +			 * safe to remove everything in one go.
    1.67 +			 */
    1.68 +			META_UNREGCVAR(pInfo->pVar);
    1.69 +			delete [] pInfo->pVar->GetName();
    1.70 +			delete [] pInfo->pVar->GetHelpText();
    1.71 +			delete [] pInfo->pVar->GetDefault();
    1.72 +			delete pInfo->pVar;
    1.73 +		}
    1.74 +		else
    1.75 +		{
    1.76 +			/* If we didn't create it, we might be tracking it.  Also, 
    1.77 +			 * it could be unreadable.
    1.78 +			 */
    1.79 +			UntrackConCommandBase(pInfo->pVar, this);
    1.80 +		}
    1.81 +
    1.82 +		/* It's not safe to read the name here, so we simply delete the 
    1.83 +		 * the info struct and clear the lookup cache at the end.
    1.84 +		 */
    1.85 +		delete pInfo;
    1.86 +	}
    1.87 +	convar_cache.clear();
    1.88 +
    1.89 +	/* Unhook things */
    1.90  	if (m_bIsDLLQueryHooked)
    1.91  	{
    1.92  		SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
    1.93 @@ -112,21 +138,6 @@
    1.94  		m_bIsVSPQueryHooked = false;
    1.95  	}
    1.96  
    1.97 -	IChangeableForward *fwd;
    1.98 -	List<ConVarInfo *>::iterator i;
    1.99 -
   1.100 -	/* Iterate list of ConVarInfo structures */
   1.101 -	for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
   1.102 -	{
   1.103 -		fwd = (*i)->pChangeForward;
   1.104 -
   1.105 -		/* Free any convar-change forwards that still exist */
   1.106 -		if (fwd)
   1.107 -		{
   1.108 -			g_Forwards.ReleaseForward(fwd);
   1.109 -		}
   1.110 -	}
   1.111 -
   1.112  	/* Remove the 'convars' option from the 'sm' console command */
   1.113  	g_RootMenu.RemoveRootConsoleCommand("cvars", this);
   1.114  
   1.115 @@ -165,54 +176,55 @@
   1.116  	m_bIsVSPQueryHooked = true;
   1.117  }
   1.118  
   1.119 -#if PLAPI_VERSION >= 12
   1.120 -void ConVarManager::OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
   1.121 +bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
   1.122  {
   1.123 -	/* Only check convars that have not been created by SourceMod's core */
   1.124 -	if (id != g_PLID && !pCommand->IsCommand())
   1.125 +	ConVarInfo **pLookup = convar_cache.retrieve(name);
   1.126 +	if (pLookup != NULL)
   1.127  	{
   1.128 -		ConVarInfo *pInfo;
   1.129 -		const char *cvarName = pCommand->GetName();
   1.130 -		HandleSecurity sec(NULL, g_pCoreIdent);
   1.131 -		bool handleExists = sm_trie_retrieve(m_ConVarCache, cvarName, reinterpret_cast<void **>(&pInfo));
   1.132 -
   1.133 -		if (handleExists)
   1.134 -		{
   1.135 -			g_HandleSys.FreeHandle(pInfo->handle, &sec);
   1.136 -			sm_trie_delete(m_ConVarCache, cvarName);
   1.137 -			m_ConVars.remove(pInfo);
   1.138 -		}
   1.139 +		*pVar = *pLookup;
   1.140 +		return true;
   1.141 +	}
   1.142 +	else
   1.143 +	{
   1.144 +		return false;
   1.145  	}
   1.146  }
   1.147  
   1.148 -#else
   1.149 +void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
   1.150 +{
   1.151 +	/* Only check convars that have not been created by SourceMod's core */
   1.152 +	ConVarInfo *pInfo;
   1.153 +	if (!convar_cache_lookup(name, &pInfo))
   1.154 +	{
   1.155 +		return;
   1.156 +	}
   1.157  
   1.158 -/* I truly detest this code */
   1.159 -void ConVarManager::OnMetamodPluginUnloaded(PluginId id)
   1.160 -{
   1.161 -	ConVarInfo *pInfo;
   1.162 -	const char *cvarName;
   1.163  	HandleSecurity sec(NULL, g_pCoreIdent);
   1.164  
   1.165 -	List<ConVarInfo *>::iterator i;
   1.166 -	for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
   1.167 +	/* Remove it from our cache */
   1.168 +	m_ConVars.remove(pInfo);
   1.169 +	convar_cache.remove(name);
   1.170 +
   1.171 +	/* Now make sure no plugins are referring to this pointer */
   1.172 +	IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
   1.173 +	while (pl_iter->MorePlugins())
   1.174  	{
   1.175 -		pInfo = (*i);
   1.176 -		cvarName = pInfo->name;
   1.177 +		IPlugin *pl = pl_iter->GetPlugin();
   1.178  
   1.179 -		if (cvarName && !icvar->FindVar(cvarName))
   1.180 +		ConVarList *pConVarList;
   1.181 +		if (pl->GetProperty("ConVarList", (void **)&pConVarList, true) 
   1.182 +			&& pConVarList != NULL)
   1.183  		{
   1.184 -			m_IgnoreHandle = true;
   1.185 -			g_HandleSys.FreeHandle(pInfo->handle, &sec);
   1.186 -
   1.187 -			sm_trie_delete(m_ConVarCache, cvarName);
   1.188 -			m_ConVars.erase(i);
   1.189 +			pConVarList->remove(pInfo->pVar);
   1.190 +		}
   1.191  
   1.192 -			delete [] cvarName;
   1.193 -		}
   1.194 +		pl_iter->NextPlugin();
   1.195  	}
   1.196 +
   1.197 +	/* Free resources */
   1.198 +	g_HandleSys.FreeHandle(pInfo->handle, &sec);
   1.199 +	delete pInfo;
   1.200  }
   1.201 -#endif
   1.202  
   1.203  void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
   1.204  {
   1.205 @@ -227,33 +239,6 @@
   1.206  
   1.207  void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
   1.208  {
   1.209 -#if PLAPI_VERSION < 12
   1.210 -	/* Lovely workaround for our workaround! */
   1.211 -	if (m_IgnoreHandle)
   1.212 -	{
   1.213 -		m_IgnoreHandle = false;
   1.214 -		return;
   1.215 -	}
   1.216 -#endif
   1.217 -
   1.218 -	ConVarInfo *info;
   1.219 -	ConVar *pConVar = static_cast<ConVar *>(object);
   1.220 -
   1.221 -	/* Find convar in lookup trie */
   1.222 -	sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast<void **>(&info));
   1.223 -
   1.224 -	/* If convar was created by SourceMod plugin... */
   1.225 -	if (info->sourceMod)
   1.226 -	{
   1.227 -		/* Then unlink it from SourceMM */
   1.228 -		g_SMAPI->UnregisterConCommandBase(g_PLAPI, pConVar);
   1.229 -
   1.230 -		/* Delete string allocations */
   1.231 -		delete [] pConVar->GetName(); 
   1.232 -		delete [] pConVar->GetDefault();
   1.233 -		delete [] pConVar->GetHelpText();
   1.234 -		delete pConVar;
   1.235 -	}
   1.236  }
   1.237  
   1.238  void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   1.239 @@ -320,28 +305,33 @@
   1.240  		AddConVarToPluginList(pContext, pConVar);
   1.241  
   1.242  		/* First find out if we already have a handle to it */
   1.243 -		if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo))
   1.244 +		if (convar_cache_lookup(name, &pInfo))
   1.245  		{
   1.246  			return pInfo->handle;
   1.247  		}
   1.248  		else
   1.249  		{
   1.250 -			/* If we don't, then create a new handle from the convar */
   1.251 -			hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
   1.252 -
   1.253  			/* Create and initialize ConVarInfo structure */
   1.254  			pInfo = new ConVarInfo();
   1.255 -			pInfo->handle = hndl;
   1.256  			pInfo->sourceMod = false;
   1.257  			pInfo->pChangeForward = NULL;
   1.258  			pInfo->origCallback = pConVar->GetCallback();
   1.259 -		#if PLAPI_VERSION < 12
   1.260 -			pInfo->name = sm_strdup(pConVar->GetName());
   1.261 -		#endif
   1.262 +			pInfo->pVar = pConVar;
   1.263 +
   1.264 +			/* If we don't, then create a new handle from the convar */
   1.265 +			hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
   1.266 +			if (hndl == BAD_HANDLE)
   1.267 +			{
   1.268 +				delete pInfo;
   1.269 +				return BAD_HANDLE;
   1.270 +			}
   1.271 +
   1.272 +			pInfo->handle = hndl;
   1.273  
   1.274  			/* Insert struct into caches */
   1.275  			m_ConVars.push_back(pInfo);
   1.276 -			sm_trie_insert(m_ConVarCache, name, pInfo);
   1.277 +			convar_cache.insert(name, pInfo);
   1.278 +			TrackConCommandBase(pConVar, this);
   1.279  
   1.280  			return hndl;
   1.281  		}
   1.282 @@ -360,28 +350,33 @@
   1.283  		pBase = const_cast<ConCommandBase *>(pBase->GetNext());
   1.284  	}
   1.285  
   1.286 -	/* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */
   1.287 -	pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max);
   1.288 -
   1.289 -	/* Add convar to plugin's list */
   1.290 -	AddConVarToPluginList(pContext, pConVar);
   1.291 -
   1.292 -	/* Create a handle from the new convar */
   1.293 -	hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
   1.294 -
   1.295  	/* Create and initialize ConVarInfo structure */
   1.296  	pInfo = new ConVarInfo();
   1.297  	pInfo->handle = hndl;
   1.298  	pInfo->sourceMod = true;
   1.299  	pInfo->pChangeForward = NULL;
   1.300  	pInfo->origCallback = NULL;
   1.301 -#if PLAPI_VERSION < 12
   1.302 -	pInfo->name = NULL;
   1.303 -#endif
   1.304 +
   1.305 +	/* Create a handle from the new convar */
   1.306 +	hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
   1.307 +	if (hndl == BAD_HANDLE)
   1.308 +	{
   1.309 +		delete pInfo;
   1.310 +		return BAD_HANDLE;
   1.311 +	}
   1.312 +
   1.313 +	pInfo->handle = hndl;
   1.314 +
   1.315 +	/* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */
   1.316 +	pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max);
   1.317 +	pInfo->pVar = pConVar;
   1.318 +
   1.319 +	/* Add convar to plugin's list */
   1.320 +	AddConVarToPluginList(pContext, pConVar);
   1.321  
   1.322  	/* Insert struct into caches */
   1.323  	m_ConVars.push_back(pInfo);
   1.324 -	sm_trie_insert(m_ConVarCache, name, pInfo);
   1.325 +	convar_cache.insert(name, pInfo);
   1.326  
   1.327  	return hndl;
   1.328  }
   1.329 @@ -402,27 +397,32 @@
   1.330  	}
   1.331  
   1.332  	/* At this point, the convar exists. So, find out if we already have a handle */
   1.333 -	if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo))
   1.334 +	if (convar_cache_lookup(name, &pInfo))
   1.335  	{
   1.336  		return pInfo->handle;
   1.337  	}
   1.338  
   1.339 -	/* If we don't have a handle, then create a new one */
   1.340 -	hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
   1.341 -
   1.342  	/* Create and initialize ConVarInfo structure */
   1.343  	pInfo = new ConVarInfo();
   1.344 -	pInfo->handle = hndl;
   1.345  	pInfo->sourceMod = false;
   1.346  	pInfo->pChangeForward = NULL;
   1.347  	pInfo->origCallback = pConVar->GetCallback();
   1.348 -#if PLAPI_VERSION < 12
   1.349 -	pInfo->name = sm_strdup(pConVar->GetName());
   1.350 -#endif
   1.351 +	pInfo->pVar = pConVar;
   1.352 +
   1.353 +	/* If we don't have a handle, then create a new one */
   1.354 +	hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
   1.355 +	if (hndl == BAD_HANDLE)
   1.356 +	{
   1.357 +		delete pInfo;
   1.358 +		return BAD_HANDLE;
   1.359 +	}
   1.360 +
   1.361 +	pInfo->handle = hndl;
   1.362  
   1.363  	/* Insert struct into our caches */
   1.364  	m_ConVars.push_back(pInfo);
   1.365 -	sm_trie_insert(m_ConVarCache, name, pInfo);
   1.366 +	convar_cache.insert(name, pInfo);
   1.367 +	TrackConCommandBase(pConVar, this);
   1.368  
   1.369  	return hndl;
   1.370  }
   1.371 @@ -433,7 +433,7 @@
   1.372  	IChangeableForward *pForward;
   1.373  
   1.374  	/* Find the convar in the lookup trie */
   1.375 -	if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
   1.376 +	if (convar_cache_lookup(pConVar->GetName(), &pInfo))
   1.377  	{
   1.378  		/* Get the forward */
   1.379  		pForward = pInfo->pChangeForward;
   1.380 @@ -460,7 +460,7 @@
   1.381  	IPluginContext *pContext = pFunction->GetParentContext();
   1.382  
   1.383  	/* Find the convar in the lookup trie */
   1.384 -	if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
   1.385 +	if (convar_cache_lookup(pConVar->GetName(), &pInfo))
   1.386  	{
   1.387  		/* Get the forward */
   1.388  		pForward = pInfo->pChangeForward;
   1.389 @@ -569,11 +569,13 @@
   1.390  		return;
   1.391  	}
   1.392  
   1.393 -	Trie *pCache = g_ConVarManager.GetConVarCache();
   1.394  	ConVarInfo *pInfo;
   1.395  
   1.396  	/* Find the convar in the lookup trie */
   1.397 -	sm_trie_retrieve(pCache, pConVar->GetName(), (void **)&pInfo);
   1.398 +	if (!convar_cache_lookup(pConVar->GetName(), &pInfo))
   1.399 +	{
   1.400 +		return;
   1.401 +	}
   1.402  
   1.403  	FnChangeCallback_t origCallback = pInfo->origCallback;
   1.404  	IChangeableForward *pForward = pInfo->pChangeForward;
   1.405 @@ -642,6 +644,23 @@
   1.406  	}
   1.407  }
   1.408  
   1.409 +HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
   1.410 +{
   1.411 +	ConVarInfo *pInfo;
   1.412 +	HandleError error;
   1.413 +	
   1.414 +	if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
   1.415 +	{
   1.416 +		return error;
   1.417 +	}
   1.418 +
   1.419 +	if (pVar)
   1.420 +	{
   1.421 +		*pVar = pInfo->pVar;
   1.422 +	}
   1.423 +
   1.424 +	return error;
   1.425 +}
   1.426  
   1.427  static int s_YamagramState = 0;
   1.428  
     2.1 --- a/core/ConVarManager.h	Mon Oct 15 22:15:22 2007 +0000
     2.2 +++ b/core/ConVarManager.h	Tue Oct 16 01:17:08 2007 +0000
     2.3 @@ -34,13 +34,13 @@
     2.4  
     2.5  #include "sm_globals.h"
     2.6  #include "sourcemm_api.h"
     2.7 -#include "sm_trie.h"
     2.8  #include <sh_list.h>
     2.9  #include <IPluginSys.h>
    2.10  #include <IForwardSys.h>
    2.11  #include <IHandleSys.h>
    2.12  #include <IRootConsoleMenu.h>
    2.13  #include <compat_wrappers.h>
    2.14 +#include "concmd_cleaner.h"
    2.15  
    2.16  using namespace SourceHook;
    2.17  
    2.18 @@ -49,13 +49,11 @@
    2.19   */
    2.20  struct ConVarInfo
    2.21  {
    2.22 -	Handle_t handle;					/**< Handle to convar */
    2.23 +	Handle_t handle;					/**< Handle to self */
    2.24  	bool sourceMod;						/**< Determines whether or not convar was created by a SourceMod plugin */
    2.25  	IChangeableForward *pChangeForward;	/**< Forward associated with convar */
    2.26  	FnChangeCallback_t origCallback;	/**< The original callback function */
    2.27 -#if PLAPI_VERSION < 12
    2.28 -	const char *name;					/**< Name of convar */
    2.29 -#endif
    2.30 +	ConVar *pVar;						/**< The actual convar */
    2.31  };
    2.32  
    2.33  /**
    2.34 @@ -72,7 +70,8 @@
    2.35  	public SMGlobalClass,
    2.36  	public IHandleTypeDispatch,
    2.37  	public IPluginsListener,
    2.38 -	public IRootConsoleCommand
    2.39 +	public IRootConsoleCommand,
    2.40 +	public IConCommandTracker
    2.41  {
    2.42  public:
    2.43  	ConVarManager();
    2.44 @@ -87,22 +86,8 @@
    2.45  	void OnPluginUnloaded(IPlugin *plugin);
    2.46  public: //IRootConsoleCommand
    2.47  	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
    2.48 -public:
    2.49 -	/**
    2.50 -	 * Get the 'ConVar' handle type ID.
    2.51 -	 */
    2.52 -	inline HandleType_t GetHandleType()
    2.53 -	{
    2.54 -		return m_ConVarType;
    2.55 -	}
    2.56 -
    2.57 -	/**
    2.58 -	 * Get the convar lookup trie.
    2.59 -	 */
    2.60 -	inline Trie *GetConVarCache()
    2.61 -	{
    2.62 -		return m_ConVarCache;
    2.63 -	}
    2.64 +public: //IConCommandTracker
    2.65 +	void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
    2.66  public:
    2.67  	/**
    2.68  	 * Create a convar and return a handle to it.
    2.69 @@ -133,17 +118,8 @@
    2.70  
    2.71  	bool IsQueryingSupported();
    2.72  
    2.73 -#if PLAPI_VERSION >= 12
    2.74 -	/**
    2.75 -	 * Called when Metamod:Source is about to remove convar
    2.76 -	 */
    2.77 -	void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand);
    2.78 -#else
    2.79 -	/**
    2.80 -	 * Called when Metamod:Source has unloaded a plugin
    2.81 -	 */
    2.82 -	void OnMetamodPluginUnloaded(PluginId id);
    2.83 -#endif
    2.84 +	HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
    2.85 +
    2.86  private:
    2.87  	/**
    2.88  	 * Adds a convar to a plugin's list.
    2.89 @@ -168,12 +144,8 @@
    2.90  	HandleType_t m_ConVarType;
    2.91  	List<ConVarInfo *> m_ConVars;
    2.92  	List<ConVarQuery> m_ConVarQueries;
    2.93 -	Trie *m_ConVarCache;
    2.94  	bool m_bIsDLLQueryHooked;
    2.95  	bool m_bIsVSPQueryHooked;
    2.96 -#if PLAPI_VERSION < 12
    2.97 -	bool m_IgnoreHandle;
    2.98 -#endif
    2.99  };
   2.100  
   2.101  extern ConVarManager g_ConVarManager;
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/concmd_cleaner.cpp	Tue Oct 16 01:17:08 2007 +0000
     3.3 @@ -0,0 +1,175 @@
     3.4 +/**
     3.5 + * vim: set ts=4 :
     3.6 + * =============================================================================
     3.7 + * SourceMod
     3.8 + * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     3.9 + * =============================================================================
    3.10 + *
    3.11 + * This program is free software; you can redistribute it and/or modify it under
    3.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    3.13 + * Free Software Foundation.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    3.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.18 + * details.
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License along with
    3.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    3.22 + *
    3.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    3.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    3.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    3.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    3.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    3.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    3.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    3.30 + * or <http://www.sourcemod.net/license.php>.
    3.31 + *
    3.32 + * Version: $Id$
    3.33 + */
    3.34 +
    3.35 +#include "sm_globals.h"
    3.36 +#include <sh_list.h>
    3.37 +#include <convar.h>
    3.38 +#include "concmd_cleaner.h"
    3.39 +#include "sm_stringutil.h"
    3.40 +#include "sourcemm_api.h"
    3.41 +
    3.42 +#if defined ORANGEBOX_BUILD
    3.43 +SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
    3.44 +#endif
    3.45 +
    3.46 +using namespace SourceHook;
    3.47 +
    3.48 +struct ConCommandInfo
    3.49 +{
    3.50 +	ConCommandBase *pBase;
    3.51 +	IConCommandTracker *cls;
    3.52 +	char name[64];
    3.53 +};
    3.54 +
    3.55 +List<ConCommandInfo *> tracked_bases;
    3.56 +
    3.57 +ConCommandBase *FindConCommandBase(const char *name);
    3.58 +
    3.59 +class ConCommandCleaner : public SMGlobalClass
    3.60 +{
    3.61 +public:
    3.62 +#if defined ORANGEBOX_BUILD
    3.63 +	void OnSourceModAllInitialized()
    3.64 +	{
    3.65 +		SH_ADD_HOOK(ICvar, UnregisterConCommand, SH_NOATTRIB, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
    3.66 +	}
    3.67 +
    3.68 +	void OnSourceModShutdown()
    3.69 +	{
    3.70 +		SH_REMOVE_HOOK(ICvar, UnregisterConCommand, SH_NOATTRIB, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
    3.71 +	}
    3.72 +#endif
    3.73 +
    3.74 +	void UnlinkConCommandBase(ConCommandBase *pBase)
    3.75 +	{
    3.76 +		ConCommandInfo *pInfo;
    3.77 +		List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
    3.78 +
    3.79 +		if (pBase)
    3.80 +		{
    3.81 +			while (iter != tracked_bases.end())
    3.82 +			{
    3.83 +				if ((*iter)->pBase == pBase)
    3.84 +				{
    3.85 +					pInfo = (*iter);
    3.86 +					iter = tracked_bases.erase(iter);
    3.87 +					pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
    3.88 +					delete pInfo;
    3.89 +				}
    3.90 +				else
    3.91 +				{
    3.92 +					iter++;
    3.93 +				}
    3.94 +			}
    3.95 +		}
    3.96 +		else
    3.97 +		{
    3.98 +			while (iter != tracked_bases.end())
    3.99 +			{
   3.100 +				/* This is just god-awful! */
   3.101 +				if (FindConCommandBase((*iter)->name) != (*iter)->pBase)
   3.102 +				{
   3.103 +					pInfo = (*iter);
   3.104 +					iter = tracked_bases.erase(iter);
   3.105 +					pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
   3.106 +					delete pInfo;
   3.107 +				}
   3.108 +				else
   3.109 +				{
   3.110 +					iter++;
   3.111 +				}
   3.112 +			}
   3.113 +		}
   3.114 +	}
   3.115 +
   3.116 +	void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
   3.117 +	{
   3.118 +		ConCommandInfo *info = new ConCommandInfo;
   3.119 +
   3.120 +		info->pBase = pBase;
   3.121 +		info->cls = cls;
   3.122 +		strncopy(info->name, pBase->GetName(), sizeof(info->name));
   3.123 +
   3.124 +		tracked_bases.push_back(info);
   3.125 +	}
   3.126 +
   3.127 +	void RemoveTarget(ConCommandBase *pBase, IConCommandTracker *cls)
   3.128 +	{
   3.129 +		List<ConCommandInfo *>::iterator iter;
   3.130 +		ConCommandInfo *pInfo;
   3.131 +
   3.132 +		iter = tracked_bases.begin();
   3.133 +		while (iter != tracked_bases.end())
   3.134 +		{
   3.135 +			pInfo = (*iter);
   3.136 +			if (pInfo->pBase == pBase && pInfo->cls == cls)
   3.137 +			{
   3.138 +				delete pInfo;
   3.139 +				iter = tracked_bases.erase(iter);
   3.140 +			}
   3.141 +			else
   3.142 +			{
   3.143 +				iter++;
   3.144 +			}
   3.145 +		}
   3.146 +	}
   3.147 +} s_ConCmdTracker;
   3.148 +
   3.149 +ConCommandBase *FindConCommandBase(const char *name)
   3.150 +{
   3.151 +	const ConCommandBase *pBase = icvar->GetCommands();
   3.152 +
   3.153 +	while (pBase != NULL)
   3.154 +	{
   3.155 +		if (strcmp(pBase->GetName(), name) == 0)
   3.156 +		{
   3.157 +			return const_cast<ConCommandBase *>(pBase);
   3.158 +		}
   3.159 +		pBase = pBase->GetNext();
   3.160 +	}
   3.161 +
   3.162 +	return NULL;
   3.163 +}
   3.164 +
   3.165 +void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
   3.166 +{
   3.167 +	s_ConCmdTracker.AddTarget(pBase, me);
   3.168 +}
   3.169 +
   3.170 +void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
   3.171 +{
   3.172 +	s_ConCmdTracker.RemoveTarget(pBase, me);
   3.173 +}
   3.174 +
   3.175 +void Global_OnUnlinkConCommandBase(ConCommandBase *pBase)
   3.176 +{
   3.177 +	s_ConCmdTracker.UnlinkConCommandBase(pBase);
   3.178 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/core/concmd_cleaner.h	Tue Oct 16 01:17:08 2007 +0000
     4.3 @@ -0,0 +1,41 @@
     4.4 +/**
     4.5 + * vim: set ts=4 :
     4.6 + * =============================================================================
     4.7 + * SourceMod
     4.8 + * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     4.9 + * =============================================================================
    4.10 + *
    4.11 + * This program is free software; you can redistribute it and/or modify it under
    4.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    4.13 + * Free Software Foundation.
    4.14 + * 
    4.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    4.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    4.18 + * details.
    4.19 + *
    4.20 + * You should have received a copy of the GNU General Public License along with
    4.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    4.22 + *
    4.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    4.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    4.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    4.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    4.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    4.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    4.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    4.30 + * or <http://www.sourcemod.net/license.php>.
    4.31 + *
    4.32 + * Version: $Id$
    4.33 + */
    4.34 +
    4.35 +class IConCommandTracker
    4.36 +{
    4.37 +public:
    4.38 +	virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe) = 0;
    4.39 +};
    4.40 +
    4.41 +void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
    4.42 +void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
    4.43 +void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
    4.44 +
     5.1 --- a/core/msvc8/sourcemod_mm.vcproj	Mon Oct 15 22:15:22 2007 +0000
     5.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Tue Oct 16 01:17:08 2007 +0000
     5.3 @@ -610,6 +610,10 @@
     5.4  				>
     5.5  			</File>
     5.6  			<File
     5.7 +				RelativePath="..\concmd_cleaner.cpp"
     5.8 +				>
     5.9 +			</File>
    5.10 +			<File
    5.11  				RelativePath="..\ConCmdManager.cpp"
    5.12  				>
    5.13  			</File>
    5.14 @@ -804,6 +808,10 @@
    5.15  				>
    5.16  			</File>
    5.17  			<File
    5.18 +				RelativePath="..\concmd_cleaner.h"
    5.19 +				>
    5.20 +			</File>
    5.21 +			<File
    5.22  				RelativePath="..\ConCmdManager.h"
    5.23  				>
    5.24  			</File>
     6.1 --- a/core/smn_console.cpp	Mon Oct 15 22:15:22 2007 +0000
     6.2 +++ b/core/smn_console.cpp	Tue Oct 16 01:17:08 2007 +0000
     6.3 @@ -110,7 +110,9 @@
     6.4  	if (IsFlagSet(pConVar, FCVAR_PROTECTED))
     6.5  	{
     6.6  		pEvent->SetString("cvarvalue", "***PROTECTED***");
     6.7 -	} else {
     6.8 +	}
     6.9 +	else
    6.10 +	{
    6.11  		pEvent->SetString("cvarvalue", pConVar->GetString());
    6.12  	}
    6.13  
    6.14 @@ -141,7 +143,7 @@
    6.15  
    6.16  	if (hndl == BAD_HANDLE)
    6.17  	{
    6.18 -		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
    6.19 +		return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
    6.20  	}
    6.21  
    6.22  	return hndl;
    6.23 @@ -162,7 +164,7 @@
    6.24  	HandleError err;
    6.25  	ConVar *pConVar;
    6.26  
    6.27 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.28 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.29  		!= HandleError_None)
    6.30  	{
    6.31  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.32 @@ -186,7 +188,7 @@
    6.33  	HandleError err;
    6.34  	ConVar *pConVar;
    6.35  
    6.36 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.37 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.38  		!= HandleError_None)
    6.39  	{
    6.40  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.41 @@ -210,7 +212,7 @@
    6.42  	HandleError err;
    6.43  	ConVar *pConVar;
    6.44  
    6.45 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.46 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.47  		!= HandleError_None)
    6.48  	{
    6.49  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.50 @@ -225,7 +227,7 @@
    6.51  	HandleError err;
    6.52  	ConVar *pConVar;
    6.53  
    6.54 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.55 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.56  		!= HandleError_None)
    6.57  	{
    6.58  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.59 @@ -241,7 +243,7 @@
    6.60  	HandleError err;
    6.61  	ConVar *pConVar;
    6.62  
    6.63 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.64 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.65  		!= HandleError_None)
    6.66  	{
    6.67  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.68 @@ -270,7 +272,7 @@
    6.69  	HandleError err;
    6.70  	ConVar *pConVar;
    6.71  
    6.72 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.73 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.74  		!= HandleError_None)
    6.75  	{
    6.76  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.77 @@ -287,7 +289,7 @@
    6.78  	HandleError err;
    6.79  	ConVar *pConVar;
    6.80  
    6.81 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.82 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.83  		!= HandleError_None)
    6.84  	{
    6.85  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.86 @@ -317,7 +319,7 @@
    6.87  	HandleError err;
    6.88  	ConVar *pConVar;
    6.89  
    6.90 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
    6.91 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
    6.92  		!= HandleError_None)
    6.93  	{
    6.94  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
    6.95 @@ -334,7 +336,7 @@
    6.96  	HandleError err;
    6.97  	ConVar *pConVar;
    6.98  
    6.99 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.100 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.101  		!= HandleError_None)
   6.102  	{
   6.103  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.104 @@ -366,7 +368,7 @@
   6.105  	HandleError err;
   6.106  	ConVar *pConVar;
   6.107  
   6.108 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.109 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.110  		!= HandleError_None)
   6.111  	{
   6.112  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.113 @@ -395,7 +397,7 @@
   6.114  	HandleError err;
   6.115  	ConVar *pConVar;
   6.116  
   6.117 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.118 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.119  		!= HandleError_None)
   6.120  	{
   6.121  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.122 @@ -410,7 +412,7 @@
   6.123  	HandleError err;
   6.124  	ConVar *pConVar;
   6.125  
   6.126 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.127 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.128  		!= HandleError_None)
   6.129  	{
   6.130  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.131 @@ -427,7 +429,7 @@
   6.132  	HandleError err;
   6.133  	ConVar *pConVar;
   6.134  
   6.135 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.136 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.137  		!= HandleError_None)
   6.138  	{
   6.139  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.140 @@ -461,7 +463,7 @@
   6.141  	HandleError err;
   6.142  	ConVar *pConVar;
   6.143  
   6.144 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.145 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.146  		!= HandleError_None)
   6.147  	{
   6.148  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
   6.149 @@ -488,7 +490,7 @@
   6.150  	HandleError err;
   6.151  	ConVar *pConVar;
   6.152  
   6.153 -	if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
   6.154 +	if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
   6.155  		!= HandleError_None)
   6.156  	{
   6.157  		return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
     7.1 --- a/core/sourcemm_api.cpp	Mon Oct 15 22:15:22 2007 +0000
     7.2 +++ b/core/sourcemm_api.cpp	Tue Oct 16 01:17:08 2007 +0000
     7.3 @@ -33,7 +33,7 @@
     7.4  #include "sourcemm_api.h"
     7.5  #include "sm_version.h"
     7.6  #include "Logger.h"
     7.7 -#include "ConVarManager.h"
     7.8 +#include "concmd_cleaner.h"
     7.9  
    7.10  SourceMod_Core g_SourceMod_Core;
    7.11  IVEngineServer *engine = NULL;
    7.12 @@ -203,14 +203,18 @@
    7.13  	}
    7.14  }
    7.15  
    7.16 -#if PLAPI_VERSION >= 12
    7.17 +#if defined METAMOD_PLAPI_VERSION
    7.18 +
    7.19  void SourceMod_Core::OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
    7.20  {
    7.21 -	g_ConVarManager.OnUnlinkConCommandBase(id, pCommand);
    7.22 +	Global_OnUnlinkConCommandBase(pCommand);
    7.23  }
    7.24 +
    7.25  #else
    7.26 +
    7.27  void SourceMod_Core::OnPluginUnload(PluginId id)
    7.28  {
    7.29 -	g_ConVarManager.OnMetamodPluginUnloaded(id);
    7.30 +	Global_OnUnlinkConCommandBase(NULL);
    7.31  }
    7.32 +
    7.33  #endif
     8.1 --- a/core/sourcemm_api.h	Mon Oct 15 22:15:22 2007 +0000
     8.2 +++ b/core/sourcemm_api.h	Tue Oct 16 01:17:08 2007 +0000
     8.3 @@ -74,7 +74,7 @@
     8.4  	const char *GetLogTag();
     8.5  public:
     8.6  	void OnVSPListening(IServerPluginCallbacks *iface);
     8.7 -#if PLAPI_VERSION >= 12
     8.8 +#if defined METAMOD_PLAPI_VERSION
     8.9  	void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand);
    8.10  #else
    8.11  	void OnPluginUnload(PluginId id);