diff --git a/amxmodx/CvarManager.cpp b/amxmodx/CvarManager.cpp index 1843b5cf..88c5c196 100644 --- a/amxmodx/CvarManager.cpp +++ b/amxmodx/CvarManager.cpp @@ -154,7 +154,7 @@ void CvarManager::CreateCvarHook(void) } } -cvar_t* CvarManager::CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags, +CvarInfo* CvarManager::CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags, const char* helpText, bool hasMin, float min, bool hasMax, float max) { cvar_t* var = nullptr; @@ -215,11 +215,27 @@ cvar_t* CvarManager::CreateCvar(const char* name, const char* value, const char* // Make sure that whether an existing or new cvar is set to the given value. CVAR_DIRECTSET(var, value); } + else if (info->pluginId == -1) + { + // In situation where a plugin has been modified/recompiled + // or new added plugins, and a change map occurs. We want to keep data up to date. + info->bound.hasMin = hasMin; + info->bound.minVal = min; + info->bound.hasMax = hasMax; + info->bound.maxVal = max; + info->defaultval = value; + info->description = helpText; + info->pluginId = pluginId; + } // Detour is disabled on map change. - m_HookDetour->EnableDetour(); + // Don't enable it unless there are things to do. + if (info->bound.hasMin || info->bound.hasMax) + { + m_HookDetour->EnableDetour(); + } - return info->var; + return info; } CvarInfo* CvarManager::FindCvar(const char* name) @@ -227,9 +243,6 @@ CvarInfo* CvarManager::FindCvar(const char* name) cvar_t* var = nullptr; CvarInfo* info = nullptr; - // Detour is disabled on map change. - m_HookDetour->EnableDetour(); - // Do we have already cvar in cache? if (CacheLookup(name, &info)) { @@ -316,6 +329,104 @@ AutoForward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, cons return forward; } +bool CvarManager::BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen) +{ + if (varofs > amx->hlw) // If variable address is not inside global area, we can't bind it. + { + LogError(amx, AMX_ERR_NATIVE, "A global variable must be provided"); + return false; + } + + int pluginId = g_plugins.findPluginFast(amx)->getId(); + cell* address = get_amxaddr(amx, varofs); + + // To avoid unexpected behavior, probably better to error such situations. + for (size_t i = 0; i < info->binds.length(); ++i) + { + CvarBind* bind = info->binds[i]; + + if (bind->pluginId == pluginId) + { + if (bind->varAddress == address) + { + LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars"); + return false; + } + } + } + + CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen); + + info->binds.append(bind); + + // Update right away variable with current cvar value. + switch (type) + { + case CvarBind::CvarType_Int: + *bind->varAddress = atoi(info->var->string); + break; + case CvarBind::CvarType_Float: + *bind->varAddress = amx_ftoc(info->var->value); + break; + case CvarBind::CvarType_String: + set_amxstring_simple(bind->varAddress, info->var->string, bind->varLength); + break; + } + + // Detour is disabled on map change. + m_HookDetour->EnableDetour(); + + return true; +} + +bool CvarManager::SetCvarMin(CvarInfo* info, bool set, float value, int pluginId) +{ + info->bound.hasMin = set; + info->bound.minPluginId = pluginId; + + if (set) + { + if (info->bound.hasMax && value > info->bound.maxVal) + { + return false; + } + + info->bound.minVal = value; + + // Detour is disabled on map change. + m_HookDetour->EnableDetour(); + + // Update if needed. + CVAR_SET_FLOAT(info->var->name, value); + } + + return true; +} + +bool CvarManager::SetCvarMax(CvarInfo* info, bool set, float value, int pluginId) +{ + info->bound.hasMax = set; + info->bound.maxPluginId = pluginId; + + if (set) + { + if (info->bound.hasMin && value < info->bound.minVal) + { + return false; + } + + info->bound.maxVal = value; + + // Detour is disabled on map change. + m_HookDetour->EnableDetour(); + + // Update if needed. + CVAR_SET_FLOAT(info->var->name, value); + } + + return true; +} + size_t CvarManager::GetRegCvarsCount() { return m_AmxmodxCvars; @@ -475,6 +586,11 @@ void CvarManager::OnPluginUnloaded() delete (*cvar)->hooks[i]; } + if ((*cvar)->amxmodx) // Mark registered cvars so we can refresh default datas at next map. + { + (*cvar)->pluginId = -1; + } + (*cvar)->binds.clear(); (*cvar)->hooks.clear(); } diff --git a/amxmodx/CvarManager.h b/amxmodx/CvarManager.h index d0312c1c..9c67f436 100644 --- a/amxmodx/CvarManager.h +++ b/amxmodx/CvarManager.h @@ -150,7 +150,7 @@ class CvarManager void CreateCvarHook(); - cvar_t* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, + CvarInfo* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags = 0, const char* helpText = "", bool hasMin = false, float min = 0, bool hasMax = false, float max = 0); @@ -160,6 +160,9 @@ class CvarManager bool CacheLookup(const char* name, CvarInfo** info); AutoForward* HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback); + bool BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen = 0); + bool SetCvarMin(CvarInfo* info, bool set, float value, int pluginId); + bool SetCvarMax(CvarInfo* info, bool set, float value, int pluginId); size_t GetRegCvarsCount(); diff --git a/amxmodx/cvars.cpp b/amxmodx/cvars.cpp index 84e37482..339166da 100644 --- a/amxmodx/cvars.cpp +++ b/amxmodx/cvars.cpp @@ -22,34 +22,8 @@ static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params) const char* value = get_amxstring(amx, params[2], 1, length); const char* helpText = get_amxstring(amx, params[4], 2, length); - int flags = params[3]; - bool hasMin = params[5] != 0; - bool hasMax = params[7] != 0; - float minVal = 0; - float maxVal = 0; - - if (hasMin) - { - minVal = amx_ctof(params[6]); - - if (hasMax && minVal > maxVal) - { - LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound"); - return 0; - } - } + int flags = params[3]; - if (hasMax) - { - maxVal = amx_ctof(params[8]); - - if (hasMin && maxVal < minVal) - { - LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound"); - return 0; - } - } - CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); if (CheckBadConList(name, 0)) @@ -57,9 +31,31 @@ static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params) plugin->AddToFailCounter(1); } - cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText, hasMin, minVal, hasMax, maxVal); + CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText); - return reinterpret_cast(var); + if (info) + { + bool hasMin = params[5] != 0; + bool hasMax = params[7] != 0; + float minVal = amx_ctof(params[6]); + float maxVal = amx_ctof(params[8]); + + if (!g_CvarManager.SetCvarMin(info, hasMin, minVal, plugin->getId())) + { + LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound"); + return 0; + } + + if (!g_CvarManager.SetCvarMax(info, hasMax, maxVal, plugin->getId())) + { + LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound"); + return 0; + } + + return reinterpret_cast(info->var); + } + + return 0; } // register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0) @@ -79,9 +75,14 @@ static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) plugin->AddToFailCounter(1); } - cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags); + CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags); - return reinterpret_cast(var); + if (info) + { + return reinterpret_cast(info->var); + } + + return 0; } // cvar_exists(const cvar[]) @@ -368,53 +369,6 @@ static cell AMX_NATIVE_CALL get_pcvar_bounds(AMX *amx, cell *params) return hasBound; } -bool bind_pcvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen = 0) -{ - if (varofs > amx->hlw) // If variable address is not inside global area, we can't bind it. - { - LogError(amx, AMX_ERR_NATIVE, "A global variable must be provided"); - return false; - } - - int pluginId = g_plugins.findPluginFast(amx)->getId(); - cell* address = get_amxaddr(amx, varofs); - - // To avoid unexpected behavior, probably better to error such situations. - for (size_t i = 0; i < info->binds.length(); ++i) - { - CvarBind* bind = info->binds[i]; - - if (bind->pluginId == pluginId) - { - if (bind->varAddress == address) - { - LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars"); - return false; - } - } - } - - CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen); - - info->binds.append(bind); - - // Update right away variable with current cvar value. - switch (type) - { - case CvarBind::CvarType_Int: - *bind->varAddress = atoi(info->var->string); - break; - case CvarBind::CvarType_Float: - *bind->varAddress = amx_ftoc(info->var->value); - break; - case CvarBind::CvarType_String: - set_amxstring_simple(bind->varAddress, info->var->string, bind->varLength); - break; - } - - return true; -} - // bind_pcvar_float(pcvar, &Float:var) static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params) { @@ -427,7 +381,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params) return 0; } - return bind_pcvar(info, CvarBind::CvarType_Float, amx, params[2]); + return g_CvarManager.BindCvar(info, CvarBind::CvarType_Float, amx, params[2]); } // bind_pcvar_num(pcvar, &any:var) @@ -442,7 +396,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_num(AMX *amx, cell *params) return 0; } - return bind_pcvar(info, CvarBind::CvarType_Int, amx, params[2]); + return g_CvarManager.BindCvar(info, CvarBind::CvarType_Int, amx, params[2]); } // bind_pcvar_string(pcvar, any:var[], varlen) @@ -457,7 +411,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_string(AMX *amx, cell *params) return 0; } - return bind_pcvar(info, CvarBind::CvarType_String, amx, params[2], params[3]); + return g_CvarManager.BindCvar(info, CvarBind::CvarType_String, amx, params[2], params[3]); } // set_pcvar_flags(pcvar, flags) @@ -538,53 +492,26 @@ static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params) bool set = params[3] != 0; int pluginId = g_plugins.findPluginFast(amx)->getId(); - float value = 0; - bool should_update = false; + float value = amx_ctof(params[4]); switch (params[2]) { case CvarBound_Lower: { - info->bound.hasMin = set; - - if (set) + if (!g_CvarManager.SetCvarMin(info, set, value, pluginId)) { - value = amx_ctof(params[4]); - - if (info->bound.hasMax && value > info->bound.maxVal) - { - LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound"); - return 0; - } - - should_update = true; - - info->bound.minVal = value; - info->bound.minPluginId = pluginId; + LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound"); + return 0; } - break; } case CvarBound_Upper: { - info->bound.hasMax = set; - - if (set) + if (!g_CvarManager.SetCvarMax(info, set, value, pluginId)) { - value = amx_ctof(params[4]); - - if (info->bound.hasMin && value < info->bound.minVal) - { - LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound"); - return 0; - } - - should_update = true; - - info->bound.maxVal = value; - info->bound.maxPluginId = pluginId; + LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound"); + return 0; } - break; } default: @@ -594,11 +521,6 @@ static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params) } } - if (should_update) - { - CVAR_SET_FLOAT(ptr->name, value); - } - return 1; }