Track the creating plugin for convars (#1537)
Similar to the recent work for commands, track and expose the creating plugin for convars. The first plugin to register a given cvar becomes the owner until that plugin is unloaded. If a plugin attempts to register a convar that was already registered and the originally registering plugin has been unloaded, that plugin becomes the owner. This isn't quite as nice as the way commands shift "ownership" as plugins are unloaded, but we don't have a sane data structure currently to implement that, and it seemed like a lot of unnecessary work as there shouldn't really be multiple plugins with conflicting cvars. Closes #1492
This commit is contained in:
parent
39aa75436e
commit
6a2ac9800b
@ -210,18 +210,27 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na
|
||||
void ConVarManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
List<ConVarQuery>::iterator iter;
|
||||
|
||||
/* If plugin has a convar list, free its memory */
|
||||
if (plugin->GetProperty("ConVarList", (void **)&pConVarList, true))
|
||||
{
|
||||
delete pConVarList;
|
||||
}
|
||||
|
||||
/* Clear any references to this plugin as the convar creator */
|
||||
for (List<ConVarInfo *>::iterator iter = m_ConVars.begin(); iter != m_ConVars.end(); ++iter)
|
||||
{
|
||||
ConVarInfo *pInfo = (*iter);
|
||||
|
||||
if (pInfo->pPlugin == plugin)
|
||||
{
|
||||
pInfo->pPlugin = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const IPluginRuntime * pRuntime = plugin->GetRuntime();
|
||||
|
||||
/* Remove convar queries for this plugin that haven't returned results yet */
|
||||
for (iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||
for (List<ConVarQuery>::iterator iter = m_ConVarQueries.begin(); iter != m_ConVarQueries.end();)
|
||||
{
|
||||
ConVarQuery &query = (*iter);
|
||||
if (query.pCallback->GetParentRuntime() == pRuntime)
|
||||
@ -347,6 +356,8 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
ConVarInfo *pInfo = NULL;
|
||||
Handle_t hndl = 0;
|
||||
|
||||
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||
|
||||
/* Find out if the convar exists already */
|
||||
pConVar = icvar->FindVar(name);
|
||||
|
||||
@ -354,11 +365,16 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
if (pConVar)
|
||||
{
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
AddConVarToPluginList(plugin, pConVar);
|
||||
|
||||
/* First find out if we already have a handle to it */
|
||||
if (convar_cache_lookup(name, &pInfo))
|
||||
{
|
||||
/* If the convar doesn't have an owning plugin, but SM created it, adopt it */
|
||||
if (pInfo->sourceMod && pInfo->pPlugin == nullptr) {
|
||||
pInfo->pPlugin = plugin;
|
||||
}
|
||||
|
||||
return pInfo->handle;
|
||||
}
|
||||
else
|
||||
@ -399,6 +415,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pInfo->handle = hndl;
|
||||
pInfo->sourceMod = true;
|
||||
pInfo->pChangeForward = NULL;
|
||||
pInfo->pPlugin = plugin;
|
||||
|
||||
/* Create a handle from the new convar */
|
||||
hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL);
|
||||
@ -415,7 +432,7 @@ Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name,
|
||||
pInfo->pVar = pConVar;
|
||||
|
||||
/* Add convar to plugin's list */
|
||||
AddConVarToPluginList(pContext, pConVar);
|
||||
AddConVarToPluginList(plugin, pConVar);
|
||||
|
||||
/* Insert struct into caches */
|
||||
m_ConVars.push_back(pInfo);
|
||||
@ -569,15 +586,13 @@ QueryCvarCookie_t ConVarManager::QueryClientConVar(edict_t *pPlayer, const char
|
||||
return cookie;
|
||||
}
|
||||
|
||||
void ConVarManager::AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar)
|
||||
void ConVarManager::AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar)
|
||||
{
|
||||
ConVarList *pConVarList;
|
||||
ConVarList::iterator iter;
|
||||
bool inserted = false;
|
||||
const char *orig = pConVar->GetName();
|
||||
|
||||
IPlugin *plugin = scripts->FindPluginByContext(pContext->GetContext());
|
||||
|
||||
/* Check plugin for an existing convar list */
|
||||
if (!plugin->GetProperty("ConVarList", (void **)&pConVarList))
|
||||
{
|
||||
@ -696,7 +711,7 @@ void ConVarManager::OnClientQueryFinished(QueryCvarCookie_t cookie,
|
||||
}
|
||||
#endif
|
||||
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
||||
HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin)
|
||||
{
|
||||
ConVarInfo *pInfo;
|
||||
HandleError error;
|
||||
@ -711,5 +726,10 @@ HandleError ConVarManager::ReadConVarHandle(Handle_t hndl, ConVar **pVar)
|
||||
*pVar = pInfo->pVar;
|
||||
}
|
||||
|
||||
if (ppPlugin)
|
||||
{
|
||||
*ppPlugin = pInfo->pPlugin;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ struct ConVarInfo
|
||||
bool sourceMod; /**< Determines whether or not convar was created by a SourceMod plugin */
|
||||
IChangeableForward *pChangeForward; /**< Forward associated with convar */
|
||||
ConVar *pVar; /**< The actual convar */
|
||||
IPlugin *pPlugin; /**< Originally owning plugin */
|
||||
List<IConVarChangeListener *> changeListeners;
|
||||
|
||||
struct ConVarPolicy
|
||||
@ -154,7 +155,7 @@ public:
|
||||
|
||||
bool IsQueryingSupported();
|
||||
|
||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar);
|
||||
HandleError ReadConVarHandle(Handle_t hndl, ConVar **pVar, IPlugin **ppPlugin = nullptr);
|
||||
|
||||
// Called via game hooks.
|
||||
void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue);
|
||||
@ -171,7 +172,7 @@ private:
|
||||
/**
|
||||
* Adds a convar to a plugin's list.
|
||||
*/
|
||||
static void AddConVarToPluginList(IPluginContext *pContext, const ConVar *pConVar);
|
||||
static void AddConVarToPluginList(IPlugin *plugin, const ConVar *pConVar);
|
||||
private:
|
||||
HandleType_t m_ConVarType;
|
||||
List<ConVarInfo *> m_ConVars;
|
||||
|
@ -553,6 +553,21 @@ static cell_t sm_GetConVarFlags(IPluginContext *pContext, const cell_t *params)
|
||||
return pConVar->m_nFlags;
|
||||
}
|
||||
|
||||
static cell_t sm_GetConVarPlugin(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
HandleError err;
|
||||
IPlugin *pPlugin;
|
||||
|
||||
if ((err=g_ConVarManager.ReadConVarHandle(hndl, nullptr, &pPlugin))
|
||||
!= HandleError_None)
|
||||
{
|
||||
return pContext->ThrowNativeError("Invalid convar handle %x (error %d)", hndl, err);
|
||||
}
|
||||
|
||||
return pPlugin ? pPlugin->GetMyHandle() : BAD_HANDLE;
|
||||
}
|
||||
|
||||
static cell_t sm_SetConVarFlags(IPluginContext *pContext, const cell_t *params)
|
||||
{
|
||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
||||
@ -1517,6 +1532,7 @@ REGISTER_NATIVES(consoleNatives)
|
||||
{"ConVar.IntValue.set", sm_SetConVarNum},
|
||||
{"ConVar.Flags.get", sm_GetConVarFlags},
|
||||
{"ConVar.Flags.set", sm_SetConVarFlags},
|
||||
{"ConVar.Plugin.get", sm_GetConVarPlugin},
|
||||
{"ConVar.SetBool", sm_SetConVarNum},
|
||||
{"ConVar.SetInt", sm_SetConVarNum},
|
||||
{"ConVar.SetFloat", sm_SetConVarFloat},
|
||||
|
@ -122,6 +122,11 @@ methodmap ConVar < Handle
|
||||
public native set(int flags);
|
||||
}
|
||||
|
||||
// Retrieves the plugin handle of the convar's creator
|
||||
property Handle Plugin {
|
||||
public native get();
|
||||
}
|
||||
|
||||
// Sets the boolean value of a console variable.
|
||||
//
|
||||
// Note: The replicate and notify params are only relevant for the
|
||||
|
Loading…
Reference in New Issue
Block a user