1.1 --- a/core/CConVarManager.cpp Sun Feb 11 11:09:38 2007 +0000
1.2 +++ b/core/CConVarManager.cpp Sun Feb 11 11:20:38 2007 +0000
1.3 @@ -1,364 +1,365 @@
1.4 -/**
1.5 -* ===============================================================
1.6 -* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.7 -* ===============================================================
1.8 -*
1.9 -* This file is not open source and may not be copied without explicit
1.10 -* written permission of AlliedModders LLC. This file may not be redistributed
1.11 -* in whole or significant part.
1.12 -* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.13 -*
1.14 -* Version: $Id$
1.15 -*/
1.16 -
1.17 -#include "CConVarManager.h"
1.18 -#include "CLogger.h"
1.19 -#include "PluginSys.h"
1.20 -#include "sm_srvcmds.h"
1.21 -#include "sm_stringutil.h"
1.22 -
1.23 -CConVarManager g_ConVarManager;
1.24 -
1.25 -CConVarManager::CConVarManager() : m_ConVarType(0)
1.26 -{
1.27 - // Create a convar lookup trie
1.28 - m_ConVarCache = sm_trie_create();
1.29 -}
1.30 -
1.31 -CConVarManager::~CConVarManager()
1.32 -{
1.33 - List<ConVarInfo *>::iterator i;
1.34 -
1.35 - // Destroy our convar lookup trie
1.36 - sm_trie_destroy(m_ConVarCache);
1.37 -
1.38 - // Destroy all the ConVarInfo structures
1.39 - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
1.40 - {
1.41 - delete (*i);
1.42 - }
1.43 -
1.44 - m_ConVars.clear();
1.45 -}
1.46 -
1.47 -void CConVarManager::OnSourceModAllInitialized()
1.48 -{
1.49 - HandleAccess sec;
1.50 -
1.51 - // Set up access rights for the 'ConVar' handle type
1.52 - sec.access[HandleAccess_Read] = 0;
1.53 - sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.54 - sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.55 -
1.56 - // Create the 'ConVar' handle type
1.57 - m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
1.58 -
1.59 - // Add the 'cvars' option to the 'sm' console command
1.60 - g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
1.61 -}
1.62 -
1.63 -void CConVarManager::OnSourceModShutdown()
1.64 -{
1.65 - IChangeableForward *fwd;
1.66 - List<ConVarInfo *>::iterator i;
1.67 -
1.68 - // Iterate list of ConVarInfo structures
1.69 - for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
1.70 - {
1.71 - fwd = (*i)->changeForward;
1.72 -
1.73 - // Free any convar-change forwards that still exist
1.74 - if (fwd)
1.75 - {
1.76 - g_Forwards.ReleaseForward(fwd);
1.77 - }
1.78 - }
1.79 -
1.80 - // Remove the 'cvars' option from the 'sm' console command
1.81 - g_RootMenu.RemoveRootConsoleCommand("cvars", this);
1.82 -
1.83 - // Remove the 'ConVar' handle type
1.84 - g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
1.85 -}
1.86 -
1.87 -void CConVarManager::OnHandleDestroy(HandleType_t type, void *object)
1.88 -{
1.89 - ConVarInfo *info;
1.90 - ConCommandBase *cvar = static_cast<ConCommandBase *>(object);
1.91 -
1.92 - // Find convar in lookup trie
1.93 - sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info));
1.94 -
1.95 - // If convar was created by SourceMod plugin...
1.96 - if (info->sourceMod)
1.97 - {
1.98 - // Then unregister it
1.99 - g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar);
1.100 - }
1.101 -}
1.102 -
1.103 -void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount)
1.104 -{
1.105 - if (argcount >= 3)
1.106 - {
1.107 - int id = 1;
1.108 -
1.109 - // Get plugin index that was passed
1.110 - int num = atoi(g_RootMenu.GetArgument(2));
1.111 -
1.112 - // If invalid plugin index...
1.113 - if (num < 1 || num > (int)g_PluginSys.GetPluginCount())
1.114 - {
1.115 - g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
1.116 - return;
1.117 - }
1.118 -
1.119 - // Get plugin object
1.120 - CPlugin *pl = g_PluginSys.GetPluginByOrder(num);
1.121 -
1.122 - // Get number of convars created by plugin
1.123 - int convarnum = pl->GetConVarCount();
1.124 -
1.125 - if (convarnum == 0)
1.126 - {
1.127 - g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name);
1.128 - return;
1.129 - }
1.130 -
1.131 - g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name);
1.132 -
1.133 - // Iterate convar list and display each one
1.134 - for (int i = 0; i < convarnum; i++, id++)
1.135 - {
1.136 - ConVar *cvar = pl->GetConVarByIndex(i);
1.137 - g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString());
1.138 - }
1.139 -
1.140 - return;
1.141 - }
1.142 -
1.143 - // Display usage of subcommand
1.144 - g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>");
1.145 -}
1.146 -
1.147 -Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max)
1.148 -{
1.149 - ConVar *cvar = NULL;
1.150 - ConVarInfo *info = NULL;
1.151 - Handle_t hndl = 0;
1.152 -
1.153 - // Find out if the convar exists already
1.154 - cvar = icvar->FindVar(name);
1.155 -
1.156 - // If the convar already exists...
1.157 - if (cvar != NULL)
1.158 - {
1.159 - // First check if we already have a handle to it
1.160 - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast<void **>(&info)))
1.161 - {
1.162 - // If we do, then return that handle
1.163 - return info->handle;
1.164 - } else {
1.165 - // If we don't, then create a new handle from the convar
1.166 - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.167 -
1.168 - info = new ConVarInfo;
1.169 - info->handle = hndl;
1.170 - info->sourceMod = false;
1.171 - info->changeForward = NULL;
1.172 - info->origCallback = cvar->GetCallback();
1.173 -
1.174 - m_ConVars.push_back(info);
1.175 -
1.176 - return hndl;
1.177 - }
1.178 - }
1.179 -
1.180 - // To prevent creating a convar that has the same name as a console command... ugh
1.181 - ConCommandBase *pBase = icvar->GetCommands();
1.182 -
1.183 - while (pBase)
1.184 - {
1.185 - if (strcmp(pBase->GetName(), name) == 0)
1.186 - {
1.187 - return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
1.188 - }
1.189 -
1.190 - pBase = const_cast<ConCommandBase *>(pBase->GetNext());
1.191 - }
1.192 -
1.193 - // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it!
1.194 - cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max);
1.195 -
1.196 - // Add new convar to plugin's list
1.197 - g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar);
1.198 -
1.199 - // Create a handle from the new convar
1.200 - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.201 -
1.202 - info = new ConVarInfo;
1.203 - info->handle = hndl;
1.204 - info->sourceMod = true;
1.205 - info->changeForward = NULL;
1.206 - info->origCallback = NULL;
1.207 -
1.208 - m_ConVars.push_back(info);
1.209 -
1.210 - // Insert the handle into our lookup trie
1.211 - sm_trie_insert(m_ConVarCache, name, info);
1.212 -
1.213 - return hndl;
1.214 -}
1.215 -
1.216 -Handle_t CConVarManager::FindConVar(const char *name)
1.217 -{
1.218 - ConVar *cvar = NULL;
1.219 - ConVarInfo *info = NULL;
1.220 - Handle_t hndl = 0;
1.221 -
1.222 - // Search for convar
1.223 - cvar = icvar->FindVar(name);
1.224 -
1.225 - // If it doesn't exist, then return an invalid handle
1.226 - if (cvar == NULL)
1.227 - {
1.228 - return BAD_HANDLE;
1.229 - }
1.230 -
1.231 - // At this point, convar exists, so find out if we already have a handle for it
1.232 - if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast<void **>(&info)))
1.233 - {
1.234 - // If we do, then return that handle
1.235 - return info->handle;
1.236 - }
1.237 -
1.238 - // If we don't, then create a new handle from the convar
1.239 - hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.240 -
1.241 - info = new ConVarInfo;
1.242 - info->handle = hndl;
1.243 - info->sourceMod = false;
1.244 - info->changeForward = NULL;
1.245 - info->origCallback = cvar->GetCallback();
1.246 -
1.247 - m_ConVars.push_back(info);
1.248 -
1.249 - // Insert the handle into our cache
1.250 - sm_trie_insert(m_ConVarCache, name, info);
1.251 -
1.252 - return hndl;
1.253 -}
1.254 -
1.255 -void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid)
1.256 -{
1.257 - IPluginFunction *func = pContext->GetFunctionById(funcid);
1.258 - IChangeableForward *fwd = NULL;
1.259 - char fwdName[64];
1.260 - ConVarInfo *info = NULL;
1.261 -
1.262 - // This shouldn't happen...
1.263 - if (func == NULL)
1.264 - {
1.265 - pContext->ThrowNativeError("Invalid function: %d", funcid);
1.266 - return;
1.267 - }
1.268 -
1.269 - // Create a forward name
1.270 - UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName());
1.271 -
1.272 - // First find out if the forward already exists
1.273 - g_Forwards.FindForward(fwdName, &fwd);
1.274 -
1.275 - // If the forward doesn't exist...
1.276 - if (fwd == NULL)
1.277 - {
1.278 - // This is the forward's parameter type list
1.279 - ParamType p[] = {Param_Cell, Param_String, Param_String};
1.280 -
1.281 - // Create the forward
1.282 - fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p);
1.283 -
1.284 - // Find the convar in the lookup trie
1.285 - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info)))
1.286 - {
1.287 - // Set the convar's forward to the newly created one
1.288 - info->changeForward = fwd;
1.289 -
1.290 - // Set the convar's callback to our static one
1.291 - cvar->InstallChangeCallback(OnConVarChanged);
1.292 - }
1.293 - }
1.294 -
1.295 - // Add the function to the forward's list
1.296 - fwd->AddFunction(func);
1.297 -}
1.298 -
1.299 -void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid)
1.300 -{
1.301 - IPluginFunction *func = pContext->GetFunctionById(funcid);
1.302 - IChangeableForward *fwd = NULL;
1.303 - ConVarInfo *info = NULL;
1.304 -
1.305 - // This shouldn't happen...
1.306 - if (func == NULL)
1.307 - {
1.308 - pContext->ThrowNativeError("Invalid function: %d", funcid);
1.309 - return;
1.310 - }
1.311 -
1.312 - // Find the convar in the lookup trie
1.313 - if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info)))
1.314 - {
1.315 - // Get the forward
1.316 - fwd = info->changeForward;
1.317 -
1.318 - // If the forward doesn't exist, we can't unhook anything
1.319 - if (fwd == NULL)
1.320 - {
1.321 - pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName());
1.322 - return;
1.323 - }
1.324 -
1.325 - // Remove the function from the forward's list
1.326 - if (!fwd->RemoveFunction(func))
1.327 - {
1.328 - pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName());
1.329 - return;
1.330 - }
1.331 -
1.332 - // If the forward now has 0 functions in it...
1.333 - if (fwd->GetFunctionCount() == 0)
1.334 - {
1.335 - // Free this forward
1.336 - g_Forwards.ReleaseForward(fwd);
1.337 - info->changeForward = NULL;
1.338 -
1.339 - // Put the back the original convar callback
1.340 - cvar->InstallChangeCallback(info->origCallback);
1.341 - }
1.342 - }
1.343 -}
1.344 -
1.345 -void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue)
1.346 -{
1.347 - Trie *cache = g_ConVarManager.GetConVarCache();
1.348 - ConVarInfo *info;
1.349 -
1.350 - // Find the convar in the lookup trie
1.351 - sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast<void **>(&info));
1.352 -
1.353 - FnChangeCallback origCallback = info->origCallback;
1.354 - IChangeableForward *fwd = info->changeForward;
1.355 -
1.356 - // If there was a change callback installed previously, call it
1.357 - if (origCallback)
1.358 - {
1.359 - origCallback(cvar, oldValue);
1.360 - }
1.361 -
1.362 - // Now call forwards in plugins that have hooked this
1.363 - fwd->PushCell(info->handle);
1.364 - fwd->PushString(cvar->GetString());
1.365 - fwd->PushString(oldValue);
1.366 - fwd->Execute(NULL);
1.367 -}
1.368 \ No newline at end of file
1.369 +/**
1.370 +* ===============================================================
1.371 +* SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved.
1.372 +* ===============================================================
1.373 +*
1.374 +* This file is not open source and may not be copied without explicit
1.375 +* written permission of AlliedModders LLC. This file may not be redistributed
1.376 +* in whole or significant part.
1.377 +* For information, see LICENSE.txt or http://www.sourcemod.net/license.php
1.378 +*
1.379 +* Version: $Id$
1.380 +*/
1.381 +
1.382 +#include "CConVarManager.h"
1.383 +#include "CLogger.h"
1.384 +#include "PluginSys.h"
1.385 +#include "sm_srvcmds.h"
1.386 +#include "sm_stringutil.h"
1.387 +
1.388 +CConVarManager g_ConVarManager;
1.389 +
1.390 +CConVarManager::CConVarManager() : m_ConVarType(0)
1.391 +{
1.392 + // Create a convar lookup trie
1.393 + m_ConVarCache = sm_trie_create();
1.394 +}
1.395 +
1.396 +CConVarManager::~CConVarManager()
1.397 +{
1.398 + List<ConVarInfo *>::iterator i;
1.399 +
1.400 + // Destroy our convar lookup trie
1.401 + sm_trie_destroy(m_ConVarCache);
1.402 +
1.403 + // Destroy all the ConVarInfo structures
1.404 + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
1.405 + {
1.406 + delete (*i);
1.407 + }
1.408 +
1.409 + m_ConVars.clear();
1.410 +}
1.411 +
1.412 +void CConVarManager::OnSourceModAllInitialized()
1.413 +{
1.414 + HandleAccess sec;
1.415 +
1.416 + // Set up access rights for the 'ConVar' handle type
1.417 + sec.access[HandleAccess_Read] = 0;
1.418 + sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.419 + sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY | HANDLE_RESTRICT_OWNER;
1.420 +
1.421 + // Create the 'ConVar' handle type
1.422 + m_ConVarType = g_HandleSys.CreateType("ConVar", this, 0, NULL, &sec, g_pCoreIdent, NULL);
1.423 +
1.424 + // Add the 'cvars' option to the 'sm' console command
1.425 + g_RootMenu.AddRootConsoleCommand("cvars", "View convars created by a plugin", this);
1.426 +}
1.427 +
1.428 +void CConVarManager::OnSourceModShutdown()
1.429 +{
1.430 + IChangeableForward *fwd;
1.431 + List<ConVarInfo *>::iterator i;
1.432 +
1.433 + // Iterate list of ConVarInfo structures
1.434 + for (i = m_ConVars.begin(); i != m_ConVars.end(); i++)
1.435 + {
1.436 + fwd = (*i)->changeForward;
1.437 +
1.438 + // Free any convar-change forwards that still exist
1.439 + if (fwd)
1.440 + {
1.441 + g_Forwards.ReleaseForward(fwd);
1.442 + }
1.443 + }
1.444 +
1.445 + // Remove the 'cvars' option from the 'sm' console command
1.446 + g_RootMenu.RemoveRootConsoleCommand("cvars", this);
1.447 +
1.448 + // Remove the 'ConVar' handle type
1.449 + g_HandleSys.RemoveType(m_ConVarType, g_pCoreIdent);
1.450 +}
1.451 +
1.452 +void CConVarManager::OnHandleDestroy(HandleType_t type, void *object)
1.453 +{
1.454 + ConVarInfo *info;
1.455 + ConCommandBase *cvar = static_cast<ConCommandBase *>(object);
1.456 +
1.457 + // Find convar in lookup trie
1.458 + sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info));
1.459 +
1.460 + // If convar was created by SourceMod plugin...
1.461 + if (info->sourceMod)
1.462 + {
1.463 + // Then unregister it
1.464 + g_SMAPI->UnregisterConCmdBase(g_PLAPI, cvar);
1.465 + }
1.466 +}
1.467 +
1.468 +void CConVarManager::OnRootConsoleCommand(const char *command, unsigned int argcount)
1.469 +{
1.470 + if (argcount >= 3)
1.471 + {
1.472 + int id = 1;
1.473 +
1.474 + // Get plugin index that was passed
1.475 + int num = atoi(g_RootMenu.GetArgument(2));
1.476 +
1.477 + // If invalid plugin index...
1.478 + if (num < 1 || num > (int)g_PluginSys.GetPluginCount())
1.479 + {
1.480 + g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
1.481 + return;
1.482 + }
1.483 +
1.484 + // Get plugin object
1.485 + CPlugin *pl = g_PluginSys.GetPluginByOrder(num);
1.486 +
1.487 + // Get number of convars created by plugin
1.488 + int convarnum = pl->GetConVarCount();
1.489 +
1.490 + if (convarnum == 0)
1.491 + {
1.492 + g_RootMenu.ConsolePrint("[SM] No convars for \"%s\"", pl->GetPublicInfo()->name);
1.493 + return;
1.494 + }
1.495 +
1.496 + g_RootMenu.ConsolePrint("[SM] Displaying convars for \"%s\":", pl->GetPublicInfo()->name);
1.497 +
1.498 + // Iterate convar list and display each one
1.499 + for (int i = 0; i < convarnum; i++, id++)
1.500 + {
1.501 + ConVar *cvar = pl->GetConVarByIndex(i);
1.502 + g_RootMenu.ConsolePrint(" %02d \"%s\" = \"%s\"", id, cvar->GetName(), cvar->GetString());
1.503 + }
1.504 +
1.505 + return;
1.506 + }
1.507 +
1.508 + // Display usage of subcommand
1.509 + g_RootMenu.ConsolePrint("[SM] Usage: sm cvars <#>");
1.510 +}
1.511 +
1.512 +Handle_t CConVarManager::CreateConVar(IPluginContext *pContext, const char *name, const char *defaultVal, const char *helpText, int flags, bool hasMin, float min, bool hasMax, float max)
1.513 +{
1.514 + ConVar *cvar = NULL;
1.515 + ConVarInfo *info = NULL;
1.516 + Handle_t hndl = 0;
1.517 +
1.518 + // Find out if the convar exists already
1.519 + cvar = icvar->FindVar(name);
1.520 +
1.521 + // If the convar already exists...
1.522 + if (cvar != NULL)
1.523 + {
1.524 + // First check if we already have a handle to it
1.525 + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast<void **>(&info)))
1.526 + {
1.527 + // If we do, then return that handle
1.528 + return info->handle;
1.529 + } else {
1.530 + // If we don't, then create a new handle from the convar
1.531 + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.532 +
1.533 + info = new ConVarInfo;
1.534 + info->handle = hndl;
1.535 + info->sourceMod = false;
1.536 + info->changeForward = NULL;
1.537 + info->origCallback = cvar->GetCallback();
1.538 +
1.539 + m_ConVars.push_back(info);
1.540 +
1.541 + return hndl;
1.542 + }
1.543 + }
1.544 +
1.545 + // To prevent creating a convar that has the same name as a console command... ugh
1.546 + ConCommandBase *pBase = icvar->GetCommands();
1.547 +
1.548 + while (pBase)
1.549 + {
1.550 + if (strcmp(pBase->GetName(), name) == 0)
1.551 + {
1.552 + return pContext->ThrowNativeError("Convar \"%s\" was not created. A console command with the same name already exists.", name);
1.553 + }
1.554 +
1.555 + pBase = const_cast<ConCommandBase *>(pBase->GetNext());
1.556 + }
1.557 +
1.558 + // Since we didn't find an existing convar (or concmd with the same name), now we can finally create it!
1.559 + cvar = new ConVar(name, defaultVal, flags, helpText, hasMin, min, hasMax, max);
1.560 +
1.561 + // Add new convar to plugin's list
1.562 + g_PluginSys.GetPluginByCtx(pContext->GetContext())->AddConVar(cvar);
1.563 +
1.564 + // Create a handle from the new convar
1.565 + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.566 +
1.567 + info = new ConVarInfo;
1.568 + info->handle = hndl;
1.569 + info->sourceMod = true;
1.570 + info->changeForward = NULL;
1.571 + info->origCallback = NULL;
1.572 +
1.573 + m_ConVars.push_back(info);
1.574 +
1.575 + // Insert the handle into our lookup trie
1.576 + sm_trie_insert(m_ConVarCache, name, info);
1.577 +
1.578 + return hndl;
1.579 +}
1.580 +
1.581 +Handle_t CConVarManager::FindConVar(const char *name)
1.582 +{
1.583 + ConVar *cvar = NULL;
1.584 + ConVarInfo *info = NULL;
1.585 + Handle_t hndl = 0;
1.586 +
1.587 + // Search for convar
1.588 + cvar = icvar->FindVar(name);
1.589 +
1.590 + // If it doesn't exist, then return an invalid handle
1.591 + if (cvar == NULL)
1.592 + {
1.593 + return BAD_HANDLE;
1.594 + }
1.595 +
1.596 + // At this point, convar exists, so find out if we already have a handle for it
1.597 + if (sm_trie_retrieve(m_ConVarCache, name, reinterpret_cast<void **>(&info)))
1.598 + {
1.599 + // If we do, then return that handle
1.600 + return info->handle;
1.601 + }
1.602 +
1.603 + // If we don't, then create a new handle from the convar
1.604 + hndl = g_HandleSys.CreateHandle(m_ConVarType, cvar, NULL, g_pCoreIdent, NULL);
1.605 +
1.606 + info = new ConVarInfo;
1.607 + info->handle = hndl;
1.608 + info->sourceMod = false;
1.609 + info->changeForward = NULL;
1.610 + info->origCallback = cvar->GetCallback();
1.611 +
1.612 + m_ConVars.push_back(info);
1.613 +
1.614 + // Insert the handle into our cache
1.615 + sm_trie_insert(m_ConVarCache, name, info);
1.616 +
1.617 + return hndl;
1.618 +}
1.619 +
1.620 +void CConVarManager::HookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid)
1.621 +{
1.622 + IPluginFunction *func = pContext->GetFunctionById(funcid);
1.623 + IChangeableForward *fwd = NULL;
1.624 + char fwdName[64];
1.625 + ConVarInfo *info = NULL;
1.626 +
1.627 + // This shouldn't happen...
1.628 + if (func == NULL)
1.629 + {
1.630 + pContext->ThrowNativeError("Invalid function: %d", funcid);
1.631 + return;
1.632 + }
1.633 +
1.634 + // Create a forward name
1.635 + UTIL_Format(fwdName, sizeof(fwdName), "ConVar.%s", cvar->GetName());
1.636 +
1.637 + // First find out if the forward already exists
1.638 + g_Forwards.FindForward(fwdName, &fwd);
1.639 +
1.640 + // If the forward doesn't exist...
1.641 + if (fwd == NULL)
1.642 + {
1.643 + // This is the forward's parameter type list
1.644 + ParamType p[] = {Param_Cell, Param_String, Param_String};
1.645 +
1.646 + // Create the forward
1.647 + fwd = g_Forwards.CreateForwardEx(fwdName, ET_Ignore, 3, p);
1.648 +
1.649 + // Find the convar in the lookup trie
1.650 + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info)))
1.651 + {
1.652 + // Set the convar's forward to the newly created one
1.653 + info->changeForward = fwd;
1.654 +
1.655 + // Set the convar's callback to our static one
1.656 + cvar->InstallChangeCallback(OnConVarChanged);
1.657 + }
1.658 + }
1.659 +
1.660 + // Add the function to the forward's list
1.661 + fwd->AddFunction(func);
1.662 +}
1.663 +
1.664 +void CConVarManager::UnhookConVarChange(IPluginContext *pContext, ConVar *cvar, funcid_t funcid)
1.665 +{
1.666 + IPluginFunction *func = pContext->GetFunctionById(funcid);
1.667 + IChangeableForward *fwd = NULL;
1.668 + ConVarInfo *info = NULL;
1.669 +
1.670 + // This shouldn't happen...
1.671 + if (func == NULL)
1.672 + {
1.673 + pContext->ThrowNativeError("Invalid function: %d", funcid);
1.674 + return;
1.675 + }
1.676 +
1.677 + // Find the convar in the lookup trie
1.678 + if (sm_trie_retrieve(m_ConVarCache, cvar->GetName(), reinterpret_cast<void **>(&info)))
1.679 + {
1.680 + // Get the forward
1.681 + fwd = info->changeForward;
1.682 +
1.683 + // If the forward doesn't exist, we can't unhook anything
1.684 + if (fwd == NULL)
1.685 + {
1.686 + pContext->ThrowNativeError("Convar \"%s\" has no active hook.", cvar->GetName());
1.687 + return;
1.688 + }
1.689 +
1.690 + // Remove the function from the forward's list
1.691 + if (!fwd->RemoveFunction(func))
1.692 + {
1.693 + pContext->ThrowNativeError("Function %d is not a valid hook callback for convar \"%s\"", funcid, cvar->GetName());
1.694 + return;
1.695 + }
1.696 +
1.697 + // If the forward now has 0 functions in it...
1.698 + if (fwd->GetFunctionCount() == 0)
1.699 + {
1.700 + // Free this forward
1.701 + g_Forwards.ReleaseForward(fwd);
1.702 + info->changeForward = NULL;
1.703 +
1.704 + // Put the back the original convar callback
1.705 + cvar->InstallChangeCallback(info->origCallback);
1.706 + }
1.707 + }
1.708 +}
1.709 +
1.710 +void CConVarManager::OnConVarChanged(ConVar *cvar, const char *oldValue)
1.711 +{
1.712 + Trie *cache = g_ConVarManager.GetConVarCache();
1.713 + ConVarInfo *info;
1.714 +
1.715 + // Find the convar in the lookup trie
1.716 + sm_trie_retrieve(cache, cvar->GetName(), reinterpret_cast<void **>(&info));
1.717 +
1.718 + FnChangeCallback origCallback = info->origCallback;
1.719 + IChangeableForward *fwd = info->changeForward;
1.720 +
1.721 + // If there was a change callback installed previously, call it
1.722 + if (origCallback)
1.723 + {
1.724 + origCallback(cvar, oldValue);
1.725 + }
1.726 +
1.727 + // Now call forwards in plugins that have hooked this
1.728 + fwd->PushCell(info->handle);
1.729 + fwd->PushString(cvar->GetString());
1.730 + fwd->PushString(oldValue);
1.731 + fwd->Execute(NULL);
1.732 +}
1.733 +