diff --git a/amxmodx/CvarManager.cpp b/amxmodx/CvarManager.cpp index 92549105..00ed7bc5 100644 --- a/amxmodx/CvarManager.cpp +++ b/amxmodx/CvarManager.cpp @@ -22,8 +22,35 @@ bool Cvar_DirectSet_Custom(cvar_t* var, const char* value) if (!var || !value // Sanity checks against bogus pointers. || strcmp(var->string, value) == 0 // Make sure old and new values are different to not trigger callbacks. - || !g_CvarManager.CacheLookup(var->name, &info) // No data in cache, nothing to call. - || info->hooks.empty()) // No hooked cvars, nothing to call. + || !g_CvarManager.CacheLookup(var->name, &info)) // No data in cache, nothing to do. + { + return true; + } + + if (info->hasMin || info->hasMax) // cvar_s doesn't have min/max mechanism, so we check things here. + { + float fvalue = atof(value); + bool oob = false; + + if (info->hasMin && fvalue < info->minVal) + { + oob = true; + fvalue = info->minVal; + } + else if (info->hasMax && fvalue > info->maxVal) + { + oob = true; + fvalue = info->maxVal; + } + + if (oob) // Found value out of bound, set new value and block original call. + { + CVAR_SET_FLOAT(var->name, fvalue); + return false; + } + } + + if (info->hooks.empty()) // No hooked cvars, nothing to call. { return true; } @@ -115,7 +142,8 @@ void CvarManager::CreateCvarHook(void) } } -cvar_t* CvarManager::CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId) +cvar_t* 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; CvarInfo* info = nullptr; @@ -126,12 +154,7 @@ cvar_t* CvarManager::CreateCvar(const char* name, const char* value, float fvalu var = CVAR_GET_POINTER(name); // Whether it exists, we need to prepare a new entry. - info = new CvarInfo(); - - // Shared datas. - info->name = name; - info->plugin = plugin; - info->pluginId = plugnId; + info = new CvarInfo(name, helpText, hasMin, min, hasMax, max, plugin, pluginId); if (var) { @@ -202,12 +225,8 @@ cvar_t* CvarManager::FindCvar(const char* name) } // Create a new entry. - info = new CvarInfo(); - info->var = var; - info->name = name; - info->plugin = ""; - info->pluginId = -1; - info->amxmodx = false; + info = new CvarInfo(name); + info->var = var; // Add entry in the caches. m_Cvars.append(info); @@ -251,12 +270,8 @@ Forward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, const ch if (!CacheLookup(var->name, &info)) { // Create a new entry. - info = new CvarInfo(); - info->var = var; - info->name = var->name; - info->plugin = ""; - info->pluginId = -1; - info->amxmodx = false; + info = new CvarInfo(var->name); + info->var = var; // Add entry in the caches. m_Cvars.append(info); diff --git a/amxmodx/CvarManager.h b/amxmodx/CvarManager.h index a5eb7eb7..0a8c631c 100644 --- a/amxmodx/CvarManager.h +++ b/amxmodx/CvarManager.h @@ -52,11 +52,29 @@ typedef ke::Vector CvarsHook; struct CvarInfo : public ke::InlineListNode { + CvarInfo(const char* name_, const char* helpText, bool hasMin_, float min_, bool hasMax_, float max_, + const char* plugin_, int pluginId_) + : + name(name_), description(helpText), hasMin(hasMin_), minVal(min_), hasMax(hasMax_), maxVal(max_), + plugin(plugin_), pluginId(pluginId_) {}; + + CvarInfo(const char* name_) + : + name(name_), defaultval(""), description(""), hasMin(false), minVal(0), hasMax(false), maxVal(0), + plugin(""), pluginId(-1), amxmodx(false) {}; + cvar_t* var; ke::AString name; ke::AString defaultval; + ke::AString description; + bool hasMin; + bool hasMax; + float minVal; + float maxVal; + ke::AString plugin; int pluginId; + CvarsHook hooks; bool amxmodx; @@ -80,7 +98,10 @@ class CvarManager void CreateCvarHook(); - cvar_t* CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId); + cvar_t* 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); cvar_t* FindCvar(const char* name); CvarInfo* FindCvar(size_t index); bool CacheLookup(const char* name, CvarInfo** info); diff --git a/amxmodx/cvars.cpp b/amxmodx/cvars.cpp index 19dba289..16f99e58 100644 --- a/amxmodx/cvars.cpp +++ b/amxmodx/cvars.cpp @@ -14,6 +14,32 @@ char CVarTempBuffer[64]; const char *invis_cvar_list[5] = { "amxmodx_version", "amxmodx_modules", "amx_debug", "amx_mldebug", "amx_client_languages" }; +// create_cvar(const name[], const default_value[], flags = 0, const description[] = "", bool:has_min = false, Float:min_val = 0.0, bool:has_max = false, Float:max_val = 0.0) +static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + 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 ? true : false; + bool hasMax = params[7] > 0 ? true : false; + float minVal = amx_ctof(params[6]); + float maxVal = amx_ctof(params[8]); + + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + if (CheckBadConList(name, 0)) + { + plugin->AddToFailCounter(1); + } + + cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText, hasMin, minVal, hasMax, maxVal); + + return reinterpret_cast(var); +} + // register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0) static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) { @@ -31,7 +57,7 @@ static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) plugin->AddToFailCounter(1); } - cvar_t* var = g_CvarManager.CreateCvar(name, value, fvalue, flags, plugin->getName(), plugin->getId()); + cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags); return reinterpret_cast(var); } @@ -487,6 +513,7 @@ static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params) AMX_NATIVE_INFO g_CvarNatives[] = { + {"create_cvar", create_cvar}, {"register_cvar", register_cvar}, {"cvar_exists", cvar_exists}, {"get_cvar_pointer", get_cvar_pointer}, diff --git a/plugins/include/cvars.inc b/plugins/include/cvars.inc index 8a8fb83d..1f9aa2a1 100644 --- a/plugins/include/cvars.inc +++ b/plugins/include/cvars.inc @@ -15,6 +15,7 @@ /** * CVAR flags for register_cvar() */ +#define FCVAR_NONE 0 /* No flags */ #define FCVAR_ARCHIVE 1 /* Set to cause it to be saved to vars.rc */ #define FCVAR_USERINFO 2 /* Changes the client's info string */ #define FCVAR_SERVER 4 /* Notifies players when changed */ @@ -26,9 +27,32 @@ #define FCVAR_UNLOGGED 256 /* If this is a FCVAR_SERVER, don't log changes to the log file / console if we are creating a log */ #define FCVAR_NOEXTRAWHITEPACE 512 /* Strip trailing/leading white space from this cvar */ +/** + * Creates a new cvar for the engine. + * + * @note This is same as regitser_cvar but with more options. + * @note For a list of possible cvar flags see FCVAR_* constants above. + * @note If an already existing cvar is registered it will not be duplicated. + * @note The returned cvar pointer should be used with the get_pcvar_* and + * set_pcvar_* set of functions. + * + * @param name Cvar name + * @param string Default cvar value + * @param flags Optional bitstring of flags determining how the convar should be handled + * @param help_text Optional description of the cvar + * @param has_min Optional boolean that determines if the convar has a minimum valu + * @param min_val Minimum floating point value that the convar can have if has_min is true + * @param has_max Optional boolean that determines if the convar has a maximum value + * @param max_val Maximum floating point value that the convar can have if has_max is true + * + * @return Unique cvar pointer + */ +native create_cvar(const name[], const string[], flags = FCVAR_NONE, const help_text[] = "", bool:has_min = false, Float:min_val = 0.0, bool:has_max = false, Float:max_val = 0.0); + /** * Registers a new cvar for the engine. * + * @note Deprecated. Consider to use create_cvar for more options. * @note For a list of possible cvar flags see FCVAR_* constants in amxconst.inc * @note If an already existing cvar is registered it will not be duplicated. * @note The returned cvar pointer should be used with the get_pcvar_* and @@ -41,7 +65,7 @@ * * @return Unique cvar pointer */ -native register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0); +native register_cvar(const name[], const string[], flags = FCVAR_NONE, Float:fvalue=0.0); /** * Returns if a cvar is registered on the server.