- added new system for detecting convar/concmd removals in one nice place
- convar code overhaul - reorganized handle contents to make removal easier --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401588
This commit is contained in:
parent
60d8e4f248
commit
796d9b2de8
@ -37,6 +37,7 @@
|
||||
#include "sm_srvcmds.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include <sh_vector.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
|
||||
ConVarManager g_ConVarManager;
|
||||
|
||||
@ -45,31 +46,14 @@ SH_DECL_HOOK5_void(IServerPluginCallbacks, OnQueryCvarValueFinished, SH_NOATTRIB
|
||||
|
||||
const ParamType CONVARCHANGE_PARAMS[] = {Param_Cell, Param_String, Param_String};
|
||||
typedef List<const ConVar *> ConVarList;
|
||||
KTrie<ConVarInfo *> convar_cache;
|
||||
|
||||
ConVarManager::ConVarManager() : m_ConVarType(0), m_bIsDLLQueryHooked(false), m_bIsVSPQueryHooked(false)
|
||||
{
|
||||
#if PLAPI_VERSION < 12
|
||||
m_IgnoreHandle = false;
|
||||
#endif
|
||||
|
||||
/* Create a convar lookup trie */
|
||||
m_ConVarCache = sm_trie_create();
|
||||
}
|
||||
|
||||
ConVarManager::~ConVarManager()
|
||||
{
|
||||
List<ConVarInfo *>::iterator iter;
|
||||
|
||||
/* Destroy our convar lookup trie */
|
||||
sm_trie_destroy(m_ConVarCache);
|
||||
|
||||
/* Destroy all the ConVarInfo structures */
|
||||
for (iter = m_ConVars.begin(); iter != m_ConVars.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
|
||||
m_ConVars.clear();
|
||||
}
|
||||
|
||||
void ConVarManager::OnSourceModAllInitialized()
|
||||
@ -101,6 +85,48 @@ void ConVarManager::OnSourceModAllInitialized()
|
||||
|
||||
void ConVarManager::OnSourceModShutdown()
|
||||
{
|
||||
List<ConVarInfo *>::iterator iter = m_ConVars.begin();
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
|
||||
/* Iterate list of ConVarInfo structures, remove every one of them */
|
||||
while (iter != m_ConVars.end())
|
||||
{
|
||||
ConVarInfo *pInfo = (*iter);
|
||||
|
||||
iter = m_ConVars.erase(iter);
|
||||
|
||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
||||
if (pInfo->pChangeForward != NULL)
|
||||
{
|
||||
g_Forwards.ReleaseForward(pInfo->pChangeForward);
|
||||
}
|
||||
if (pInfo->sourceMod)
|
||||
{
|
||||
/* If we created it, we won't be tracking it, therefore it is
|
||||
* safe to remove everything in one go.
|
||||
*/
|
||||
META_UNREGCVAR(pInfo->pVar);
|
||||
delete [] pInfo->pVar->GetName();
|
||||
delete [] pInfo->pVar->GetHelpText();
|
||||
delete [] pInfo->pVar->GetDefault();
|
||||
delete pInfo->pVar;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we didn't create it, we might be tracking it. Also,
|
||||
* it could be unreadable.
|
||||
*/
|
||||
UntrackConCommandBase(pInfo->pVar, this);
|
||||
}
|
||||
|
||||
/* It's not safe to read the name here, so we simply delete the
|
||||
* the info struct and clear the lookup cache at the end.
|
||||
*/
|
||||
delete pInfo;
|
||||
}
|
||||
convar_cache.clear();
|
||||
|
||||
/* Unhook things */
|
||||
if (m_bIsDLLQueryHooked)
|
||||
{
|
||||
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, OnQueryCvarValueFinished, gamedll, this, &ConVarManager::OnQueryCvarValueFinished, false);
|
||||
@ -112,21 +138,6 @@ void ConVarManager::OnSourceModShutdown()
|
||||
m_bIsVSPQueryHooked = false;
|
||||
}
|
||||
|
||||
IChangeableForward *fwd;
|
||||
List<ConVarInfo *>::iterator i;
|
||||
|
||||
/* Iterate list of ConVarInfo structures */
|
||||
for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
|
||||
{
|
||||
fwd = (*i)->pChangeForward;
|
||||
|
||||
/* Free any convar-change forwards that still exist */
|
||||
if (fwd)
|
||||
{
|
||||
g_Forwards.ReleaseForward(fwd);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the 'convars' option from the 'sm' console command */
|
||||
g_RootMenu.RemoveRootConsoleCommand("cvars", this);
|
||||
|
||||
@ -165,54 +176,55 @@ void ConVarManager::OnSourceModVSPReceived()
|
||||
m_bIsVSPQueryHooked = true;
|
||||
}
|
||||
|
||||
#if PLAPI_VERSION >= 12
|
||||
void ConVarManager::OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
|
||||
bool convar_cache_lookup(const char *name, ConVarInfo **pVar)
|
||||
{
|
||||
ConVarInfo **pLookup = convar_cache.retrieve(name);
|
||||
if (pLookup != NULL)
|
||||
{
|
||||
*pVar = *pLookup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe)
|
||||
{
|
||||
/* Only check convars that have not been created by SourceMod's core */
|
||||
if (id != g_PLID && !pCommand->IsCommand())
|
||||
{
|
||||
ConVarInfo *pInfo;
|
||||
const char *cvarName = pCommand->GetName();
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
bool handleExists = sm_trie_retrieve(m_ConVarCache, cvarName, reinterpret_cast<void **>(&pInfo));
|
||||
|
||||
if (handleExists)
|
||||
if (!convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
||||
sm_trie_delete(m_ConVarCache, cvarName);
|
||||
return;
|
||||
}
|
||||
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
|
||||
/* Remove it from our cache */
|
||||
m_ConVars.remove(pInfo);
|
||||
}
|
||||
}
|
||||
convar_cache.remove(name);
|
||||
|
||||
/* Now make sure no plugins are referring to this pointer */
|
||||
IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
|
||||
while (pl_iter->MorePlugins())
|
||||
{
|
||||
IPlugin *pl = pl_iter->GetPlugin();
|
||||
|
||||
ConVarList *pConVarList;
|
||||
if (pl->GetProperty("ConVarList", (void **)&pConVarList, true)
|
||||
&& pConVarList != NULL)
|
||||
{
|
||||
pConVarList->remove(pInfo->pVar);
|
||||
}
|
||||
|
||||
#else
|
||||
pl_iter->NextPlugin();
|
||||
}
|
||||
|
||||
/* I truly detest this code */
|
||||
void ConVarManager::OnMetamodPluginUnloaded(PluginId id)
|
||||
{
|
||||
ConVarInfo *pInfo;
|
||||
const char *cvarName;
|
||||
HandleSecurity sec(NULL, g_pCoreIdent);
|
||||
|
||||
List<ConVarInfo *>::iterator i;
|
||||
for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
|
||||
{
|
||||
pInfo = (*i);
|
||||
cvarName = pInfo->name;
|
||||
|
||||
if (cvarName && !icvar->FindVar(cvarName))
|
||||
{
|
||||
m_IgnoreHandle = true;
|
||||
/* Free resources */
|
||||
g_HandleSys.FreeHandle(pInfo->handle, &sec);
|
||||
|
||||
sm_trie_delete(m_ConVarCache, cvarName);
|
||||
m_ConVars.erase(i);
|
||||
|
||||
delete [] cvarName;
|
||||
delete pInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
@ -227,33 +239,6 @@ void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
|
||||
void ConVarManager::OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
#if PLAPI_VERSION < 12
|
||||
/* Lovely workaround for our workaround! */
|
||||
if (m_IgnoreHandle)
|
||||
{
|
||||
m_IgnoreHandle = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
ConVarInfo *info;
|
||||
ConVar *pConVar = static_cast<ConVar *>(object);
|
||||
|
||||
/* Find convar in lookup trie */
|
||||
sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), reinterpret_cast<void **>(&info));
|
||||
|
||||
/* If convar was created by SourceMod plugin... */
|
||||
if (info->sourceMod)
|
||||
{
|
||||
/* Then unlink it from SourceMM */
|
||||
g_SMAPI->UnregisterConCommandBase(g_PLAPI, pConVar);
|
||||
|
||||
/* Delete string allocations */
|
||||
delete [] pConVar->GetName();
|
||||
delete [] pConVar->GetDefault();
|
||||
delete [] pConVar->GetHelpText();
|
||||
delete pConVar;
|
||||
}
|
||||
}
|
||||
|
||||
void ConVarManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
|
||||
@ -320,28 +305,33 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
|
||||
/* First find out if we already have a handle to it */
|
||||
if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo))
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
return pInfo->handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we don't, then create a new handle from the convar */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
/* Create and initialize ConVarInfo structure */
|
||||
pInfo = new ConVarInfo();
|
||||
pInfo->handle = hndl;
|
||||
pInfo->sourceMod = false;
|
||||
pInfo->pChangeForward = NULL;
|
||||
pInfo->origCallback = pConVar->GetCallback();
|
||||
#if PLAPI_VERSION < 12
|
||||
pInfo->name = sm_strdup(pConVar->GetName());
|
||||
#endif
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* If we don't, then create a new handle from the convar */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
pInfo->handle = hndl;
|
||||
|
||||
/* Insert struct into caches */
|
||||
m_ConVars.push_back(pInfo);
|
||||
sm_trie_insert(m_ConVarCache, name, pInfo);
|
||||
convar_cache.insert(name, pInfo);
|
||||
TrackConCommandBase(pConVar, this);
|
||||
|
||||
return hndl;
|
||||
}
|
||||
@ -360,28 +350,33 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pBase = const_cast<ConCommandBase *>(pBase->GetNext());
|
||||
}
|
||||
|
||||
/* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */
|
||||
pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max);
|
||||
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
|
||||
/* Create a handle from the new convar */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
/* Create and initialize ConVarInfo structure */
|
||||
pInfo = new ConVarInfo();
|
||||
pInfo->handle = hndl;
|
||||
pInfo->sourceMod = true;
|
||||
pInfo->pChangeForward = NULL;
|
||||
pInfo->origCallback = NULL;
|
||||
#if PLAPI_VERSION < 12
|
||||
pInfo->name = NULL;
|
||||
#endif
|
||||
|
||||
/* Create a handle from the new convar */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
pInfo->handle = hndl;
|
||||
|
||||
/* Since an existing convar (or concmd with the same name) was not found , now we can finally create it */
|
||||
pConVar = new ConVar(sm_strdup(name), sm_strdup(defaultVal), flags, sm_strdup(description), hasMin, min, hasMax, max);
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
|
||||
/* Insert struct into caches */
|
||||
m_ConVars.push_back(pInfo);
|
||||
sm_trie_insert(m_ConVarCache, name, pInfo);
|
||||
convar_cache.insert(name, pInfo);
|
||||
|
||||
return hndl;
|
||||
}
|
||||
@ -402,27 +397,32 @@ Handle_t ConVarManager::FindConVar(const char *name)
|
||||
}
|
||||
|
||||
/* At this point, the convar exists. So, find out if we already have a handle */
|
||||
if (sm_trie_retrieve(m_ConVarCache, name, (void **)&pInfo))
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
return pInfo->handle;
|
||||
}
|
||||
|
||||
/* If we don't have a handle, then create a new one */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pConVar, NULL, g_pCoreIdent, NULL);
|
||||
|
||||
/* Create and initialize ConVarInfo structure */
|
||||
pInfo = new ConVarInfo();
|
||||
pInfo->handle = hndl;
|
||||
pInfo->sourceMod = false;
|
||||
pInfo->pChangeForward = NULL;
|
||||
pInfo->origCallback = pConVar->GetCallback();
|
||||
#if PLAPI_VERSION < 12
|
||||
pInfo->name = sm_strdup(pConVar->GetName());
|
||||
#endif
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* If we don't have a handle, then create a new one */
|
||||
hndl = g_HandleSys.CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
delete pInfo;
|
||||
return BAD_HANDLE;
|
||||
}
|
||||
|
||||
pInfo->handle = hndl;
|
||||
|
||||
/* Insert struct into our caches */
|
||||
m_ConVars.push_back(pInfo);
|
||||
sm_trie_insert(m_ConVarCache, name, pInfo);
|
||||
convar_cache.insert(name, pInfo);
|
||||
TrackConCommandBase(pConVar, this);
|
||||
|
||||
return hndl;
|
||||
}
|
||||
@ -433,7 +433,7 @@ void ConVarManager::HookConVarChange(ConVar *pConVar, IPluginFunction *pFunction
|
||||
IChangeableForward *pForward;
|
||||
|
||||
/* Find the convar in the lookup trie */
|
||||
if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
|
||||
if (convar_cache_lookup(pConVar->GetName(), &pInfo))
|
||||
{
|
||||
/* Get the forward */
|
||||
pForward = pInfo->pChangeForward;
|
||||
@ -460,7 +460,7 @@ void ConVarManager::UnhookConVarChange(ConVar *pConVar, IPluginFunction *pFuncti
|
||||
IPluginContext *pContext = pFunction->GetParentContext();
|
||||
|
||||
/* Find the convar in the lookup trie */
|
||||
if (sm_trie_retrieve(m_ConVarCache, pConVar->GetName(), (void **)&pInfo))
|
||||
if (convar_cache_lookup(pConVar->GetName(), &pInfo))
|
||||
{
|
||||
/* Get the forward */
|
||||
pForward = pInfo->pChangeForward;
|
||||
@ -569,11 +569,13 @@ void ConVarManager::OnConVarChanged(ConVar *pConVar, const char *oldValue)
|
||||
return;
|
||||
}
|
||||
|
||||
Trie *pCache = g_ConVarManager.GetConVarCache();
|
||||
ConVarInfo *pInfo;
|
||||
|
||||
/* Find the convar in the lookup trie */
|
||||
sm_trie_retrieve(pCache, pConVar->GetName(), (void **)&pInfo);
|
||||
if (!convar_cache_lookup(pConVar->GetName(), &pInfo))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FnChangeCallback_t origCallback = pInfo->origCallback;
|
||||
IChangeableForward *pForward = pInfo->pChangeForward;
|
||||
@ -642,6 +644,23 @@ void ConVarManager::OnQueryCvarValueFinished(QueryCvarCookie_t cookie, edict_t *
|
||||
}
|
||||
}
|
||||
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
||||
{
|
||||
ConVarInfo *pInfo;
|
||||
HandleError error;
|
||||
|
||||
if ((error = g_HandleSys.ReadHandle(hndl, m_ConVarType, NULL, (void **)&pInfo)) != HandleError_None)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pVar)
|
||||
{
|
||||
*pVar = pInfo->pVar;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int s_YamagramState = 0;
|
||||
|
||||
|
@ -34,13 +34,13 @@
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_trie.h"
|
||||
#include <sh_list.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include <compat_wrappers.h>
|
||||
#include "concmd_cleaner.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
@ -49,13 +49,11 @@ using namespace SourceHook;
|
||||
*/
|
||||
struct ConVarInfo
|
||||
{
|
||||
Handle_t handle; /**< Handle to convar */
|
||||
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 */
|
||||
#if PLAPI_VERSION < 12
|
||||
const char *name; /**< Name of convar */
|
||||
#endif
|
||||
ConVar *pVar; /**< The actual convar */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -72,7 +70,8 @@ class ConVarManager :
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch,
|
||||
public IPluginsListener,
|
||||
public IRootConsoleCommand
|
||||
public IRootConsoleCommand,
|
||||
public IConCommandTracker
|
||||
{
|
||||
public:
|
||||
ConVarManager();
|
||||
@ -87,22 +86,8 @@ public: // IPluginsListener
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
/**
|
||||
* Get the 'ConVar' handle type ID.
|
||||
*/
|
||||
inline HandleType_t GetHandleType()
|
||||
{
|
||||
return m_ConVarType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the convar lookup trie.
|
||||
*/
|
||||
inline Trie *GetConVarCache()
|
||||
{
|
||||
return m_ConVarCache;
|
||||
}
|
||||
public: //IConCommandTracker
|
||||
void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe);
|
||||
public:
|
||||
/**
|
||||
* Create a convar and return a handle to it.
|
||||
@ -133,17 +118,8 @@ public:
|
||||
|
||||
bool IsQueryingSupported();
|
||||
|
||||
#if PLAPI_VERSION >= 12
|
||||
/**
|
||||
* Called when Metamod:Source is about to remove convar
|
||||
*/
|
||||
void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand);
|
||||
#else
|
||||
/**
|
||||
* Called when Metamod:Source has unloaded a plugin
|
||||
*/
|
||||
void OnMetamodPluginUnloaded(PluginId id);
|
||||
#endif
|
||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds a convar to a plugin's list.
|
||||
@ -168,12 +144,8 @@ private:
|
||||
HandleType_t m_ConVarType;
|
||||
List<ConVarInfo *> m_ConVars;
|
||||
List<ConVarQuery> m_ConVarQueries;
|
||||
Trie *m_ConVarCache;
|
||||
bool m_bIsDLLQueryHooked;
|
||||
bool m_bIsVSPQueryHooked;
|
||||
#if PLAPI_VERSION < 12
|
||||
bool m_IgnoreHandle;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern ConVarManager g_ConVarManager;
|
||||
|
175
core/concmd_cleaner.cpp
Normal file
175
core/concmd_cleaner.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "sm_globals.h"
|
||||
#include <sh_list.h>
|
||||
#include <convar.h>
|
||||
#include "concmd_cleaner.h"
|
||||
#include "sm_stringutil.h"
|
||||
#include "sourcemm_api.h"
|
||||
|
||||
#if defined ORANGEBOX_BUILD
|
||||
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
|
||||
#endif
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
struct ConCommandInfo
|
||||
{
|
||||
ConCommandBase *pBase;
|
||||
IConCommandTracker *cls;
|
||||
char name[64];
|
||||
};
|
||||
|
||||
List<ConCommandInfo *> tracked_bases;
|
||||
|
||||
ConCommandBase *FindConCommandBase(const char *name);
|
||||
|
||||
class ConCommandCleaner : public SMGlobalClass
|
||||
{
|
||||
public:
|
||||
#if defined ORANGEBOX_BUILD
|
||||
void OnSourceModAllInitialized()
|
||||
{
|
||||
SH_ADD_HOOK(ICvar, UnregisterConCommand, SH_NOATTRIB, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
|
||||
}
|
||||
|
||||
void OnSourceModShutdown()
|
||||
{
|
||||
SH_REMOVE_HOOK(ICvar, UnregisterConCommand, SH_NOATTRIB, SH_MEMBER(this, &ConCommandCleaner::UnlinkConCommandBase), false);
|
||||
}
|
||||
#endif
|
||||
|
||||
void UnlinkConCommandBase(ConCommandBase *pBase)
|
||||
{
|
||||
ConCommandInfo *pInfo;
|
||||
List<ConCommandInfo *>::iterator iter = tracked_bases.begin();
|
||||
|
||||
if (pBase)
|
||||
{
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
if ((*iter)->pBase == pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
|
||||
delete pInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
/* This is just god-awful! */
|
||||
if (FindConCommandBase((*iter)->name) != (*iter)->pBase)
|
||||
{
|
||||
pInfo = (*iter);
|
||||
iter = tracked_bases.erase(iter);
|
||||
pInfo->cls->OnUnlinkConCommandBase(pBase, pBase->GetName(), true);
|
||||
delete pInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
||||
{
|
||||
ConCommandInfo *info = new ConCommandInfo;
|
||||
|
||||
info->pBase = pBase;
|
||||
info->cls = cls;
|
||||
strncopy(info->name, pBase->GetName(), sizeof(info->name));
|
||||
|
||||
tracked_bases.push_back(info);
|
||||
}
|
||||
|
||||
void RemoveTarget(ConCommandBase *pBase, IConCommandTracker *cls)
|
||||
{
|
||||
List<ConCommandInfo *>::iterator iter;
|
||||
ConCommandInfo *pInfo;
|
||||
|
||||
iter = tracked_bases.begin();
|
||||
while (iter != tracked_bases.end())
|
||||
{
|
||||
pInfo = (*iter);
|
||||
if (pInfo->pBase == pBase && pInfo->cls == cls)
|
||||
{
|
||||
delete pInfo;
|
||||
iter = tracked_bases.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} s_ConCmdTracker;
|
||||
|
||||
ConCommandBase *FindConCommandBase(const char *name)
|
||||
{
|
||||
const ConCommandBase *pBase = icvar->GetCommands();
|
||||
|
||||
while (pBase != NULL)
|
||||
{
|
||||
if (strcmp(pBase->GetName(), name) == 0)
|
||||
{
|
||||
return const_cast<ConCommandBase *>(pBase);
|
||||
}
|
||||
pBase = pBase->GetNext();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
|
||||
{
|
||||
s_ConCmdTracker.AddTarget(pBase, me);
|
||||
}
|
||||
|
||||
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me)
|
||||
{
|
||||
s_ConCmdTracker.RemoveTarget(pBase, me);
|
||||
}
|
||||
|
||||
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase)
|
||||
{
|
||||
s_ConCmdTracker.UnlinkConCommandBase(pBase);
|
||||
}
|
41
core/concmd_cleaner.h
Normal file
41
core/concmd_cleaner.h
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
class IConCommandTracker
|
||||
{
|
||||
public:
|
||||
virtual void OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name, bool is_read_safe) = 0;
|
||||
};
|
||||
|
||||
void TrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||
void UntrackConCommandBase(ConCommandBase *pBase, IConCommandTracker *me);
|
||||
void Global_OnUnlinkConCommandBase(ConCommandBase *pBase);
|
||||
|
@ -609,6 +609,10 @@
|
||||
RelativePath="..\ChatTriggers.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\concmd_cleaner.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ConCmdManager.cpp"
|
||||
>
|
||||
@ -803,6 +807,10 @@
|
||||
RelativePath="..\..\public\compat_wrappers.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\concmd_cleaner.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\ConCmdManager.h"
|
||||
>
|
||||
|
@ -110,7 +110,9 @@ static void NotifyConVar(ConVar *pConVar)
|
||||
if (IsFlagSet(pConVar, FCVAR_PROTECTED))
|
||||
{
|
||||
pEvent->SetString("cvarvalue", "***PROTECTED***");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
pEvent->SetString("cvarvalue", pConVar->GetString());
|
||||
}
|
||||
|
||||
@ -141,7 +143,7 @@ static cell_t sm_CreateConVar(IPluginContext *pContext, const cell_t *params)
|
||||
|
||||
if (hndl == BAD_HANDLE)
|
||||
{
|
||||
return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
|
||||
return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same might already exist.", name);
|
||||
}
|
||||
|
||||
return hndl;
|
||||
@ -162,7 +164,7 @@ static cell_t sm_HookConVarChange(IPluginContext *pContext, const cell_t *params
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -186,7 +188,7 @@ static cell_t sm_UnhookConVarChange(IPluginContext *pContext, const cell_t *para
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -210,7 +212,7 @@ static cell_t sm_GetConVarBool(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -225,7 +227,7 @@ static cell_t sm_GetConVarInt(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -241,7 +243,7 @@ static cell_t sm_SetConVarNum(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -270,7 +272,7 @@ static cell_t sm_GetConVarFloat(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -287,7 +289,7 @@ static cell_t sm_SetConVarFloat(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -317,7 +319,7 @@ static cell_t sm_GetConVarString(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -334,7 +336,7 @@ static cell_t sm_SetConVarString(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -366,7 +368,7 @@ static cell_t sm_ResetConVar(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -395,7 +397,7 @@ static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -410,7 +412,7 @@ static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -427,7 +429,7 @@ static cell_t sm_GetConVarBounds(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -461,7 +463,7 @@ static cell_t sm_SetConVarBounds(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
@ -488,7 +490,7 @@ static cell_t sm_GetConVarName(IPluginContext *pContext, const cell_t *params)
|
||||
HandleError err;
|
||||
ConVar *pConVar;
|
||||
|
||||
if ((err=g_HandleSys.ReadHandle(hndl, g_ConVarManager.GetHandleType(), NULL, (void **)&pConVar))
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, &pConVar))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "sourcemm_api.h"
|
||||
#include "sm_version.h"
|
||||
#include "Logger.h"
|
||||
#include "ConVarManager.h"
|
||||
#include "concmd_cleaner.h"
|
||||
|
||||
SourceMod_Core g_SourceMod_Core;
|
||||
IVEngineServer *engine = NULL;
|
||||
@ -203,14 +203,18 @@ void SourceMod_Core::OnVSPListening(IServerPluginCallbacks *iface)
|
||||
}
|
||||
}
|
||||
|
||||
#if PLAPI_VERSION >= 12
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
|
||||
void SourceMod_Core::OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand)
|
||||
{
|
||||
g_ConVarManager.OnUnlinkConCommandBase(id, pCommand);
|
||||
Global_OnUnlinkConCommandBase(pCommand);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void SourceMod_Core::OnPluginUnload(PluginId id)
|
||||
{
|
||||
g_ConVarManager.OnMetamodPluginUnloaded(id);
|
||||
Global_OnUnlinkConCommandBase(NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
const char *GetLogTag();
|
||||
public:
|
||||
void OnVSPListening(IServerPluginCallbacks *iface);
|
||||
#if PLAPI_VERSION >= 12
|
||||
#if defined METAMOD_PLAPI_VERSION
|
||||
void OnUnlinkConCommandBase(PluginId id, ConCommandBase *pCommand);
|
||||
#else
|
||||
void OnPluginUnload(PluginId id);
|
||||
|
Loading…
Reference in New Issue
Block a user