diff --git a/core/ConVarManager.cpp b/core/ConVarManager.cpp index 52700679..dcd5d8ed 100644 --- a/core/ConVarManager.cpp +++ b/core/ConVarManager.cpp @@ -210,18 +210,27 @@ void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *na void ConVarManager::OnPluginUnloaded(IPlugin *plugin) { ConVarList *pConVarList; - List::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::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::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; } diff --git a/core/ConVarManager.h b/core/ConVarManager.h index fd3b0025..b541baf9 100644 --- a/core/ConVarManager.h +++ b/core/ConVarManager.h @@ -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 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 m_ConVars; diff --git a/core/smn_console.cpp b/core/smn_console.cpp index 5ed90a7e..25da56ba 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -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(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(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}, diff --git a/plugins/include/convars.inc b/plugins/include/convars.inc index cde31d1e..8e7ccace 100644 --- a/plugins/include/convars.inc +++ b/plugins/include/convars.inc @@ -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