void ConVarManager::OnUnlinkConCommandBase(ConCommandBase *pBase, const char *name) { /* Only check convars that have not been created by SourceMod's core */ ConVarInfo *pInfo; if (!convar_cache_lookup(name, &pInfo)) { 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 = scripts->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); } pl_iter->NextPlugin(); } /* Free resources */ handlesys->FreeHandle(pInfo->handle, &sec); delete pInfo; }
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); handlesys->FreeHandle(pInfo->handle, &sec); if (pInfo->pChangeForward != NULL) { forwardsys->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(); g_Players.RemoveClientListener(this); /* Remove the 'convars' option from the 'sm' console command */ rootmenu->RemoveRootConsoleCommand("cvars", this); scripts->RemovePluginsListener(this); /* Remove the 'ConVar' handle type */ handlesys->RemoveType(m_ConVarType, g_pCoreIdent); }
Handle_t ConVarManager::FindConVar(const char *name) { ConVar *pConVar = NULL; ConVarInfo *pInfo; Handle_t hndl; /* Check convar cache to find out if we already have a handle */ if (convar_cache_lookup(name, &pInfo)) { return pInfo->handle; } /* Couldn't find it in cache, so search for it */ pConVar = icvar->FindVar(name); /* If it doesn't exist, then return an invalid handle */ if (!pConVar) { return BAD_HANDLE; } /* Create and initialize ConVarInfo structure */ pInfo = new ConVarInfo(); pInfo->sourceMod = false; pInfo->pChangeForward = NULL; pInfo->pVar = pConVar; /* If we don't have a handle, then create a new one */ hndl = 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); convar_cache.insert(name, pInfo); TrackConCommandBase(pConVar, this); return hndl; }
Handle_t ConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *description, int flags, bool hasMin, float min, bool hasMax, float max) { ConVar *pConVar = NULL; ConVarInfo *pInfo = NULL; Handle_t hndl = 0; /* Find out if the convar exists already */ pConVar = icvar->FindVar(name); /* If the convar already exists... */ if (pConVar) { /* Add convar to plugin's list */ AddConVarToPluginList(pContext, pConVar); /* First find out if we already have a handle to it */ if (convar_cache_lookup(name, &pInfo)) { return pInfo->handle; } else { /* Create and initialize ConVarInfo structure */ pInfo = new ConVarInfo(); pInfo->sourceMod = false; pInfo->pChangeForward = NULL; pInfo->pVar = pConVar; /* If we don't, then create a new handle from the convar */ hndl = 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); convar_cache.insert(name, pInfo); TrackConCommandBase(pConVar, this); return hndl; } } /* Prevent creating a convar that has the same name as a console command */ if (FindCommand(name)) { return BAD_HANDLE; } /* Create and initialize ConVarInfo structure */ pInfo = new ConVarInfo(); pInfo->handle = hndl; pInfo->sourceMod = true; pInfo->pChangeForward = NULL; /* Create a handle from the new convar */ hndl = handlesys->CreateHandle(m_ConVarType, pInfo, NULL, g_pCoreIdent, NULL); if (hndl == BAD_HANDLE) { delete pInfo; return BAD_HANDLE; } pInfo->handle = hndl; /* Hardening: remove NOTIFY from any convar plugins attempt to create */ flags &= ~FCVAR_NOTIFY; /* 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); convar_cache.insert(name, pInfo); return hndl; }
bool convar_cache_lookup(const char *name, ConVarInfo **pVar) { return convar_cache.retrieve(name, pVar); }
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); handlesys->FreeHandle(pInfo->handle, &sec); if (pInfo->pChangeForward != NULL) { forwardsys->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(); #if SOURCE_ENGINE != SE_DARKMESSIAH /* Unhook things */ if (m_bIsDLLQueryHooked) { SH_REMOVE_HOOK(IServerGameDLL, OnQueryCvarValueFinished, gamedll, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false); m_bIsDLLQueryHooked = false; } else if (m_bIsVSPQueryHooked) { #if SOURCE_ENGINE != SE_DOTA SH_REMOVE_HOOK(IServerPluginCallbacks, OnQueryCvarValueFinished, vsp_interface, SH_MEMBER(this, &ConVarManager::OnQueryCvarValueFinished), false); #endif m_bIsVSPQueryHooked = false; } #endif g_Players.RemoveClientListener(this); #if SOURCE_ENGINE >= SE_ORANGEBOX SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallbacks, icvar, SH_STATIC(OnConVarChanged), false); #else SH_REMOVE_HOOK(ICvar, CallGlobalChangeCallback, icvar, SH_STATIC(OnConVarChanged), false); #endif /* Remove the 'convars' option from the 'sm' console command */ g_RootMenu.RemoveRootConsoleCommand("cvars", this); scripts->RemovePluginsListener(this); /* Remove the 'ConVar' handle type */ handlesys->RemoveType(m_ConVarType, g_pCoreIdent); }