diff --git a/amxmodx/AMBuilder b/amxmodx/AMBuilder index 00a8c2b5..a6b7c61a 100644 --- a/amxmodx/AMBuilder +++ b/amxmodx/AMBuilder @@ -96,6 +96,7 @@ binary.sources = [ 'stackstructs.cpp', 'CTextParsers.cpp', 'textparse.cpp', + 'CvarManager.cpp', 'cvars.cpp', '../public/memtools/CDetour/detours.cpp', '../public/memtools/CDetour/asm/asm.c', diff --git a/amxmodx/CvarManager.cpp b/amxmodx/CvarManager.cpp new file mode 100644 index 00000000..92549105 --- /dev/null +++ b/amxmodx/CvarManager.cpp @@ -0,0 +1,348 @@ +// vim: set ts=4 sw=4 tw=99 noet: +// +// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO"). +// Copyright (C) The AMX Mod X Development Team. +// +// This software is licensed under the GNU General Public License, version 3 or higher. +// Additional exceptions apply. For full license details, see LICENSE.txt or visit: +// https://alliedmods.net/amxmodx-license + +#include "CvarManager.h" +#include "amxmodx.h" +#include + +CvarManager g_CvarManager; + +/** + * Returns true to call original function, otherwise false to block it. + */ +bool Cvar_DirectSet_Custom(cvar_t* var, const char* value) +{ + CvarInfo* info = nullptr; + + 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. + { + return true; + } + + int lastResult = 0; + int result; + + for (size_t i = 0; i < info->hooks.length(); ++i) + { + CvarPlugin* p = info->hooks[i]; + + if (p->forward->state == Forward::FSTATE_OK) // Our callback can be enable/disabled by natives. + { + result = executeForwards(p->forward->id, reinterpret_cast(var), var->string, value); + + if (result >= lastResult) + { + lastResult = result; + } + } + } + + return !!!lastResult; +} + +DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value) +{ + if (Cvar_DirectSet_Custom(var, value)) + { + DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value); + } +} + +CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr) +{ +} + +CvarManager::~CvarManager() +{ + OnAmxxShutdown(); +} + +void CvarManager::CreateCvarHook(void) +{ + // void PF_Cvar_DirectSet(struct cvar_s *var, const char *value) // = pfnCvar_DirectSet + // { + // Cvar_DirectSet(var, value); // <- We want to hook this. + // } + + byte *baseAddress = (byte *)g_engfuncs.pfnCvar_DirectSet; + uintptr_t *functionAddress = nullptr; + +#if defined(WIN32) + // 55 push ebp + // 8B EC mov ebp, esp + // 8B 45 0C mov eax, [ebp+arg_4] + // 8B 4D 08 mov ecx, [ebp+arg_0] + // 50 push eax + // 51 push ecx + // E8 XX XX XX XX call Cvar_DirectSet + const byte opcodeJump = 0xE8; +#else + // E9 XX XX XX XX jmp Cvar_DirectSet + const byte opcodeJump = 0xE9; +#endif + + const byte opcodeJumpSize = 5; + const byte opcodeJumpByteSize = 1; + + const int maxBytesLimit = 20; + + for (size_t i = 0; i < maxBytesLimit; ++i, ++baseAddress) + { + if (*baseAddress == opcodeJump) + { + functionAddress = (uintptr_t *)(&baseAddress[opcodeJumpSize] + *(uintptr_t *)&baseAddress[opcodeJumpByteSize]); + break; + } + } + + if (functionAddress) + { + m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress); + + if (m_HookDetour) + { + m_HookDetour->EnableDetour(); + } + } +} + +cvar_t* CvarManager::CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId) +{ + cvar_t* var = nullptr; + CvarInfo* info = nullptr; + + if (!CacheLookup(name, &info)) + { + // Not cached - Is cvar already exist? + 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; + + if (var) + { + // Cvar already exists. Just copy. + // "string" will be set after. "value" and "next" are automatically set. + info->var = var; + info->defaultval = var->string; + info->amxmodx = false; + } + else + { + // Registers a new cvar. + static cvar_t cvar_reg_helper; + + // "string" will be set after. "value" and "next" are automatically set. + cvar_reg_helper.name = info->name.chars(); + cvar_reg_helper.string = ""; + cvar_reg_helper.flags = flags; + + // Adds cvar to global list. + CVAR_REGISTER(&cvar_reg_helper); + + // Registering can fail if name is already a registered command. + var = CVAR_GET_POINTER(name); + + // If so, we can't go further. + if (!var) + { + delete info; + return nullptr; + } + + // If ok, we got a valid pointer, we can copy. + info->var = var; + info->defaultval = value; + info->amxmodx = true; + + // Keeps track count of cvars registered by AMXX. + ++m_AmxmodxCvars; + } + + // Add a new entry in the caches. + m_Cvars.append(info); + m_Cache.insert(name, info); + + // Make sure that whether an existing or new cvar is set to the given value. + CVAR_DIRECTSET(var, value); + } + + return info->var; +} + +cvar_t* CvarManager::FindCvar(const char* name) +{ + cvar_t* var = nullptr; + CvarInfo* info = nullptr; + + // Do we have already cvar in cache? + if (CacheLookup(name, &info)) + { + return info->var; + } + + // Cvar doesn't exist. + if (!(var = CVAR_GET_POINTER(name))) + { + return nullptr; + } + + // Create a new entry. + info = new CvarInfo(); + info->var = var; + info->name = name; + info->plugin = ""; + info->pluginId = -1; + info->amxmodx = false; + + // Add entry in the caches. + m_Cvars.append(info); + m_Cache.insert(name, info); + + return var; +} + +CvarInfo* CvarManager::FindCvar(size_t index) +{ + // Used by get_plugins_cvar native. + // For compatibility, only cvars registered by AMXX are concerned. + + size_t iter_id = 0; + + for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++) + { + if (iter->amxmodx && iter_id++ == index) + { + return *(iter); + } + } + + return nullptr; +} + +bool CvarManager::CacheLookup(const char* name, CvarInfo** info) +{ + return m_Cache.retrieve(name, info); +} + +Forward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback) +{ + CvarInfo* info = nullptr; + + // A cvar is guaranteed to be in cache if pointer is got from + // get_cvar_pointer and register_cvar natives. Though it might be + // provided by another way. If by any chance we run in such + // situation, we create a new entry right now. + + 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; + + // Add entry in the caches. + m_Cvars.append(info); + m_Cache.insert(info->name.chars(), info); + } + + int length; + *callback = get_amxstring(amx, param, 0, length); + + int forwardId = registerSPForwardByName(amx, *callback, FP_CELL, FP_STRING, FP_STRING, FP_DONE); + + // Invalid callback, it could be: not a public function, wrongly named, or simply missing. + if (forwardId == -1) + { + return nullptr; + } + + // Detour is disabled on map change. + m_HookDetour->EnableDetour(); + + Forward* forward = new Forward(forwardId, *callback); + info->hooks.append(new CvarPlugin(g_plugins.findPlugin(amx)->getId(), forward)); + + return forward; +} + +size_t CvarManager::GetRegCvarsCount() +{ + return m_AmxmodxCvars; +} + +void CvarManager::OnConsoleCommand() +{ + print_srvconsole("Registered cvars:\n"); + print_srvconsole(" %-24.23s %-24.23s %-16.15s\n", "name", "value", "plugin"); + + size_t index = 0; + ke::AString pluginName; + + if (CMD_ARGC() > 2) // Searching for cvars registered to a plugin + { + pluginName = CMD_ARGV(2); + } + + for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++) + { + CvarInfo* ci = (*iter); + + if (ci->amxmodx && (!pluginName.length() || strncmp(ci->name.chars(), pluginName.chars(), pluginName.length()) == 0)) + { + print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++index, ci->name.chars(), ci->var->string, ci->plugin.chars()); + } + } +} + +void CvarManager::OnPluginUnloaded() +{ + // Clear only plugin hooks list. + for (CvarsList::iterator cvar = m_Cvars.begin(); cvar != m_Cvars.end(); cvar++) + { + for (size_t i = 0; i < (*cvar)->hooks.length(); ++i) + { + delete (*cvar)->hooks[i]; + } + + (*cvar)->hooks.clear(); + } + + // There is no point to enable detour if at next map change + // no plugins hook cvars. + m_HookDetour->DisableDetour(); +} + +void CvarManager::OnAmxxShutdown() +{ + // Free everything. + for (CvarsList::iterator cvar = m_Cvars.begin(); cvar != m_Cvars.end(); cvar = m_Cvars.erase(cvar)) + { + for (size_t i = 0; i < (*cvar)->hooks.length(); ++i) + { + delete (*cvar)->hooks[i]; + } + + delete (*cvar); + } + + m_Cache.clear(); + m_HookDetour->Destroy(); +} diff --git a/amxmodx/cvars.h b/amxmodx/CvarManager.h similarity index 100% rename from amxmodx/cvars.h rename to amxmodx/CvarManager.h diff --git a/amxmodx/Makefile b/amxmodx/Makefile index 10aae948..e83bcbfa 100755 --- a/amxmodx/Makefile +++ b/amxmodx/Makefile @@ -22,7 +22,8 @@ OBJECTS = meta_api.cpp CFile.cpp CVault.cpp vault.cpp float.cpp file.cpp modules optimizer.cpp format.cpp messages.cpp libraries.cpp vector.cpp sorting.cpp \ nongpl_matches.cpp CFlagManager.cpp datastructs.cpp \ trie_natives.cpp CDataPack.cpp datapacks.cpp stackstructs.cpp \ - CTextParsers.cpp textparse.cpp \ + CTextParsers.cpp textparse.cpp CvarManager.cpp cvars.cpp \ + ../public/memtools/CDetour/detours.cpp ../public/memtools/CDetour/asm/asm.c ############################################## ### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### diff --git a/amxmodx/amxmodx.cpp b/amxmodx/amxmodx.cpp index 5956214f..495a2361 100755 --- a/amxmodx/amxmodx.cpp +++ b/amxmodx/amxmodx.cpp @@ -22,25 +22,6 @@ extern CFlagManager FlagMan; CVector DynamicAdmins; -char CVarTempBuffer[64]; - -const char *invis_cvar_list[5] = {"amxmodx_version", "amxmodx_modules", "amx_debug", "amx_mldebug", "amx_client_languages"}; - -bool CheckBadConList(const char *cvar, int type) -{ - int i = 0; - while (NONGPL_CVAR_LIST[i].cvar != NULL) - { - if (NONGPL_CVAR_LIST[i].type == type - && strcmp(NONGPL_CVAR_LIST[i].cvar, cvar) == 0) - { - return true; - } - i++; - } - - return false; -} static cell AMX_NATIVE_CALL get_xvar_id(AMX *amx, cell *params) { @@ -112,36 +93,6 @@ static cell AMX_NATIVE_CALL emit_sound(AMX *amx, cell *params) /* 7 param */ return 1; } -static cell AMX_NATIVE_CALL enable_cvar_hook(AMX *amx, cell *params) /* 7 param */ -{ - Forward* forward = reinterpret_cast(params[1]); - - if (!forward) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); - return 0; - } - - forward->state = Forward::FSTATE_OK; - - return 1; -} - -static cell AMX_NATIVE_CALL disable_cvar_hook(AMX *amx, cell *params) /* 7 param */ -{ - Forward* forward = reinterpret_cast(params[1]); - - if (!forward) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); - return 0; - } - - forward->state = Forward::FSTATE_STOP; - - return 1; -} - static cell AMX_NATIVE_CALL server_print(AMX *amx, cell *params) /* 1 param */ { int len; @@ -1939,170 +1890,6 @@ static cell AMX_NATIVE_CALL client_cmd(AMX *amx, cell *params) /* 2 param */ return len; } -static cell AMX_NATIVE_CALL get_pcvar_string(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - return set_amxstring_utf8(amx, params[2], ptr->string ? ptr->string : "", ptr->string ? strlen(ptr->string) : 0, params[3] + 1); // EOS -} - -static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params) /* 3 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - - cvar_t* var = g_CvarManager.FindCvar(name); - - const char *value = var ? var->string : ""; - length = var ? strlen(value) : 0; - - return set_amxstring_utf8(amx, params[2], value, length, params[3] + 1); // + EOS -} - -static cell AMX_NATIVE_CALL get_pcvar_float(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - return amx_ftoc(ptr->value); -} - -static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) /* 1 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - - cvar_t* var = g_CvarManager.FindCvar(name); - - return var ? amx_ftoc(var->value) : 0; -} - -static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2])); - CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]); - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) /* 2 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - - cvar_t* var = g_CvarManager.FindCvar(name); - - if (var) - { - UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2])); - CVAR_DIRECTSET(var, &CVarTempBuffer[0]); - } - - return 1; -} - -static cell AMX_NATIVE_CALL get_pcvar_num(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - return (int)ptr->value; -} - -static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) /* 1 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - - cvar_t* var = g_CvarManager.FindCvar(name); - - return var ? (int)var->value : 0; - -} - -static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - UTIL_Format(CVarTempBuffer,sizeof(CVarTempBuffer)-1,"%d",params[2]); - CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]); - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) /* 2 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - int value = params[2]; - - cvar_t* var = g_CvarManager.FindCvar(name); - - if (var) - { - UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%d", value); - CVAR_DIRECTSET(var, &CVarTempBuffer[0]); - } - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - - cvar_t* var = g_CvarManager.FindCvar(name); - - if (var) - { - CVAR_DIRECTSET(var, get_amxstring(amx, params[2], 1, length)); - } - - return 1; -} - -static cell AMX_NATIVE_CALL set_pcvar_string(AMX *amx, cell *params) /* 2 param */ -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - int len; - - CVAR_DIRECTSET(ptr, get_amxstring(amx,params[2],0,len)); - - return 1; -} - static cell AMX_NATIVE_CALL log_message(AMX *amx, cell *params) /* 1 param */ { int len; @@ -2655,33 +2442,6 @@ static cell AMX_NATIVE_CALL task_exists(AMX *amx, cell *params) /* 1 param */ return g_tasksMngr.taskExists(params[1], params[2] ? 0 : amx); } -static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params) /* 1 param */ -{ - int ilen; - return (g_CvarManager.FindCvar(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0); -} - -static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) /* 3 param */ -{ - int length; - const char* name = get_amxstring(amx, params[1], 0, length); - const char* value = get_amxstring(amx, params[2], 1, length); - - int flags = params[3]; - float fvalue = amx_ctof(params[4]); - - CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); - - if (CheckBadConList(name, 0)) - { - plugin->AddToFailCounter(1); - } - - cvar_t* var = g_CvarManager.CreateCvar(name, value, fvalue, flags, plugin->getName(), plugin->getId()); - - return reinterpret_cast(var); -} - static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */ { int index = params[1]; @@ -3067,30 +2827,6 @@ static cell AMX_NATIVE_CALL remove_quotes(AMX *amx, cell *params) /* 1 param */ return 0; } -//native get_plugins_cvar(id, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0); -static cell AMX_NATIVE_CALL get_plugins_cvar(AMX *amx, cell *params) -{ - CvarInfo* info = g_CvarManager.FindCvar(params[1]); - - if (info) - { - set_amxstring(amx, params[2], info->name.chars(), params[3]); - *get_amxaddr(amx, params[4]) = info->var->flags; - *get_amxaddr(amx, params[5]) = info->pluginId; - *get_amxaddr(amx, params[6]) = reinterpret_cast(info->var); - - return 1; - } - - return 0; -} - -//native get_plugins_cvarsnum(); -static cell AMX_NATIVE_CALL get_plugins_cvarsnum(AMX *amx, cell *params) -{ - return g_CvarManager.GetRegCvarsCount(); -} - static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */ { int index = params[1]; @@ -3134,80 +2870,6 @@ static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param * return amx_ftoc(pfloat); } -static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params) -{ - int ilen; - char* sCvar = get_amxstring(amx, params[1], 0, ilen); - - if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats")) - return 0; - - cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); - - if (pCvar) - { - pCvar->flags &= ~((int)(params[2])); - return 1; - } - - return 0; -} - -static cell AMX_NATIVE_CALL get_pcvar_flags(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - return ptr->flags; -} - -static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params) -{ - int ilen; - char* sCvar = get_amxstring(amx, params[1], 0, ilen); - - cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); - - return pCvar ? pCvar->flags : 0; -} - -static cell AMX_NATIVE_CALL set_pcvar_flags(AMX *amx, cell *params) -{ - cvar_t *ptr = reinterpret_cast(params[1]); - if (!ptr) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); - return 0; - } - - ptr->flags = static_cast(params[2]); - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params) -{ - int ilen; - char* sCvar = get_amxstring(amx, params[1], 0, ilen); - - if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats")) - return 0; - - cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); - - if (pCvar) - { - pCvar->flags |= (int)(params[2]); - return 1; - } - - return 0; -} - static cell AMX_NATIVE_CALL force_unmodified(AMX *amx, cell *params) { int a; @@ -4156,102 +3818,6 @@ static cell AMX_NATIVE_CALL int3(AMX *amx, cell *params) /*********************************************************************/ -#if defined AMD64 -static bool g_warned_ccqv = false; -#endif -// native query_client_cvar(id, const cvar[], const resultfunc[]) -static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params) -{ - int numParams = params[0] / sizeof(cell); - - if (numParams != 3 && numParams != 5) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed!"); - return 0; - } - -#if defined AMD64 - if (!g_warned_ccqv) - { - LogError(amx, AMX_ERR_NATIVE, "[AMXX] Client CVAR Querying is not available on AMD64 (one time warn)"); - g_warned_ccqv = true; - } - - return 0; -#endif - - if (!g_NewDLL_Available) - { - LogError(amx, AMX_ERR_NATIVE, "Client CVAR querying is not enabled - check MM version!"); - return 0; - } - - int id = params[1]; - - if (id < 1 || id > gpGlobals->maxClients) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", id); - return 0; - } - - CPlayer *pPlayer = GET_PLAYER_POINTER_I(id); - - if (!pPlayer->initialized || pPlayer->IsBot()) - { - LogError(amx, AMX_ERR_NATIVE, "Player %d is either not connected or a bot", id); - return 0; - } - - int dummy; - const char *cvarname = get_amxstring(amx, params[2], 0, dummy); - const char *resultfuncname = get_amxstring(amx, params[3], 1, dummy); - - // public clientcvarquery_result(id, const cvar[], const result[], [const param[]]) - int iFunc; - - if (numParams == 5 && params[4] != 0) - iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_ARRAY, FP_DONE); - else - iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_DONE); - - if (iFunc == -1) - { - LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", resultfuncname); - return 0; - } - - ClientCvarQuery_Info *queryObject = new ClientCvarQuery_Info; - queryObject->resultFwd = iFunc; - queryObject->requestId = MAKE_REQUESTID(PLID); - - if (numParams == 5 && params[4] != 0) - { - queryObject->paramLen = params[4] + 1; - queryObject->params = new cell[queryObject->paramLen]; - - if (!queryObject->params) - { - delete queryObject; - unregisterSPForward(iFunc); - LogError(amx, AMX_ERR_MEMORY, "Hmm. Out of memory?"); - return 0; - } - - memcpy(reinterpret_cast(queryObject->params), reinterpret_cast(get_amxaddr(amx, params[5])), queryObject->paramLen * sizeof(cell)); - - queryObject->params[queryObject->paramLen - 1] = 0; - } else { - queryObject->params = NULL; - queryObject->paramLen = 0; - } - - pPlayer->queries.push_back(queryObject); - - QUERY_CLIENT_CVAR_VALUE2(pPlayer->pEdict, cvarname, queryObject->requestId); - - return 1; -} - static cell AMX_NATIVE_CALL amx_abort(AMX *amx, cell *params) { int err = params[1]; @@ -4480,16 +4046,6 @@ static cell AMX_NATIVE_CALL DestroyForward(AMX *amx, cell *params) return 1; } -static cell AMX_NATIVE_CALL get_cvar_pointer(AMX *amx, cell *params) -{ - int len; - char *name = get_amxstring(amx, params[1], 0, len); - - cvar_t *ptr = g_CvarManager.FindCvar(name); - - return reinterpret_cast(ptr); -} - CVector g_hudsync; static cell AMX_NATIVE_CALL CreateHudSyncObj(AMX *amx, cell *params) @@ -4861,29 +4417,6 @@ static cell AMX_NATIVE_CALL has_map_ent_class(AMX *amx, cell *params) return len && !FNullEnt(FIND_ENTITY_BY_STRING(NULL, "classname", name)); }; -// hook_cvar_change(cvarHandle, const callback[]) -static cell AMX_NATIVE_CALL hook_cvar_change(AMX *amx, cell *params) -{ - cvar_t* var = reinterpret_cast(params[1]); - - if (!var) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid cvar handle: %p", var); - return 0; - } - - const char* callback; - Forward* forward = g_CvarManager.HookCvarChange(var, amx, params[2], &callback); - - if (!forward) - { - LogError(amx, AMX_ERR_NATIVE, "Invalid callback function: %s", callback); - return 0; - } - - return reinterpret_cast(forward); -} - static cell AMX_NATIVE_CALL is_rukia_a_hag(AMX *amx, cell *params) { return 1; @@ -4918,10 +4451,7 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"client_print_color", client_print_color}, {"console_cmd", console_cmd}, {"console_print", console_print}, - {"cvar_exists", cvar_exists}, {"emit_sound", emit_sound}, - {"enable_cvar_hook", enable_cvar_hook}, - {"disable_cvar_hook", disable_cvar_hook}, {"engclient_cmd", engclient_cmd}, {"engclient_print", engclient_print}, {"find_player", find_player}, @@ -4933,11 +4463,6 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"get_concmd", get_concmd}, {"get_concmdsnum", get_concmdsnum}, {"get_concmd_plid", get_concmd_plid}, - {"get_cvar_flags", get_cvar_flags}, - {"get_cvar_float", get_cvar_float}, - {"get_cvar_num", get_cvar_num}, - {"get_cvar_pointer", get_cvar_pointer}, - {"get_cvar_string", get_cvar_string}, {"get_flags", get_flags}, {"get_func_id", get_func_id}, {"get_gametime", get_gametime}, @@ -4949,16 +4474,10 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"get_modname", get_modname}, {"get_module", get_module}, {"get_modulesnum", get_modulesnum}, - {"get_pcvar_flags", get_pcvar_flags}, - {"get_pcvar_float", get_pcvar_float}, - {"get_pcvar_num", get_pcvar_num}, - {"get_pcvar_string", get_pcvar_string}, {"get_players", get_players}, {"get_playersnum", get_playersnum}, {"get_plugin", get_plugin}, {"get_pluginsnum", get_pluginsnum}, - {"get_plugins_cvar", get_plugins_cvar}, - {"get_plugins_cvarsnum", get_plugins_cvarsnum}, {"get_srvcmd", get_srvcmd}, {"get_srvcmdsnum", get_srvcmdsnum}, {"get_systime", get_systime}, @@ -4995,7 +4514,6 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"get_xvar_id", get_xvar_id}, {"get_xvar_num", get_xvar_num}, {"has_map_ent_class", has_map_ent_class}, - {"hook_cvar_change", hook_cvar_change}, {"int3", int3}, {"is_amd64_server", is_amd64_server}, {"is_dedicated_server", is_dedicated_server}, @@ -5028,7 +4546,6 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"precache_model", precache_model}, {"precache_sound", precache_sound}, {"precache_generic", precache_generic}, - {"query_client_cvar", query_client_cvar}, {"random_float", random_float}, {"random_num", random_num}, {"read_argc", read_argc}, @@ -5043,7 +4560,6 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"read_logdata", read_logdata}, {"register_clcmd", register_clcmd}, {"register_concmd", register_concmd}, - {"register_cvar", register_cvar}, {"register_dictionary", register_dictionary}, {"register_event", register_event}, {"register_logevent", register_logevent}, @@ -5052,25 +4568,16 @@ AMX_NATIVE_INFO amxmodx_Natives[] = {"register_plugin", register_plugin}, {"register_srvcmd", register_srvcmd}, {"require_module", require_module}, - {"remove_cvar_flags", remove_cvar_flags}, {"remove_quotes", remove_quotes}, {"remove_task", remove_task}, {"remove_user_flags", remove_user_flags}, {"server_cmd", server_cmd}, {"server_exec", server_exec}, {"server_print", server_print}, - {"set_cvar_flags", set_cvar_flags}, - {"set_cvar_float", set_cvar_float}, - {"set_cvar_num", set_cvar_num}, - {"set_cvar_string", set_cvar_string}, {"set_fail_state", set_fail_state}, {"set_dhudmessage", set_dhudmessage}, {"set_hudmessage", set_hudmessage}, {"set_localinfo", set_localinfo}, - {"set_pcvar_flags", set_pcvar_flags}, - {"set_pcvar_float", set_pcvar_float}, - {"set_pcvar_string", set_pcvar_string}, - {"set_pcvar_num", set_pcvar_num}, {"set_task", set_task}, {"set_user_flags", set_user_flags}, {"set_user_info", set_user_info}, diff --git a/amxmodx/amxmodx.h b/amxmodx/amxmodx.h index 8592c9c3..dcc0ed24 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -47,7 +47,7 @@ #include "CLang.h" #include "fakemeta.h" #include "amxxlog.h" -#include "cvars.h" +#include "CvarManager.h" #define AMXXLOG_Log g_log.Log #define AMXXLOG_Error g_log.LogError @@ -66,6 +66,7 @@ extern AMX_NATIVE_INFO g_SortNatives[]; extern AMX_NATIVE_INFO g_DataStructNatives[]; extern AMX_NATIVE_INFO g_StackNatives[]; extern AMX_NATIVE_INFO g_TextParserNatives[]; +extern AMX_NATIVE_INFO g_CvarNatives[]; #if defined(_WIN32) #define DLLOAD(path) (DLHANDLE)LoadLibrary(path) diff --git a/amxmodx/cvars.cpp b/amxmodx/cvars.cpp index 83b67c06..19dba289 100644 --- a/amxmodx/cvars.cpp +++ b/amxmodx/cvars.cpp @@ -7,342 +7,520 @@ // Additional exceptions apply. For full license details, see LICENSE.txt or visit: // https://alliedmods.net/amxmodx-license -#include "cvars.h" +#include "CvarManager.h" #include "amxmodx.h" -#include +#include "nongpl_matches.h" -CvarManager g_CvarManager; +char CVarTempBuffer[64]; +const char *invis_cvar_list[5] = { "amxmodx_version", "amxmodx_modules", "amx_debug", "amx_mldebug", "amx_client_languages" }; -/** - * Returns true to call original function, otherwise false to block it. - */ -bool Cvar_DirectSet_Custom(cvar_t* var, const char* value) +// register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0) +static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) { - CvarInfo* info = nullptr; + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + const char* value = get_amxstring(amx, params[2], 1, length); - 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. + int flags = params[3]; + float fvalue = amx_ctof(params[4]); + + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + if (CheckBadConList(name, 0)) { - return true; + plugin->AddToFailCounter(1); } - int lastResult = 0; - int result; + cvar_t* var = g_CvarManager.CreateCvar(name, value, fvalue, flags, plugin->getName(), plugin->getId()); - for (size_t i = 0; i < info->hooks.length(); ++i) + return reinterpret_cast(var); +} + +// cvar_exists(const cvar[]) +static cell AMX_NATIVE_CALL cvar_exists(AMX *amx, cell *params) +{ + int ilen; + return (g_CvarManager.FindCvar(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0); +} + +// get_cvar_pointer(const cvar[]) +static cell AMX_NATIVE_CALL get_cvar_pointer(AMX *amx, cell *params) +{ + int len; + char *name = get_amxstring(amx, params[1], 0, len); + + cvar_t *ptr = g_CvarManager.FindCvar(name); + + return reinterpret_cast(ptr); +} + +// hook_cvar_change(cvarHandle, const callback[]) +static cell AMX_NATIVE_CALL hook_cvar_change(AMX *amx, cell *params) +{ + cvar_t* var = reinterpret_cast(params[1]); + + if (!var) { - CvarPlugin* p = info->hooks[i]; - - if (p->forward->state == Forward::FSTATE_OK) // Our callback can be enable/disabled by natives. - { - result = executeForwards(p->forward->id, reinterpret_cast(var), var->string, value); - - if (result >= lastResult) - { - lastResult = result; - } - } + LogError(amx, AMX_ERR_NATIVE, "Invalid cvar handle: %p", var); + return 0; } - return !!!lastResult; -} + const char* callback; + Forward* forward = g_CvarManager.HookCvarChange(var, amx, params[2], &callback); -DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value) -{ - if (Cvar_DirectSet_Custom(var, value)) + if (!forward) { - DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value); + LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", callback); + return 0; } + + return reinterpret_cast(forward); } -CvarManager::CvarManager() : m_AmxmodxCvars(0), m_HookDetour(nullptr) +// enable_cvar_hook(cvarhook:handle); +static cell AMX_NATIVE_CALL enable_cvar_hook(AMX *amx, cell *params) { + Forward* forward = reinterpret_cast(params[1]); + + if (!forward) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); + return 0; + } + + forward->state = Forward::FSTATE_OK; + + return 1; } -CvarManager::~CvarManager() +// disable_cvar_hook(cvarhook:handle); +static cell AMX_NATIVE_CALL disable_cvar_hook(AMX *amx, cell *params) { - OnAmxxShutdown(); + Forward* forward = reinterpret_cast(params[1]); + + if (!forward) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); + return 0; + } + + forward->state = Forward::FSTATE_STOP; + + return 1; } -void CvarManager::CreateCvarHook(void) +// get_cvar_flags(const cvar[]) +static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params) { - // void PF_Cvar_DirectSet(struct cvar_s *var, const char *value) // = pfnCvar_DirectSet - // { - // Cvar_DirectSet(var, value); // <- We want to hook this. - // } + int ilen; + char* sCvar = get_amxstring(amx, params[1], 0, ilen); - byte *baseAddress = (byte *)g_engfuncs.pfnCvar_DirectSet; - uintptr_t *functionAddress = nullptr; + cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); -#if defined(WIN32) - // 55 push ebp - // 8B EC mov ebp, esp - // 8B 45 0C mov eax, [ebp+arg_4] - // 8B 4D 08 mov ecx, [ebp+arg_0] - // 50 push eax - // 51 push ecx - // E8 XX XX XX XX call Cvar_DirectSet - const byte opcodeJump = 0xE8; -#else - // E9 XX XX XX XX jmp Cvar_DirectSet - const byte opcodeJump = 0xE9; + return pCvar ? pCvar->flags : 0; +} + +// get_cvar_float(const cvarname[]) +static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + + cvar_t* var = g_CvarManager.FindCvar(name); + + return var ? amx_ftoc(var->value) : 0; +} + +// get_cvar_num(const cvarname[]) +static cell AMX_NATIVE_CALL get_cvar_num(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + + cvar_t* var = g_CvarManager.FindCvar(name); + + return var ? (int)var->value : 0; +} + +// get_cvar_string(const cvarname[], output[], iLen) +static cell AMX_NATIVE_CALL get_cvar_string(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + + cvar_t* var = g_CvarManager.FindCvar(name); + + const char *value = var ? var->string : ""; + length = var ? strlen(value) : 0; + + return set_amxstring_utf8(amx, params[2], value, length, params[3] + 1); // + EOS +} + +// set_cvar_flags(const cvar[], flags) +static cell AMX_NATIVE_CALL set_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx, params[1], 0, ilen); + + if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats")) + return 0; + + cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); + + if (pCvar) + { + pCvar->flags |= (int)(params[2]); + return 1; + } + + return 0; +} + +// set_cvar_float(const cvar[], Float:value) +static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + + cvar_t* var = g_CvarManager.FindCvar(name); + + if (var) + { + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2])); + CVAR_DIRECTSET(var, &CVarTempBuffer[0]); + } + + return 1; +} + +// set_cvar_num(const cvarname[], value) +static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + int value = params[2]; + + cvar_t* var = g_CvarManager.FindCvar(name); + + if (var) + { + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%d", value); + CVAR_DIRECTSET(var, &CVarTempBuffer[0]); + } + + return 1; +} + +// set_cvar_string(const cvar[], const value[]) +static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) +{ + int length; + const char* name = get_amxstring(amx, params[1], 0, length); + + cvar_t* var = g_CvarManager.FindCvar(name); + + if (var) + { + CVAR_DIRECTSET(var, get_amxstring(amx, params[2], 1, length)); + } + + return 1; +} + +// get_pcvar_flags(pcvar) +static cell AMX_NATIVE_CALL get_pcvar_flags(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return ptr->flags; +} + +// Float:get_pcvar_float(pcvar) +static cell AMX_NATIVE_CALL get_pcvar_float(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return amx_ftoc(ptr->value); +} + +// get_pcvar_num(pcvar) +static cell AMX_NATIVE_CALL get_pcvar_num(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return (int)ptr->value; +} + +// get_pcvar_string(pcvar, string[], maxlen) +static cell AMX_NATIVE_CALL get_pcvar_string(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return set_amxstring_utf8(amx, params[2], ptr->string ? ptr->string : "", ptr->string ? strlen(ptr->string) : 0, params[3] + 1); // EOS +} + +// set_pcvar_flags(pcvar, flags) +static cell AMX_NATIVE_CALL set_pcvar_flags(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + ptr->flags = static_cast(params[2]); + + return 1; +} + +// set_pcvar_float(pcvar, Float:num) +static cell AMX_NATIVE_CALL set_pcvar_float(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2])); + CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]); + + return 1; +} + +// set_pcvar_num(pcvar, num) +static cell AMX_NATIVE_CALL set_pcvar_num(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%d", params[2]); + CVAR_DIRECTSET(ptr, &CVarTempBuffer[0]); + + return 1; +} + +// set_pcvar_string(pcvar, const string[]) +static cell AMX_NATIVE_CALL set_pcvar_string(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + if (!ptr) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + int len; + + CVAR_DIRECTSET(ptr, get_amxstring(amx, params[2], 0, len)); + + return 1; +} + +// remove_cvar_flags(const cvar[], flags=-1) +static cell AMX_NATIVE_CALL remove_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx, params[1], 0, ilen); + + if (!strcmp(sCvar, "amx_version") || !strcmp(sCvar, "amxmodx_version") || !strcmp(sCvar, "fun_version") || !strcmp(sCvar, "sv_cheats")) + return 0; + + cvar_t* pCvar = g_CvarManager.FindCvar(sCvar); + + if (pCvar) + { + pCvar->flags &= ~((int)(params[2])); + return 1; + } + + return 0; +} + +// get_plugins_cvar(id, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0) +static cell AMX_NATIVE_CALL get_plugins_cvar(AMX *amx, cell *params) +{ + CvarInfo* info = g_CvarManager.FindCvar(params[1]); + + if (info) + { + set_amxstring(amx, params[2], info->name.chars(), params[3]); + *get_amxaddr(amx, params[4]) = info->var->flags; + *get_amxaddr(amx, params[5]) = info->pluginId; + *get_amxaddr(amx, params[6]) = reinterpret_cast(info->var); + + return 1; + } + + return 0; +} + +// get_plugins_cvarsnum() +static cell AMX_NATIVE_CALL get_plugins_cvarsnum(AMX *amx, cell *params) +{ + return g_CvarManager.GetRegCvarsCount(); +} + +#if defined AMD64 +static bool g_warned_ccqv = false; +#endif +// query_client_cvar(id, const cvar[], const resultfunc[]) +static cell AMX_NATIVE_CALL query_client_cvar(AMX *amx, cell *params) +{ + int numParams = params[0] / sizeof(cell); + + if (numParams != 3 && numParams != 5) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid number of parameters passed!"); + return 0; + } + +#if defined AMD64 + if (!g_warned_ccqv) + { + LogError(amx, AMX_ERR_NATIVE, "[AMXX] Client CVAR Querying is not available on AMD64 (one time warn)"); + g_warned_ccqv = true; + } + + return 0; #endif - const byte opcodeJumpSize = 5; - const byte opcodeJumpByteSize = 1; - - const int maxBytesLimit = 20; - - for (size_t i = 0; i < maxBytesLimit; ++i, ++baseAddress) + if (!g_NewDLL_Available) { - if (*baseAddress == opcodeJump) - { - functionAddress = (uintptr_t *)(&baseAddress[opcodeJumpSize] + *(uintptr_t *)&baseAddress[opcodeJumpByteSize]); - break; - } + LogError(amx, AMX_ERR_NATIVE, "Client CVAR querying is not enabled - check MM version!"); + return 0; } - if (functionAddress) - { - m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress); + int id = params[1]; - if (m_HookDetour) - { - m_HookDetour->EnableDetour(); - } + if (id < 1 || id > gpGlobals->maxClients) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid player id %d", id); + return 0; } -} -cvar_t* CvarManager::CreateCvar(const char* name, const char* value, float fvalue, int flags, const char* plugin, int plugnId) -{ - cvar_t* var = nullptr; - CvarInfo* info = nullptr; + CPlayer *pPlayer = GET_PLAYER_POINTER_I(id); - if (!CacheLookup(name, &info)) + if (!pPlayer->initialized || pPlayer->IsBot()) { - // Not cached - Is cvar already exist? - var = CVAR_GET_POINTER(name); + LogError(amx, AMX_ERR_NATIVE, "Player %d is either not connected or a bot", id); + return 0; + } - // Whether it exists, we need to prepare a new entry. - info = new CvarInfo(); + int dummy; + const char *cvarname = get_amxstring(amx, params[2], 0, dummy); + const char *resultfuncname = get_amxstring(amx, params[3], 1, dummy); - // Shared datas. - info->name = name; - info->plugin = plugin; - info->pluginId = plugnId; + // public clientcvarquery_result(id, const cvar[], const result[], [const param[]]) + int iFunc; - if (var) + if (numParams == 5 && params[4] != 0) + iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_ARRAY, FP_DONE); + else + iFunc = registerSPForwardByName(amx, resultfuncname, FP_CELL, FP_STRING, FP_STRING, FP_DONE); + + if (iFunc == -1) + { + LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", resultfuncname); + return 0; + } + + ClientCvarQuery_Info *queryObject = new ClientCvarQuery_Info; + queryObject->resultFwd = iFunc; + queryObject->requestId = MAKE_REQUESTID(PLID); + + if (numParams == 5 && params[4] != 0) + { + queryObject->paramLen = params[4] + 1; + queryObject->params = new cell[queryObject->paramLen]; + + if (!queryObject->params) { - // Cvar already exists. Just copy. - // "string" will be set after. "value" and "next" are automatically set. - info->var = var; - info->defaultval = var->string; - info->amxmodx = false; - } - else - { - // Registers a new cvar. - static cvar_t cvar_reg_helper; - - // "string" will be set after. "value" and "next" are automatically set. - cvar_reg_helper.name = info->name.chars(); - cvar_reg_helper.string = ""; - cvar_reg_helper.flags = flags; - - // Adds cvar to global list. - CVAR_REGISTER(&cvar_reg_helper); - - // Registering can fail if name is already a registered command. - var = CVAR_GET_POINTER(name); - - // If so, we can't go further. - if (!var) - { - delete info; - return nullptr; - } - - // If ok, we got a valid pointer, we can copy. - info->var = var; - info->defaultval = value; - info->amxmodx = true; - - // Keeps track count of cvars registered by AMXX. - ++m_AmxmodxCvars; + delete queryObject; + unregisterSPForward(iFunc); + LogError(amx, AMX_ERR_MEMORY, "Hmm. Out of memory?"); + return 0; } - // Add a new entry in the caches. - m_Cvars.append(info); - m_Cache.insert(name, info); + memcpy(reinterpret_cast(queryObject->params), reinterpret_cast(get_amxaddr(amx, params[5])), queryObject->paramLen * sizeof(cell)); - // Make sure that whether an existing or new cvar is set to the given value. - CVAR_DIRECTSET(var, value); + queryObject->params[queryObject->paramLen - 1] = 0; + } + else { + queryObject->params = NULL; + queryObject->paramLen = 0; } - return info->var; + pPlayer->queries.push_back(queryObject); + + QUERY_CLIENT_CVAR_VALUE2(pPlayer->pEdict, cvarname, queryObject->requestId); + + return 1; } -cvar_t* CvarManager::FindCvar(const char* name) + +AMX_NATIVE_INFO g_CvarNatives[] = { - cvar_t* var = nullptr; - CvarInfo* info = nullptr; + {"register_cvar", register_cvar}, + {"cvar_exists", cvar_exists}, + {"get_cvar_pointer", get_cvar_pointer}, - // Do we have already cvar in cache? - if (CacheLookup(name, &info)) - { - return info->var; - } + {"hook_cvar_change", hook_cvar_change}, + {"enable_cvar_hook", enable_cvar_hook}, + {"disable_cvar_hook", disable_cvar_hook}, - // Cvar doesn't exist. - if (!(var = CVAR_GET_POINTER(name))) - { - return nullptr; - } + {"get_cvar_flags", get_cvar_flags}, + {"get_cvar_float", get_cvar_float}, + {"get_cvar_num", get_cvar_num}, + {"get_cvar_string", get_cvar_string}, - // Create a new entry. - info = new CvarInfo(); - info->var = var; - info->name = name; - info->plugin = ""; - info->pluginId = -1; - info->amxmodx = false; + {"set_cvar_flags", set_cvar_flags}, + {"set_cvar_float", set_cvar_float}, + {"set_cvar_num", set_cvar_num}, + {"set_cvar_string", set_cvar_string}, - // Add entry in the caches. - m_Cvars.append(info); - m_Cache.insert(name, info); + {"get_pcvar_flags", get_pcvar_flags}, + {"get_pcvar_float", get_pcvar_float}, + {"get_pcvar_num", get_pcvar_num}, + {"get_pcvar_string", get_pcvar_string}, - return var; -} + {"set_pcvar_flags", set_pcvar_flags}, + {"set_pcvar_float", set_pcvar_float}, + {"set_pcvar_string", set_pcvar_string}, + {"set_pcvar_num", set_pcvar_num}, -CvarInfo* CvarManager::FindCvar(size_t index) -{ - // Used by get_plugins_cvar native. - // For compatibility, only cvars registered by AMXX are concerned. + {"remove_cvar_flags", remove_cvar_flags}, - size_t iter_id = 0; - - for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++) - { - if (iter->amxmodx && iter_id++ == index) - { - return *(iter); - } - } - - return nullptr; -} - -bool CvarManager::CacheLookup(const char* name, CvarInfo** info) -{ - return m_Cache.retrieve(name, info); -} - -Forward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback) -{ - CvarInfo* info = nullptr; - - // A cvar is guaranteed to be in cache if pointer is got from - // get_cvar_pointer and register_cvar natives. Though it might be - // provided by another way. If by any chance we run in such - // situation, we create a new entry right now. - - 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; - - // Add entry in the caches. - m_Cvars.append(info); - m_Cache.insert(info->name.chars(), info); - } - - int length; - *callback = get_amxstring(amx, param, 0, length); - - int forwardId = registerSPForwardByName(amx, *callback, FP_CELL, FP_STRING, FP_STRING, FP_DONE); - - // Invalid callback, it could be: not a public function, wrongly named, or simply missing. - if (forwardId == -1) - { - return nullptr; - } - - // Detour is disabled on map change. - m_HookDetour->EnableDetour(); + {"get_plugins_cvar", get_plugins_cvar}, + {"get_plugins_cvarsnum", get_plugins_cvarsnum}, - Forward* forward = new Forward(forwardId, *callback); - info->hooks.append(new CvarPlugin(g_plugins.findPlugin(amx)->getId(), forward)); + {"query_client_cvar", query_client_cvar}, - return forward; -} - -size_t CvarManager::GetRegCvarsCount() -{ - return m_AmxmodxCvars; -} - -void CvarManager::OnConsoleCommand() -{ - print_srvconsole("Registered cvars:\n"); - print_srvconsole(" %-24.23s %-24.23s %-16.15s\n", "name", "value", "plugin"); - - size_t index = 0; - ke::AString pluginName; - - if (CMD_ARGC() > 2) // Searching for cvars registered to a plugin - { - pluginName = CMD_ARGV(2); - } - - for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++) - { - CvarInfo* ci = (*iter); - - if (ci->amxmodx && (!pluginName.length() || strncmp(ci->name.chars(), pluginName.chars(), pluginName.length()) == 0)) - { - print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++index, ci->name.chars(), ci->var->string, ci->plugin.chars()); - } - } -} - -void CvarManager::OnPluginUnloaded() -{ - // Clear only plugin hooks list. - for (CvarsList::iterator cvar = m_Cvars.begin(); cvar != m_Cvars.end(); cvar++) - { - for (size_t i = 0; i < (*cvar)->hooks.length(); ++i) - { - delete (*cvar)->hooks[i]; - } - - (*cvar)->hooks.clear(); - } - - // There is no point to enable detour if at next map change - // no plugins hook cvars. - m_HookDetour->DisableDetour(); -} - -void CvarManager::OnAmxxShutdown() -{ - // Free everything. - for (CvarsList::iterator cvar = m_Cvars.begin(); cvar != m_Cvars.end(); cvar = m_Cvars.erase(cvar)) - { - for (size_t i = 0; i < (*cvar)->hooks.length(); ++i) - { - delete (*cvar)->hooks[i]; - } - - delete (*cvar); - } - - m_Cache.clear(); - m_HookDetour->Destroy(); -} + {NULL, NULL} +}; \ No newline at end of file diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 82fae683..41507cbb 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -31,7 +31,7 @@ #include "trie_natives.h" #include "CDataPack.h" #include "textparse.h" -#include "cvars.h" +#include "CvarManager.h" plugin_info_t Plugin_info = { diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index a6089af6..4b065c32 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -553,6 +553,7 @@ int set_amxnatives(AMX* amx, char error[128]) amx_Register(amx, g_DatapackNatives, -1); amx_Register(amx, g_StackNatives, -1); amx_Register(amx, g_TextParserNatives, -1); + amx_Register(amx, g_CvarNatives, -1); //we're not actually gonna check these here anymore amx->flags |= AMX_FLAG_PRENIT; diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj b/amxmodx/msvc12/amxmodx_mm.vcxproj index b871d45f..1cc3ed54 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj @@ -319,6 +319,7 @@ + @@ -389,7 +390,7 @@ - + diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters index e0c0e65a..6c60ac4a 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters @@ -192,15 +192,18 @@ SDK - - Source Files - Memtools\CDetour Memtools\CDetour\asm + + Source Files + + + Source Files + @@ -347,9 +350,6 @@ SDK - - Header Files - Memtools\CDetour @@ -359,6 +359,9 @@ Memtools\CDetour\asm + + Header Files + diff --git a/amxmodx/nongpl_matches.cpp b/amxmodx/nongpl_matches.cpp index b0d31dd1..d8bec891 100644 --- a/amxmodx/nongpl_matches.cpp +++ b/amxmodx/nongpl_matches.cpp @@ -30,3 +30,19 @@ NONGPL_CVAR_T NONGPL_CVAR_LIST[] = {"amx_gg", 1}, {NULL, 0}, }; + +bool CheckBadConList(const char *cvar, int type) +{ + int i = 0; + while (NONGPL_CVAR_LIST[i].cvar != NULL) + { + if (NONGPL_CVAR_LIST[i].type == type + && strcmp(NONGPL_CVAR_LIST[i].cvar, cvar) == 0) + { + return true; + } + i++; + } + + return false; +} diff --git a/amxmodx/nongpl_matches.h b/amxmodx/nongpl_matches.h index 1ea1d2df..18c0f756 100644 --- a/amxmodx/nongpl_matches.h +++ b/amxmodx/nongpl_matches.h @@ -25,5 +25,6 @@ struct NONGPL_CVAR_T extern NONGPL_PLUGIN_T NONGPL_PLUGIN_LIST[]; extern NONGPL_CVAR_T NONGPL_CVAR_LIST[]; +extern bool CheckBadConList(const char *cvar, int type); #endif //_INCLUDE_AMXMODX_NONGPL_MATCHES_H_ diff --git a/plugins/include/amxconst.inc b/plugins/include/amxconst.inc index e6830eef..7616d819 100755 --- a/plugins/include/amxconst.inc +++ b/plugins/include/amxconst.inc @@ -105,20 +105,6 @@ public stock const MaxClients; /* Maximum number of players the server supports #define PLUGIN_HANDLED 1 /* stop other plugins */ #define PLUGIN_HANDLED_MAIN 2 /* to use in client_command(), continue all plugins but stop the command */ -/** - * CVAR flags for register_cvar() - */ -#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 */ -#define FCVAR_EXTDLL 8 /* Defined by external DLL */ -#define FCVAR_CLIENTDLL 16 /* Defined by the client dll */ -#define FCVAR_PROTECTED 32 /* It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value */ -#define FCVAR_SPONLY 64 /* This cvar cannot be changed by clients connected to a multiplayer server. */ -#define FCVAR_PRINTABLEONLY 128 /* This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). */ -#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 */ - /** * IDs of weapons in CS */ diff --git a/plugins/include/amxmodx.inc b/plugins/include/amxmodx.inc index 78107435..fc9468b3 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -1404,159 +1404,6 @@ native amxclient_cmd(index, const command[], const arg1[]="", const arg2[]=""); */ native server_cmd(const command[], any:...); -/** - * Sets a cvar to a given string value. The cvar is accessed by name. - * - * @note Accessing a cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the set_pcvar_string function. - * - * @param cvar Cvar name to set value of - * @param value Value to set cvar to - * - * @noreturn - */ -native set_cvar_string(const cvar[], const value[]); - -/** - * Returns if a cvar is registered on the server. - * - * @param cvar Cvar name to check - * - * @return 1 if the cvar exists, 0 otherwise - */ -native cvar_exists(const cvar[]); - -/** - * Removes specified flags from a cvar. The cvar is accessed by name. - * - * @note Not permitted for the "amx_version", "amxmodx_version", "fun_version" - * and "sv_cheats" cvars. - * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc - * @note This function removes the flags using a bitwise-and operation. - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the set_pcvar_flags function. - * - * - * @param cvar Cvar name to remove flags from - * @param flags Bitflag sum of flags to remove - * - * @return 1 on success, 0 if cvar does not exist or is not permitted - */ -native remove_cvar_flags(const cvar[], flags=-1); - -/** - * Sets specified flags to a cvar. The cvar is accessed by name. - * - * @note Not permitted for the "amx_version", "amxmodx_version", "fun_version" - * and "sv_cheats" cvars. - * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc - * @note This function just adds the flags using a bitwise-or operation. After - * it has run the flags may not exactly equal the specified bitflag sum. - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the set_pcvar_flags function. - * - * @param cvar Cvar name to remove flags from - * @param flags Bitflag sum of flags to set - * - * @return 1 on success, 0 if cvar does not exist or is not permitted - */ -native set_cvar_flags(const cvar[], flags); - -/** - * Returns flags of a cvar. The cvar is accessed by name. - * - * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the get_pcvar_flags function. - * - * @param cvar Cvar name to retrieve flags from - * - * @return 1 on success, 0 if cvar does not exist or is not permitted - */ -native get_cvar_flags(const cvar[]); - -/** - * Sets a cvar to a given float value. The cvar is accessed by name. - * - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the set_pcvar_float function. - * - * @param cvar Cvar name to set value of - * @param value Value to set cvar to - * - * @noreturn - */ -native set_cvar_float(const cvar[], Float:value); - -/** - * Returns a floating value from a cvar. The cvar is accessed by name. - * - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the get_pcvar_float function. - * - * @param cvarname Cvar name to retrieve value from - * - * @return Cvar value, converted to float - */ -native Float:get_cvar_float(const cvarname[]); - -/** - * Returns an integer value from a cvar. The cvar is accessed by name. - * - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the get_pcvar_num function. - * - * @param cvarname Cvar name to retrieve value from - * - * @return Cvar value, converted to int - */ -native get_cvar_num(const cvarname[]); - -/** - * Sets a cvar to a given integer value. The cvar is accessed by name. - * - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the set_pcvar_num function. - * - * @param cvar Cvar name to set value of - * @param value Value to set cvar to - * - * @noreturn - */ -native set_cvar_num(const cvarname[], value); - -/** - * Gets a string value from a cvar. The cvar is accessed by name. - * - * @note Accessing a Cvar by name requires this function to walk through the - * engine's cvar list every time, which can result in a considerable waste - * of processing time, especially if many cvars have been registered. For - * a vastly superior alternative look at the get_pcvar_string function. - * - * @param cvar Cvar name to retrieve value from - * @param output Buffer to copy cvar value to - * @param iLen Maximum size of the buffer - * - * @return Number of cells written to buffer. - */ -native get_cvar_string(const cvarname[], output[], iLen); - /** * Retrieves the name of the currently played map. * @@ -1964,31 +1811,6 @@ native get_concmd_plid(cid, flag_mask, id_type); */ native get_concmdsnum(flag, id=-1); -/** - * Returns the number of plugin-registered cvars. - * - * @return Number of registered cvars - */ -native get_plugins_cvarsnum(); - -/** - * Retrieves information about a plugin-registered cvar. - * - * @note The returned cvar pointer should be used with the get_pcvar_* and - * set_pcvar_* set of functions. - * - * @param num Cvar index, this does not equal the cvar pointer, it is - * the internal index, incremented for each registered cvar - * @param name Buffer to copy cvar name to - * @param namelen Maximum buffer size - * @param flags Variable to store cvar flags to - * @param plugin_id Variable to store id of the registering plugin to - * @param pcvar_handle Variable to store cvar pointer to - * - * @return 1 on success, 0 if index is invalid - */ -native get_plugins_cvar(num, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0); - /** * Returns unique menu id of a menu. * @@ -2058,23 +1880,6 @@ native server_exec(); */ native emit_sound(index, channel, const sample[], Float:vol, Float:att, flags, pitch); -/** - * Registers a new cvar for the engine. - * - * @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 - * set_pcvar_* set of functions. - * - * @param name Cvar name - * @param string Default cvar value - * @param flags Cvar flags - * @param fvalue Unused - * - * @return Unique cvar pointer - */ -native register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0); - /** * Returns a random floating point value generated by the engine. * @@ -2806,35 +2611,6 @@ native set_array(param, const source[], size); */ native set_array_f(param, const Float:source[], size); -/** - * Dispatches a client cvar query, allowing the plugin to query for its value on - * the client. - * - * @note The callback will be called in the following manner: - * - * public cvar_query_callback(id, const cvar[], const value[], const param[]) - * - * id - Client index - * cvar - Cvar queried - * value - Cvar value on the client - * param - Extra data [optional] - * - * @param id Client index - * @param cvar Cvar to query - * @param resultFunc Callback function - * @param paramlen Size of extra data - * @param params Extra data to pass through to callback - * - * @noreturn - * @error If the client index is not within the range of 1 to - * MaxClients or the client is not connected, an error - * will be thrown. - * If the callback function is invalid, cvar querying is - * unavailable or the querying process runs out of memory, - * an error will be thrown. - */ -native query_client_cvar(id, const cvar[], const resultFunc[], paramlen=0, const params[]=""); - /** * Allows to trap error messages that occur in a plugin. * @@ -3220,110 +2996,6 @@ native ExecuteForward(forward_handle, &ret, any:...); */ native DestroyForward(forward_handle); -/** - * Returns the cvar pointer of the specified cvar. - * - * @note A pointer is also returned by register_cvar(). Plugins can (and should) - * retrieve and use pointers for already existing mod cvars. - * - * @param cvar Cvar name to find - * - * @return Cvar pointer on success, 0 if cvar was not found - */ -native get_cvar_pointer(const cvar[]); - -/** - * Returns flags of a cvar via direct pointer access. - * - * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc - * - * @param pcvar Pointer to cvar to retrieve flags from - * - * @return 1 on success, 0 if cvar pointer is invalid - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native get_pcvar_flags(pcvar); - -/** - * Sets specified flags to a cvar via direct pointer access. - * - * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc - * @note This function directly sets the provided bitflag, unlike set_cvar_flags - * which adds them using a bitwise OR. - * - * @param pcvar Pointer to cvar to set flags of - * @param flags Bitflag sum of flags to set - * - * @return 1 on success, 0 if cvar does not exist or is not permitted - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native set_pcvar_flags(pcvar, flags); - -/** - * Returns an integer value from a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to retrieve value from - * - * @return Cvar value, converted to int - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native get_pcvar_num(pcvar); - -/** - * Sets an integer value to a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to set value of - * @param num Value to set cvar to - * - * @noreturn - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native set_pcvar_num(pcvar, num); - -/** - * Returns a float value from a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to retrieve value from - * - * @return Cvar value, converted to float - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native Float:get_pcvar_float(pcvar); - -/** - * Sets a float value to a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to set value of - * @param num Value to set cvar to - * - * @noreturn - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native set_pcvar_float(pcvar, Float:num); - -/** - * Returns a string value from a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to retrieve value from - * @param string Buffer to copy cvar value to - * @param maxlen Maximum size of the buffer - * - * @return Number of cells written to buffer. - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native get_pcvar_string(pcvar, string[], maxlen); - -/** - * Sets a string value to a cvar via direct pointer access. - * - * @param pcvar Pointer to cvar to retrieve value from - * @param string Value to set cvar to - * - * @noreturn - * @error If an invalid cvar pointer is specified, an error is thrown. - */ -native set_pcvar_string(pcvar, const string[]); - /** * Sets all elements of array to a specified value. * diff --git a/plugins/include/cvars.inc b/plugins/include/cvars.inc index c5803aed..8a8fb83d 100644 --- a/plugins/include/cvars.inc +++ b/plugins/include/cvars.inc @@ -12,6 +12,58 @@ #endif #define _cvars_included +/** + * CVAR flags for register_cvar() + */ +#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 */ +#define FCVAR_EXTDLL 8 /* Defined by external DLL */ +#define FCVAR_CLIENTDLL 16 /* Defined by the client dll */ +#define FCVAR_PROTECTED 32 /* It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as value */ +#define FCVAR_SPONLY 64 /* This cvar cannot be changed by clients connected to a multiplayer server. */ +#define FCVAR_PRINTABLEONLY 128 /* This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). */ +#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 */ + +/** + * Registers a new cvar for the engine. + * + * @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 + * set_pcvar_* set of functions. + * + * @param name Cvar name + * @param string Default cvar value + * @param flags Cvar flags + * @param fvalue Unused + * + * @return Unique cvar pointer + */ +native register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0); + +/** + * Returns if a cvar is registered on the server. + * + * @param cvar Cvar name to check + * + * @return 1 if the cvar exists, 0 otherwise + */ +native cvar_exists(const cvar[]); + +/** + * Returns the cvar pointer of the specified cvar. + * + * @note A pointer is also returned by register_cvar(). Plugins can (and should) + * retrieve and use pointers for already existing mod cvars. + * + * @param cvar Cvar name to find + * + * @return Cvar pointer on success, 0 if cvar was not found + */ +native get_cvar_pointer(const cvar[]); + /** * Creates a hook for when a console variable's value is changed. * @@ -49,4 +101,292 @@ native disable_cvar_hook(cvarhook:handle); */ native enable_cvar_hook(cvarhook:handle); +/** + * Returns flags of a cvar. The cvar is accessed by name. + * + * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the get_pcvar_flags function. + * + * @param cvar Cvar name to retrieve flags from + * + * @return 1 on success, 0 if cvar does not exist or is not permitted + */ +native get_cvar_flags(const cvar[]); +/** + * Sets specified flags to a cvar. The cvar is accessed by name. + * + * @note Not permitted for the "amx_version", "amxmodx_version", "fun_version" + * and "sv_cheats" cvars. + * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc + * @note This function just adds the flags using a bitwise-or operation. After + * it has run the flags may not exactly equal the specified bitflag sum. + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the set_pcvar_flags function. + * + * @param cvar Cvar name to remove flags from + * @param flags Bitflag sum of flags to set + * + * @return 1 on success, 0 if cvar does not exist or is not permitted + */ +native set_cvar_flags(const cvar[], flags); + +/** + * Removes specified flags from a cvar. The cvar is accessed by name. + * + * @note Not permitted for the "amx_version", "amxmodx_version", "fun_version" + * and "sv_cheats" cvars. + * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc + * @note This function removes the flags using a bitwise-and operation. + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the set_pcvar_flags function. + * + * + * @param cvar Cvar name to remove flags from + * @param flags Bitflag sum of flags to remove + * + * @return 1 on success, 0 if cvar does not exist or is not permitted + */ +native remove_cvar_flags(const cvar[], flags=-1); + +/** + * Gets a string value from a cvar. The cvar is accessed by name. + * + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the get_pcvar_string function. + * + * @param cvar Cvar name to retrieve value from + * @param output Buffer to copy cvar value to + * @param iLen Maximum size of the buffer + * + * @return Number of cells written to buffer. + */ +native get_cvar_string(const cvarname[], output[], iLen); + +/** + * Sets a cvar to a given string value. The cvar is accessed by name. + * + * @note Accessing a cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the set_pcvar_string function. + * + * @param cvar Cvar name to set value of + * @param value Value to set cvar to + * + * @noreturn + */ +native set_cvar_string(const cvar[], const value[]); + +/** + * Returns a floating value from a cvar. The cvar is accessed by name. + * + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the get_pcvar_float function. + * + * @param cvarname Cvar name to retrieve value from + * + * @return Cvar value, converted to float + */ +native Float:get_cvar_float(const cvarname[]); + +/** + * Sets a cvar to a given float value. The cvar is accessed by name. + * + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the set_pcvar_float function. + * + * @param cvar Cvar name to set value of + * @param value Value to set cvar to + * + * @noreturn + */ +native set_cvar_float(const cvar[], Float:value); + +/** + * Returns an integer value from a cvar. The cvar is accessed by name. + * + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the get_pcvar_num function. + * + * @param cvarname Cvar name to retrieve value from + * + * @return Cvar value, converted to int + */ +native get_cvar_num(const cvarname[]); + +/** + * Sets a cvar to a given integer value. The cvar is accessed by name. + * + * @note Accessing a Cvar by name requires this function to walk through the + * engine's cvar list every time, which can result in a considerable waste + * of processing time, especially if many cvars have been registered. For + * a vastly superior alternative look at the set_pcvar_num function. + * + * @param cvar Cvar name to set value of + * @param value Value to set cvar to + * + * @noreturn + */ +native set_cvar_num(const cvarname[], value); + +/** + * Returns flags of a cvar via direct pointer access. + * + * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc + * + * @param pcvar Pointer to cvar to retrieve flags from + * + * @return 1 on success, 0 if cvar pointer is invalid + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native get_pcvar_flags(pcvar); + +/** + * Sets specified flags to a cvar via direct pointer access. + * + * @note For a list of possible flags see the FCVAR_* constants in amxconst.inc + * @note This function directly sets the provided bitflag, unlike set_cvar_flags + * which adds them using a bitwise OR. + * + * @param pcvar Pointer to cvar to set flags of + * @param flags Bitflag sum of flags to set + * + * @return 1 on success, 0 if cvar does not exist or is not permitted + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native set_pcvar_flags(pcvar, flags); + +/** + * Returns an integer value from a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to retrieve value from + * + * @return Cvar value, converted to int + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native get_pcvar_num(pcvar); + +/** + * Sets an integer value to a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to set value of + * @param num Value to set cvar to + * + * @noreturn + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native set_pcvar_num(pcvar, num); + +/** + * Returns a float value from a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to retrieve value from + * + * @return Cvar value, converted to float + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native Float:get_pcvar_float(pcvar); + +/** + * Sets a float value to a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to set value of + * @param num Value to set cvar to + * + * @noreturn + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native set_pcvar_float(pcvar, Float:num); + +/** + * Returns a string value from a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to retrieve value from + * @param string Buffer to copy cvar value to + * @param maxlen Maximum size of the buffer + * + * @return Number of cells written to buffer. + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native get_pcvar_string(pcvar, string[], maxlen); + +/** + * Sets a string value to a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to retrieve value from + * @param string Value to set cvar to + * + * @noreturn + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native set_pcvar_string(pcvar, const string[]); + +/** + * Returns the number of plugin-registered cvars. + * + * @return Number of registered cvars + */ +native get_plugins_cvarsnum(); + +/** + * Retrieves information about a plugin-registered cvar. + * + * @note The returned cvar pointer should be used with the get_pcvar_* and + * set_pcvar_* set of functions. + * + * @param num Cvar index, this does not equal the cvar pointer, it is + * the internal index, incremented for each registered cvar + * @param name Buffer to copy cvar name to + * @param namelen Maximum buffer size + * @param flags Variable to store cvar flags to + * @param plugin_id Variable to store id of the registering plugin to + * @param pcvar_handle Variable to store cvar pointer to + * + * @return 1 on success, 0 if index is invalid + */ +native get_plugins_cvar(num, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0); + +/** + * Dispatches a client cvar query, allowing the plugin to query for its value on + * the client. + * + * @note The callback will be called in the following manner: + * + * public cvar_query_callback(id, const cvar[], const value[], const param[]) + * + * id - Client index + * cvar - Cvar queried + * value - Cvar value on the client + * param - Extra data [optional] + * + * @param id Client index + * @param cvar Cvar to query + * @param resultFunc Callback function + * @param paramlen Size of extra data + * @param params Extra data to pass through to callback + * + * @noreturn + * @error If the client index is not within the range of 1 to + * MaxClients or the client is not connected, an error + * will be thrown. + * If the callback function is invalid, cvar querying is + * unavailable or the querying process runs out of memory, + * an error will be thrown. + */ +native query_client_cvar(id, const cvar[], const resultFunc[], paramlen=0, const params[]=""); \ No newline at end of file