diff --git a/amxmodx/AMBuilder b/amxmodx/AMBuilder index 1665ec89..a6b7c61a 100644 --- a/amxmodx/AMBuilder +++ b/amxmodx/AMBuilder @@ -96,6 +96,10 @@ binary.sources = [ 'stackstructs.cpp', 'CTextParsers.cpp', 'textparse.cpp', + 'CvarManager.cpp', + 'cvars.cpp', + '../public/memtools/CDetour/detours.cpp', + '../public/memtools/CDetour/asm/asm.c', ] if builder.target_platform == 'windows': diff --git a/amxmodx/CMisc.h b/amxmodx/CMisc.h index 851ccc36..276b4714 100755 --- a/amxmodx/CMisc.h +++ b/amxmodx/CMisc.h @@ -13,32 +13,6 @@ #include "CList.h" #include "sh_list.h" -// ***************************************************** -// class CCVar -// ***************************************************** - -class CCVar -{ - cvar_t cvar; - String name; - String plugin; - -public: - CCVar(const char* pname, const char* pplugin, int pflags, float pvalue) : name(pname), plugin(pplugin) - { - cvar.name = (char*)name.c_str(); - cvar.flags = pflags; - cvar.string = ""; - cvar.value = pvalue; - } - - inline cvar_t* getCvar() { return &cvar; } - inline const char* getPluginName() { return plugin.c_str(); } - inline const char* getName() { return name.c_str(); } - inline bool operator == (const char* string) { return (strcmp(name.c_str(), string) == 0); } - int plugin_id; -}; - // ***************************************************** // class CPlayer // ***************************************************** diff --git a/amxmodx/CvarManager.cpp b/amxmodx/CvarManager.cpp new file mode 100644 index 00000000..13cafa36 --- /dev/null +++ b/amxmodx/CvarManager.cpp @@ -0,0 +1,623 @@ +// 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 +#include + +CvarManager g_CvarManager; + +DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, 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 do. + { + DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value); + return; + } + + if (info->bound.hasMin || info->bound.hasMax) // cvar_s doesn't have min/max mechanism, so we check things here. + { + float fvalue = atof(value); + bool oob = false; + + if (info->bound.hasMin && fvalue < info->bound.minVal) + { + oob = true; + fvalue = info->bound.minVal; + } + else if (info->bound.hasMax && fvalue > info->bound.maxVal) + { + oob = true; + fvalue = info->bound.maxVal; + } + + if (oob) // Found value out of bound, set new value and block original call. + { + CVAR_SET_FLOAT(var->name, fvalue); + return; + } + } + + ke::AString oldValue; // We save old value since it will be likely changed after original function called. + + if (!info->hooks.empty()) + { + oldValue = var->string; + } + + DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value); + + if (!info->binds.empty()) + { + for (size_t i = 0; i < info->binds.length(); ++i) + { + CvarBind* bind = info->binds[i]; + + switch (bind->type) + { + case CvarBind::CvarType_Int: + { + *bind->varAddress = atoi(var->string); + break; + } + case CvarBind::CvarType_Float: + { + float fvalue = atof(var->string); + *bind->varAddress = amx_ftoc(fvalue); + break; + } + case CvarBind::CvarType_String: + { + set_amxstring_simple(bind->varAddress, var->string, bind->varLength); + break; + } + } + } + } + + if (!info->hooks.empty()) + { + for (size_t i = 0; i < info->hooks.length(); ++i) + { + CvarHook* hook = info->hooks[i]; + + if (hook->forward->state == AutoForward::FSTATE_OK) // Our callback can be enable/disabled by natives. + { + executeForwards(hook->forward->id, reinterpret_cast(var), oldValue.chars(), var->string); + } + } + } +} + +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) + { + // Disabled by default. + m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress); + } +} + +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; + 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(name, helpText, hasMin, min, hasMax, max, plugin, pluginId); + + 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); + } + 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 = false; + info->bound.minVal = 0; + info->bound.hasMax = false; + info->bound.maxVal = 0; + info->defaultval = value; + info->description = helpText; + info->pluginId = pluginId; + } + + // Detour is disabled on map change. + // Don't enable it unless there are things to do. + if (info->bound.hasMin || info->bound.hasMax) + { + m_HookDetour->EnableDetour(); + } + + return info; +} + +CvarInfo* 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; + } + + // Cvar doesn't exist. + if (!(var = CVAR_GET_POINTER(name))) + { + return nullptr; + } + + // Create a new entry. + info = new CvarInfo(name); + info->var = var; + + // Add entry in the caches. + m_Cvars.append(info); + m_Cache.insert(name, info); + + return info; +} + +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); +} + +AutoForward* 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(var->name); + info->var = var; + + // 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(); + + AutoForward* forward = new AutoForward(forwardId, *callback); + info->hooks.append(new CvarHook(g_plugins.findPlugin(amx)->getId(), forward)); + + 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, "Cvars can only be bound to global variables"); + 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 global variable can not be bound to multiple 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; +} + +AutoString convertFlagsToString(int flags) +{ + AutoString flagsName; + + if (flags > 0) + { + if (flags & FCVAR_ARCHIVE) flagsName = flagsName + "FCVAR_ARCHIVE "; + if (flags & FCVAR_USERINFO) flagsName = flagsName + "FCVAR_USERINFO "; + if (flags & FCVAR_SERVER) flagsName = flagsName + "FCVAR_SERVER "; + if (flags & FCVAR_EXTDLL) flagsName = flagsName + "FCVAR_EXTDLL "; + if (flags & FCVAR_CLIENTDLL) flagsName = flagsName + "FCVAR_CLIENTDLL "; + if (flags & FCVAR_PROTECTED) flagsName = flagsName + "FCVAR_PROTECTED "; + if (flags & FCVAR_SPONLY) flagsName = flagsName + "FCVAR_SPONLY "; + if (flags & FCVAR_PRINTABLEONLY) flagsName = flagsName + "FCVAR_PRINTABLEONLY "; + if (flags & FCVAR_UNLOGGED) flagsName = flagsName + "FCVAR_UNLOGGED "; + if (flags & FCVAR_NOEXTRAWHITEPACE) flagsName = flagsName + "FCVAR_NOEXTRAWHITEPACE "; + } + + if (!flagsName.length()) + { + flagsName = "-"; + } + + return flagsName; +} + +void CvarManager::OnConsoleCommand() +{ + size_t index = 0; + size_t indexToSearch = 0; + ke::AString partialName; + + int argcount = CMD_ARGC(); + + // amxx cvars [partial plugin name] [index from listing] + // E.g.: + // amxx cvars test <- list all cvars from plugin name starting by "test" + // amxx cvars 2 <- show informations about cvar in position 2 from "amxx cvars" list + // amxx cvars test 2 <- show informations about cvar in position 2 from "amxx cvars test" list + + if (argcount > 2) + { + const char* argument = CMD_ARGV(2); + + indexToSearch = atoi(argument); // amxx cvars 2 + + if (!indexToSearch) + { + partialName = argument; // amxx cvars test + + if (argcount > 3) // amxx cvars test 2 + { + indexToSearch = atoi(CMD_ARGV(3)); + } + } + } + + if (!indexToSearch) + { + print_srvconsole("\nManaged cvars:\n"); + print_srvconsole(" %-24.23s %-24.23s %-18.17s %-8.7s %-8.7s %-8.7s\n", "NAME", "VALUE", "PLUGIN", "BOUND", "HOOKED", "BOUNDED"); + print_srvconsole(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n"); + } + + for (CvarsList::iterator iter = m_Cvars.begin(); iter != m_Cvars.end(); iter++) + { + CvarInfo* ci = (*iter); + + // List any cvars having a status either created, hooked or bound by a plugin. + bool in_list = ci->amxmodx || !ci->binds.empty() || !ci->hooks.empty() || ci->bound.hasMin || ci->bound.hasMax; + + if (in_list && (!partialName.length() || strncmp(ci->plugin.chars(), partialName.chars(), partialName.length()) == 0)) + { + if (!indexToSearch) + { + print_srvconsole(" [%3d] %-24.23s %-24.23s %-18.17s %-8.7s %-8.7s %-8.7s\n", ++index, ci->name.chars(), ci->var->string, + ci->plugin.length() ? ci->plugin.chars() : "-", + ci->binds.empty() ? "no" : "yes", + ci->hooks.empty() ? "no" : "yes", + ci->bound.hasMin || ci->bound.hasMax ? "yes" : "no"); + } + else + { + if (++index != indexToSearch) + { + continue; + } + + print_srvconsole("\nCvar details :\n\n"); + print_srvconsole(" Cvar name : %s\n", ci->var->name); + print_srvconsole(" Value : %s\n", ci->var->string); + print_srvconsole(" Def. value : %s\n", ci->defaultval.chars()); + print_srvconsole(" Description : %s\n", ci->description.chars()); + print_srvconsole(" Flags : %s\n\n", convertFlagsToString(ci->var->flags).ptr()); + + print_srvconsole(" %-12s %-26.25s %s\n", "STATUS", "PLUGIN", "INFOS"); + print_srvconsole(" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n"); + + if (ci->amxmodx) + { + print_srvconsole(" Registered %-26.25s %s\n", ci->plugin.chars(), "-"); + } + + if (ci->bound.hasMin) + { + print_srvconsole(" Min value %-26.25s %f\n", g_plugins.findPlugin(ci->bound.minPluginId)->getName(), ci->bound.minVal); + } + + if (ci->bound.hasMax) + { + print_srvconsole(" Max value %-26.25s %f\n", g_plugins.findPlugin(ci->bound.maxPluginId)->getName(), ci->bound.maxVal); + } + + if (!ci->binds.empty()) + { + for (size_t i = 0; i < ci->binds.length(); ++i) + { + print_srvconsole(" Bound %-26.25s %s\n", g_plugins.findPlugin(ci->binds[i]->pluginId)->getName(), "-"); + } + } + + if (!ci->hooks.empty()) + { + for (size_t i = 0; i < ci->hooks.length(); ++i) + { + CvarHook* hook = ci->hooks[i]; + + print_srvconsole(" Hooked %-26.25s %s (%s)\n", g_plugins.findPlugin(hook->pluginId)->getName(), + hook->forward->callback.chars(), + hook->forward->state == AutoForward::FSTATE_OK ? "active" : "inactive"); + } + } + break; + } + } + } +} + +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)->binds.length(); ++i) + { + delete (*cvar)->binds[i]; + } + + for (size_t i = 0; i < (*cvar)->hooks.length(); ++i) + { + 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(); + } + + // 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)->binds.length(); ++i) + { + delete (*cvar)->binds[i]; + } + + 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/CvarManager.h b/amxmodx/CvarManager.h new file mode 100644 index 00000000..9c67f436 --- /dev/null +++ b/amxmodx/CvarManager.h @@ -0,0 +1,183 @@ +// 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 + +#ifndef CVARS_H +#define CVARS_H + +#include "amxmodx.h" +#include +#include +#include + +class CDetour; + +enum CvarBounds +{ + CvarBound_Upper = 0, + CvarBound_Lower +}; + +struct AutoForward +{ + enum fwdstate + { + FSTATE_INVALID = 0, + FSTATE_OK, + FSTATE_STOP, + }; + + AutoForward(int id_, const char* handler) : id(id_), state(FSTATE_OK), callback(handler) {}; + AutoForward() : id(-1) , state(FSTATE_INVALID) {}; + + ~AutoForward() + { + unregisterSPForward(id); + } + + int id; + fwdstate state; + ke::AString callback; +}; + +struct CvarHook +{ + CvarHook(int id, AutoForward* fwd) : pluginId(id), forward(fwd) {}; + CvarHook(int id) : pluginId(id), forward(new AutoForward()) {}; + + int pluginId; + ke::AutoPtr forward; +}; + +struct CvarBind +{ + enum CvarType + { + CvarType_Int, + CvarType_Float, + CvarType_String, + }; + + CvarBind(int id_, CvarType type_, cell* varAddress_, size_t varLength_) + : + pluginId(id_), + type(type_), + varAddress(varAddress_), + varLength(varLength_) {}; + + int pluginId; + CvarType type; + cell* varAddress; + size_t varLength; +}; + +struct CvarBound +{ + CvarBound(bool hasMin_, float minVal_, bool hasMax_, float maxVal_, int minPluginId_, int maxPluginId_) + : + hasMin(hasMin_), minVal(minVal_), + hasMax(hasMax_), maxVal(maxVal_), + minPluginId(minPluginId_), + maxPluginId(maxPluginId_) {}; + + CvarBound() + : + hasMin(false), minVal(0), + hasMax(false), maxVal(0) {}; + + bool hasMin; + float minVal; + bool hasMax; + float maxVal; + int minPluginId; + int maxPluginId; +}; + +typedef ke::Vector CvarsHook; +typedef ke::Vector CvarsBind; + +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), + plugin(plugin_), pluginId(pluginId_), + bound(hasMin_, min_, hasMax_, max_, pluginId_, pluginId_) {}; + + CvarInfo(const char* name_) + : + name(name_), defaultval(""), description(""), + plugin(""), pluginId(-1), bound(), amxmodx(false) {}; + + cvar_t* var; + ke::AString name; + ke::AString defaultval; + ke::AString description; + + ke::AString plugin; + int pluginId; + + CvarBound bound; + CvarsBind binds; + CvarsHook hooks; + + bool amxmodx; + + static inline bool matches(const char *name, const CvarInfo* info) + { + return strcmp(name, info->var->name) == 0; + } +}; + +typedef NameHashSet CvarsCache; +typedef ke::InlineList CvarsList; + +class CvarManager +{ + public: + + CvarManager(); + ~CvarManager(); + + public: + + void CreateCvarHook(); + + 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); + + CvarInfo* FindCvar(const char* name); + CvarInfo* FindCvar(size_t index); + 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(); + + void OnConsoleCommand(); + void OnPluginUnloaded(); + void OnAmxxShutdown(); + + private: + + CvarsCache m_Cache; + CvarsList m_Cvars; + size_t m_AmxmodxCvars; + CDetour* m_HookDetour; +}; + +extern CvarManager g_CvarManager; + +#endif // CVARS_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 7535a93d..63175d52 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) { @@ -1909,140 +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 ilen; - char* sptemp = get_amxstring(amx, params[1], 0, ilen); - - const char *value = CVAR_GET_STRING(sptemp); - return set_amxstring_utf8(amx, params[2], value, strlen(value), 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; - } - - REAL val = (REAL)ptr->value; - - return amx_ftoc(val); -} - -static cell AMX_NATIVE_CALL get_cvar_float(AMX *amx, cell *params) /* 1 param */ -{ - int ilen; - - REAL pFloat = CVAR_GET_FLOAT(get_amxstring(amx, params[1], 0, ilen)); - - return amx_ftoc(pFloat); -} - -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])); - (*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]); - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_float(AMX *amx, cell *params) /* 2 param */ -{ - int ilen; - CVAR_SET_FLOAT(get_amxstring(amx, params[1], 0, ilen), amx_ctof(params[2])); - - 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 ilen; - return (int)CVAR_GET_FLOAT(get_amxstring(amx, params[1], 0, ilen)); -} - -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]); - (*g_engfuncs.pfnCvar_DirectSet)(ptr, &CVarTempBuffer[0]); - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_num(AMX *amx, cell *params) /* 2 param */ -{ - int ilen; - CVAR_SET_FLOAT(get_amxstring(amx, params[1], 0, ilen), (float)params[2]); - - return 1; -} - -static cell AMX_NATIVE_CALL set_cvar_string(AMX *amx, cell *params) /* 2 param */ -{ - int ilen; - char* sptemp = get_amxstring(amx, params[1], 0, ilen); - char* szValue = get_amxstring(amx, params[2], 1, ilen); - - CVAR_SET_STRING(sptemp, szValue); - - 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; - - (*g_engfuncs.pfnCvar_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; @@ -2595,45 +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 (CVAR_GET_POINTER(get_amxstring(amx, params[1], 0, ilen)) ? 1 : 0); -} - -static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params) /* 3 param */ -{ - int i; - char* temp = get_amxstring(amx, params[1], 0, i); - CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); - - if (CheckBadConList(temp, 0)) - { - plugin->AddToFailCounter(1); - } - - if (!g_cvars.find(temp)) - { - CCVar* cvar = new CCVar(temp, plugin->getName(), params[3], amx_ctof(params[4])); - - cvar->plugin_id = plugin->getId(); - - g_cvars.put(cvar); - - if (CVAR_GET_POINTER(temp) == 0) - { - static cvar_t cvar_reg_helper; - cvar_reg_helper = *(cvar->getCvar()); - CVAR_REGISTER(&cvar_reg_helper); - } - - CVAR_SET_STRING(temp, get_amxstring(amx, params[2], 1, i)); - return reinterpret_cast(CVAR_GET_POINTER(temp)); - } - - return reinterpret_cast(CVAR_GET_POINTER(temp)); -} - static cell AMX_NATIVE_CALL get_user_ping(AMX *amx, cell *params) /* 3 param */ { int index = params[1]; @@ -3019,43 +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) -{ - int id = params[1]; - int iter_id = 0; - - for (CList::iterator iter=g_cvars.begin(); iter; ++iter) - { - if (id == iter_id) - { - CCVar *var = &(*iter); - set_amxstring(amx, params[2], var->getName(), params[3]); - cvar_t *ptr = CVAR_GET_POINTER(var->getName()); - if (!ptr) - { - return 0; - } - cell *addr = get_amxaddr(amx, params[4]); - *addr = ptr->flags; - addr = get_amxaddr(amx, params[5]); - *addr = var->plugin_id; - addr = get_amxaddr(amx, params[6]); - *addr = (cell)ptr; - return 1; - } - iter_id++; - } - - return 0; -} - -//native get_plugins_cvarsnum(); -static cell AMX_NATIVE_CALL get_plugins_cvarsnum(AMX *amx, cell *params) -{ - return g_cvars.size(); -} - static cell AMX_NATIVE_CALL get_user_aiming(AMX *amx, cell *params) /* 4 param */ { int index = params[1]; @@ -3099,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 = CVAR_GET_POINTER(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 = CVAR_GET_POINTER(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 = CVAR_GET_POINTER(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; @@ -4121,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]; @@ -4445,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 *temp = get_amxstring(amx, params[1], 0, len); - - cvar_t *ptr = CVAR_GET_POINTER(temp); - - return reinterpret_cast(ptr); -} - CVector g_hudsync; static cell AMX_NATIVE_CALL CreateHudSyncObj(AMX *amx, cell *params) @@ -4860,7 +4451,6 @@ 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}, {"engclient_cmd", engclient_cmd}, {"engclient_print", engclient_print}, @@ -4873,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}, @@ -4889,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}, @@ -4967,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}, @@ -4982,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}, @@ -4991,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 6b9973ca..2596a1ee 100755 --- a/amxmodx/amxmodx.h +++ b/amxmodx/amxmodx.h @@ -47,6 +47,7 @@ #include "CLang.h" #include "fakemeta.h" #include "amxxlog.h" +#include "CvarManager.h" #define AMXXLOG_Log g_log.Log #define AMXXLOG_Error g_log.LogError @@ -65,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) @@ -161,7 +163,6 @@ extern CTaskMngr g_tasksMngr; extern CPlayer g_players[33]; extern CPlayer* mPlayer; extern CmdMngr g_commands; -extern CList g_cvars; extern CList g_forcemodels; extern CList g_forcesounds; extern CList g_forcegeneric; @@ -281,6 +282,7 @@ int amxstring_len(cell* cstr); int load_amxscript(AMX* amx, void** program, const char* path, char error[64], int debug); int set_amxnatives(AMX* amx, char error[64]); int set_amxstring(AMX *amx, cell amx_addr, const char *source, int max); +int set_amxstring_simple(cell *dest, const char *source, int max); template int set_amxstring_utf8(AMX *amx, cell amx_addr, const T *source, size_t sourcelen, size_t maxlen); int set_amxstring_utf8_char(AMX *amx, cell amx_addr, const char *source, size_t sourcelen, size_t maxlen); int set_amxstring_utf8_cell(AMX *amx, cell amx_addr, const cell *source, size_t sourcelen, size_t maxlen); @@ -329,6 +331,7 @@ extern int FF_PluginEnd; extern int FF_InconsistentFile; extern int FF_ClientAuthorized; extern int FF_ChangeLevel; + extern bool g_coloredmenus; typedef void (*AUTHORIZEFUNC)(int player, const char *authstring); diff --git a/amxmodx/cvars.cpp b/amxmodx/cvars.cpp new file mode 100644 index 00000000..c3d43690 --- /dev/null +++ b/amxmodx/cvars.cpp @@ -0,0 +1,720 @@ +// 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 "nongpl_matches.h" + +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]; + + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + if (CheckBadConList(name, 0)) + { + plugin->AddToFailCounter(1); + } + + CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText); + + 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, "The minimum value can not be above the maximum value"); + return 0; + } + + if (!g_CvarManager.SetCvarMax(info, hasMax, maxVal, plugin->getId())) + { + LogError(amx, AMX_ERR_NATIVE, "The maximum value can not be below the minimum value"); + return 0; + } + + return reinterpret_cast(info->var); + } + + return 0; +} + +// register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0) +static cell AMX_NATIVE_CALL register_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); + + int flags = params[3]; + float fvalue = amx_ctof(params[4]); + + CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); + + if (CheckBadConList(name, 0)) + { + plugin->AddToFailCounter(1); + } + + CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags); + + if (info) + { + return reinterpret_cast(info->var); + } + + return 0; +} + +// 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; + const char *name = get_amxstring(amx, params[1], 0, len); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + return reinterpret_cast(info ? info->var : 0); +} + +// 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; + AutoForward* forward = g_CvarManager.HookCvarChange(var, amx, params[2], &callback); + + if (!forward) + { + LogError(amx, AMX_ERR_NATIVE, "Function \"%s\" is not present", callback); + return 0; + } + + return reinterpret_cast(forward); +} + +// enable_cvar_hook(cvarhook:handle); +static cell AMX_NATIVE_CALL enable_cvar_hook(AMX *amx, cell *params) +{ + AutoForward* forward = reinterpret_cast(params[1]); + + if (!forward) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); + return 0; + } + + forward->state = AutoForward::FSTATE_OK; + + return 1; +} + +// disable_cvar_hook(cvarhook:handle); +static cell AMX_NATIVE_CALL disable_cvar_hook(AMX *amx, cell *params) +{ + AutoForward* forward = reinterpret_cast(params[1]); + + if (!forward) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid cvar hook handle: %p", forward); + return 0; + } + + forward->state = AutoForward::FSTATE_STOP; + + return 1; +} + +// get_cvar_flags(const cvar[]) +static cell AMX_NATIVE_CALL get_cvar_flags(AMX *amx, cell *params) +{ + int ilen; + char* sCvar = get_amxstring(amx, params[1], 0, ilen); + + CvarInfo* info = g_CvarManager.FindCvar(sCvar); + + return info ? info->var->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); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + return info ? amx_ftoc(info->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); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + return info ? (int)info->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); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + const char *value = info ? info->var->string : ""; + length = info ? 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; + const 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; + + CvarInfo* info = g_CvarManager.FindCvar(sCvar); + + if (info) + { + info->var->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); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + if (info) + { + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%f", amx_ctof(params[2])); + CVAR_DIRECTSET(info->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]; + + CvarInfo* info = g_CvarManager.FindCvar(name); + + if (info) + { + UTIL_Format(CVarTempBuffer, sizeof(CVarTempBuffer) - 1, "%d", value); + CVAR_DIRECTSET(info->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); + + CvarInfo* info = g_CvarManager.FindCvar(name); + + if (info) + { + CVAR_DIRECTSET(info->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; +} + +// bool:get_pcvar_bool(pcvar) +static cell AMX_NATIVE_CALL get_pcvar_bool(AMX *amx, cell *params) +{ + return !!get_pcvar_num(amx, params); +} + +// 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 +} + +// get_pcvar_bounds(pcvar, CvarBounds:type, &Float:value) +static cell AMX_NATIVE_CALL get_pcvar_bounds(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + CvarInfo* info = nullptr; + + if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name))) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + bool hasBound = false; + float bound; + + switch (params[2]) + { + case CvarBound_Lower: + hasBound = info->bound.hasMin; + bound = info->bound.minVal; + break; + case CvarBound_Upper: + hasBound = info->bound.hasMax; + bound = info->bound.maxVal; + break; + default: + LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]); + return 0; + } + + *get_amxaddr(amx, params[3]) = amx_ftoc(bound); + + return hasBound; +} + +// bind_pcvar_float(pcvar, &Float:var) +static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + CvarInfo* info = nullptr; + + if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name))) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return g_CvarManager.BindCvar(info, CvarBind::CvarType_Float, amx, params[2]); +} + +// bind_pcvar_num(pcvar, &any:var) +static cell AMX_NATIVE_CALL bind_pcvar_num(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + CvarInfo* info = nullptr; + + if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name))) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return g_CvarManager.BindCvar(info, CvarBind::CvarType_Int, amx, params[2]); +} + +// bind_pcvar_string(pcvar, any:var[], varlen) +static cell AMX_NATIVE_CALL bind_pcvar_string(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + CvarInfo* info = nullptr; + + if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name))) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + return g_CvarManager.BindCvar(info, CvarBind::CvarType_String, amx, params[2], params[3]); +} + +// 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; +} + +// set_pcvar_bounds(pcvar, CvarBounds:type, bool:set, Float:value = 0.0) +static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params) +{ + cvar_t *ptr = reinterpret_cast(params[1]); + CvarInfo* info = nullptr; + + if (!ptr || !(info = g_CvarManager.FindCvar(ptr->name))) + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CVAR pointer"); + return 0; + } + + bool set = params[3] != 0; + int pluginId = g_plugins.findPluginFast(amx)->getId(); + float value = amx_ctof(params[4]); + + switch (params[2]) + { + case CvarBound_Lower: + { + if (!g_CvarManager.SetCvarMin(info, set, value, pluginId)) + { + LogError(amx, AMX_ERR_NATIVE, "The minimum value can not be above the maximum value"); + return 0; + } + break; + } + case CvarBound_Upper: + { + if (!g_CvarManager.SetCvarMax(info, set, value, pluginId)) + { + LogError(amx, AMX_ERR_NATIVE, "The maximum value can not be below the minimum value"); + return 0; + } + break; + } + default: + { + LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]); + return 0; + } + } + + 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; + + CvarInfo* info = g_CvarManager.FindCvar(sCvar); + + if (info) + { + info->var->flags &= ~((int)(params[2])); + return 1; + } + + return 0; +} + +// get_plugins_cvar(id, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0, description[]="", desc_len=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); + + if (*params / sizeof(cell) >= 7) + { + set_amxstring(amx, params[7], info->description.chars(), params[8]); + } + + 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 + + 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; +} + +AMX_NATIVE_INFO g_CvarNatives[] = +{ + {"create_cvar", create_cvar}, + {"register_cvar", register_cvar}, + {"cvar_exists", cvar_exists}, + {"get_cvar_pointer", get_cvar_pointer}, + + {"hook_cvar_change", hook_cvar_change}, + {"enable_cvar_hook", enable_cvar_hook}, + {"disable_cvar_hook", disable_cvar_hook}, + + {"get_cvar_flags", get_cvar_flags}, + {"get_cvar_float", get_cvar_float}, + {"get_cvar_num", get_cvar_num}, + {"get_cvar_string", get_cvar_string}, + + {"set_cvar_flags", set_cvar_flags}, + {"set_cvar_float", set_cvar_float}, + {"set_cvar_num", set_cvar_num}, + {"set_cvar_string", set_cvar_string}, + + {"get_pcvar_flags", get_pcvar_flags}, + {"get_pcvar_float", get_pcvar_float}, + {"get_pcvar_num", get_pcvar_num}, + {"get_pcvar_bool", get_pcvar_bool}, + {"get_pcvar_string", get_pcvar_string}, + {"get_pcvar_bounds", get_pcvar_bounds}, + + {"set_pcvar_flags", set_pcvar_flags}, + {"set_pcvar_float", set_pcvar_float}, + {"set_pcvar_num", set_pcvar_num}, + {"set_pcvar_bool", set_pcvar_num}, + {"set_pcvar_string", set_pcvar_string}, + {"set_pcvar_bounds", set_pcvar_bounds}, + + {"remove_cvar_flags", remove_cvar_flags}, + + {"bind_pcvar_float", bind_pcvar_float}, + {"bind_pcvar_num", bind_pcvar_num}, + {"bind_pcvar_string", bind_pcvar_string}, + + {"get_plugins_cvar", get_plugins_cvar}, + {"get_plugins_cvarsnum", get_plugins_cvarsnum}, + + {"query_client_cvar", query_client_cvar}, + + {NULL, NULL} +}; \ No newline at end of file diff --git a/amxmodx/meta_api.cpp b/amxmodx/meta_api.cpp index 2fe486fa..41507cbb 100755 --- a/amxmodx/meta_api.cpp +++ b/amxmodx/meta_api.cpp @@ -31,6 +31,7 @@ #include "trie_natives.h" #include "CDataPack.h" #include "textparse.h" +#include "CvarManager.h" plugin_info_t Plugin_info = { @@ -63,7 +64,6 @@ extern CVector DynamicAdmins; CLog g_log; CForwardMngr g_forwards; CList g_auth; -CList g_cvars; CList g_forcemodels; CList g_forcesounds; CList g_forcegeneric; @@ -121,7 +121,7 @@ cvar_t init_amxmodx_modules = {"amxmodx_modules", "", FCVAR_SPONLY}; cvar_t init_amxmodx_debug = {"amx_debug", "1", FCVAR_SPONLY}; cvar_t init_amxmodx_mldebug = {"amx_mldebug", "", FCVAR_SPONLY}; cvar_t init_amxmodx_language = {"amx_language", "en", FCVAR_SERVER}; -cvar_t init_amxmodx_cl_langs = {"amx_client_languages", "", FCVAR_SERVER}; +cvar_t init_amxmodx_cl_langs = {"amx_client_languages", "1", FCVAR_SERVER}; cvar_t* amxmodx_version = NULL; cvar_t* amxmodx_modules = NULL; cvar_t* amxmodx_language = NULL; @@ -697,6 +697,9 @@ void C_ServerDeactivate_Post() g_vault.clear(); g_xvars.clear(); g_plugins.clear(); + + g_CvarManager.OnPluginUnloaded(); + ClearPluginLibraries(); modules_callPluginsUnloaded(); @@ -1488,6 +1491,8 @@ C_DLLEXPORT int Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m GET_HOOK_TABLES(PLID, &g_pEngTable, NULL, NULL); FlagMan.SetFile("cmdaccess.ini"); + + g_CvarManager.CreateCvarHook(); return (TRUE); } @@ -1517,7 +1522,6 @@ C_DLLEXPORT int Meta_Detach(PLUG_LOADTIME now, PL_UNLOAD_REASON reason) g_vault.clear(); g_xvars.clear(); g_plugins.clear(); - g_cvars.clear(); g_langMngr.Clear(); ClearMessages(); 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 80d6961c..1cc3ed54 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj @@ -96,7 +96,7 @@ Disabled - ..\;..\..\public;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) + ..\;..\..\public;..\..\public\memtools;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebug @@ -149,7 +149,7 @@ true Speed true - ..\;..\..\public;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) + ..\;..\..\public;..\..\public\memtools;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;JIT;ASM32;PAWN_CELL_SIZE=32;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions) false true @@ -200,7 +200,7 @@ Disabled - ..\;..\..\public;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) + ..\;..\..\public;..\..\public\memtools;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT;BINLOG_ENABLED;_CRT_SECURE_NO_DEPRECATE;HAVE_STDINT_H;%(PreprocessorDefinitions) EnableFastChecks MultiThreaded @@ -252,7 +252,7 @@ true Speed true - ..\;..\..\public;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) + ..\;..\..\public;..\..\public\memtools;..\..\public\sdk;..\..\public\amtl;$(METAMOD)\metamod;$(HLSDK)\common;$(HLSDK)\engine;$(HLSDK)\dlls;$(HLSDK)\pm_shared;$(HLSDK)\public;%(AdditionalIncludeDirectories) WIN32;NDEBUG;_WINDOWS;HAVE_STDINT_H;_USRDLL;amxmodx_EXPORTS;JIT;ASM32;PAWN_CELL_SIZE=32;BINLOG_ENABLED;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) false true @@ -292,6 +292,8 @@ + + @@ -317,6 +319,8 @@ + + @@ -360,6 +364,9 @@ + + + @@ -383,6 +390,7 @@ + @@ -414,6 +422,7 @@ + diff --git a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters index db6aeada..6c60ac4a 100644 --- a/amxmodx/msvc12/amxmodx_mm.vcxproj.filters +++ b/amxmodx/msvc12/amxmodx_mm.vcxproj.filters @@ -25,6 +25,15 @@ {4022451d-eb5f-4f14-b8d8-2ce23fec6e59} + + {a1f7babf-acb1-4a06-92e9-e8a411e1f02a} + + + {8b35d490-2b01-4997-ba02-5e2cfd9c9017} + + + {64a22cd4-3715-45de-8af2-e54017733be6} + @@ -183,6 +192,18 @@ SDK + + Memtools\CDetour + + + Memtools\CDetour\asm + + + Source Files + + + Source Files + @@ -329,6 +350,18 @@ SDK + + Memtools\CDetour + + + Memtools\CDetour + + + Memtools\CDetour\asm + + + Header Files + @@ -423,6 +456,9 @@ Pawn Includes + + Pawn Includes + 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/amxmodx/srvcmd.cpp b/amxmodx/srvcmd.cpp index 91e264ef..6c6d5211 100755 --- a/amxmodx/srvcmd.cpp +++ b/amxmodx/srvcmd.cpp @@ -13,10 +13,9 @@ void amx_command() { const char* cmd = CMD_ARGV(1); - + if (!strcmp(cmd, "plugins") || !strcmp(cmd, "list")) { - print_srvconsole("Currently loaded plugins:\n"); print_srvconsole(" %-23.22s %-11.10s %-17.16s %-16.15s %-9.8s\n", "name", "version", "author", "file", "status"); @@ -24,11 +23,11 @@ void amx_command() int running = 0; CPluginMngr::iterator a = g_plugins.begin(); - - while (a) + + while (a) { ++plugins; - if ((*a).isValid() && !(*a).isPaused()) + if ((*a).isValid() && !(*a).isPaused()) ++running; print_srvconsole(" [%3d] %-23.22s %-11.10s %-17.16s %-16.15s %-9.8s\n", plugins, (*a).getTitle(), (*a).getVersion(), (*a).getAuthor(), (*a).getName(), (*a).getStatus()); @@ -45,7 +44,8 @@ void amx_command() { //error print_srvconsole("(%3d) Load fails: %s\n", num, (*a).getError()); - } else if ( (*a).getStatusCode() == ps_error) { + } + else if ((*a).getStatusCode() == ps_error) { //error print_srvconsole("(%3d) Error: %s\n", num, (*a).getError()); } @@ -54,23 +54,23 @@ void amx_command() print_srvconsole("%d plugins, %d running\n", plugins, running); } - else if (!strcmp(cmd, "pause") && CMD_ARGC() > 2) + else if (!strcmp(cmd, "pause") && CMD_ARGC() > 2) { const char* sPlugin = CMD_ARGV(2); CPluginMngr::CPlugin *plugin = g_plugins.findPlugin(sPlugin); - if (plugin && plugin->isValid()) + if (plugin && plugin->isValid()) { if (plugin->isPaused()) { if (plugin->isStopped()) { - print_srvconsole("Plugin \"%s\" is stopped and may not be paused.\n",plugin->getName()); + print_srvconsole("Plugin \"%s\" is stopped and may not be paused.\n", plugin->getName()); } else { - print_srvconsole("Plugin \"%s\" is already paused.\n",plugin->getName()); + print_srvconsole("Plugin \"%s\" is already paused.\n", plugin->getName()); } } else @@ -79,18 +79,18 @@ void amx_command() print_srvconsole("Paused plugin \"%s\"\n", plugin->getName()); } } - else + else { print_srvconsole("Couldn't find plugin matching \"%s\"\n", sPlugin); } } - else if (!strcmp(cmd, "unpause") && CMD_ARGC() > 2) + else if (!strcmp(cmd, "unpause") && CMD_ARGC() > 2) { const char* sPlugin = CMD_ARGV(2); CPluginMngr::CPlugin *plugin = g_plugins.findPlugin(sPlugin); - if (plugin && plugin->isValid() && plugin->isPaused()) + if (plugin && plugin->isValid() && plugin->isPaused()) { if (plugin->isStopped()) { @@ -105,44 +105,20 @@ void amx_command() else if (!plugin) { print_srvconsole("Couldn't find plugin matching \"%s\"\n", sPlugin); - } else { + } + else { print_srvconsole("Plugin %s can't be unpaused right now.\n", sPlugin); } } - else if (!strcmp(cmd, "cvars")) + else if (!strcmp(cmd, "cvars")) { - print_srvconsole("Registered cvars:\n"); - print_srvconsole(" %-24.23s %-24.23s %-16.15s\n", "name", "value", "plugin"); - - int ammount = 0; - - if (CMD_ARGC() > 2) // Searching for cvars registered to a plugin - { - const char* targetname = CMD_ARGV(2); - size_t len = strlen(targetname); - for (CList::iterator a = g_cvars.begin(); a; ++a) - { - if (strncmp((*a).getPluginName(), targetname, len) == 0) - { - print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++ammount, (*a).getName(), CVAR_GET_STRING((*a).getName()), (*a).getPluginName()); - } - } - } - else // No search - { - for (CList::iterator a = g_cvars.begin(); a; ++a) - { - print_srvconsole(" [%3d] %-24.23s %-24.23s %-16.15s\n", ++ammount, (*a).getName(), CVAR_GET_STRING((*a).getName()), (*a).getPluginName()); - } - } - - print_srvconsole("%d cvars\n", ammount); + g_CvarManager.OnConsoleCommand(); } - else if (!strcmp(cmd, "cmds")) + else if (!strcmp(cmd, "cmds")) { print_srvconsole("Registered commands:\n"); print_srvconsole(" %-24.23s %-16.15s %-8.7s %-16.15s\n", "name", "access", "type", "plugin"); - + int ammount = 0; char access[32]; @@ -171,9 +147,9 @@ void amx_command() ++a; } } - print_srvconsole("%d commands\n",ammount); + print_srvconsole("%d commands\n", ammount); } - else if (!strcmp(cmd, "version")) + else if (!strcmp(cmd, "version")) { print_srvconsole("%s %s (%s)\n", Plugin_info.name, Plugin_info.version, Plugin_info.url); print_srvconsole("Authors:\n\tDavid \"BAILOPAN\" Anderson, Pavol \"PM OnoTo\" Marko\n"); @@ -203,7 +179,7 @@ void amx_command() int running = 0; int modules = 0; - CList::iterator a = g_modules.begin(); + CList::iterator a = g_modules.begin(); while (a) { @@ -254,32 +230,34 @@ void amx_command() print_srvconsole("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3A\x78\x78\x24\x40\x4E\x4E\x4D\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x5E\x3E\x3E\x3F\x3E\x3E\x3E\x3E\x3B\x3B\x3B\x3A\x3A\x3F\x3E\x3A\x2E\x2E\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2E\x45\x4D\x40\x45\x78\x5E\x33\x68\x33\x2B\n"); print_srvconsole("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x24\x48\x45\x48\x78\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2B\x4E\x40\x2B\x66\x33\x78\x20\x20\n"); print_srvconsole("\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x2B\x2C\x20\x3A\x20\x20\n"); - } else { + } + else + { print_srvconsole("Usage: amxx < command > [ argument ]\n"); print_srvconsole("Commands:\n"); - print_srvconsole(" version - display amxx version info\n"); - print_srvconsole(" gpl - print the license\n"); - print_srvconsole(" plugins - list plugins currently loaded\n"); - print_srvconsole(" modules - list modules currently loaded\n"); - print_srvconsole(" cvars [ plugin ] - list cvars registered by plugins\n"); - print_srvconsole(" cmds [ plugin ] - list commands registered by plugins\n"); - print_srvconsole(" pause < plugin > - pause a running plugin\n"); - print_srvconsole(" unpause < plugin > - unpause a previously paused plugin\n"); + print_srvconsole(" version - display amxx version info\n"); + print_srvconsole(" gpl - print the license\n"); + print_srvconsole(" plugins - list plugins currently loaded\n"); + print_srvconsole(" modules - list modules currently loaded\n"); + print_srvconsole(" cvars [ plugin ] [ index ] - list cvars handled by amxx or show information about a cvar if index is provided\n"); + print_srvconsole(" cmds [ plugin ] - list commands registered by plugins\n"); + print_srvconsole(" pause < plugin > - pause a running plugin\n"); + print_srvconsole(" unpause < plugin > - unpause a previously paused plugin\n"); } } void plugin_srvcmd() { const char* cmd = CMD_ARGV(0); - + CmdMngr::iterator a = g_commands.srvcmdbegin(); - + while (a) { if ((*a).matchCommand(cmd) && (*a).getPlugin()->isExecutable((*a).getFunction())) { cell ret = executeForwards((*a).getFunction(), static_cast(g_srvindex), - static_cast((*a).getFlags()), static_cast((*a).getId())); + static_cast((*a).getFlags()), static_cast((*a).getId())); if (ret) break; } ++a; diff --git a/amxmodx/string.cpp b/amxmodx/string.cpp index 877d54cb..e9ca20f7 100755 --- a/amxmodx/string.cpp +++ b/amxmodx/string.cpp @@ -65,6 +65,20 @@ cell* get_amxaddr(AMX *amx, cell amx_addr) return (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); } +int set_amxstring_simple(cell *dest, const char *source, int max) +{ + cell* start = dest; + + while (max-- && *source) + { + *dest++ = (unsigned char)*source++; + } + + *dest = 0; + + return dest - start; +} + int set_amxstring(AMX *amx, cell amx_addr, const char *source, int max) { register cell* dest = (cell *)(amx->base + (int)(((AMX_HEADER *)amx->base)->dat + amx_addr)); 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 7fe66ee7..d09d0edb 100755 --- a/plugins/include/amxmodx.inc +++ b/plugins/include/amxmodx.inc @@ -29,6 +29,7 @@ #include #include #include +#include /** * Called just after server activation. @@ -1403,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. * @@ -1963,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. * @@ -2057,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. * @@ -2805,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. * @@ -3219,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 new file mode 100644 index 00000000..bc256fb4 --- /dev/null +++ b/plugins/include/cvars.inc @@ -0,0 +1,524 @@ +// 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 + +#if defined _cvars_included + #endinput +#endif +#define _cvars_included + +/** + * CVAR flags for create_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 */ +#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 */ + +/** + * Creates a new cvar for the engine. + * + * @note This has the same effect as register_cvar but provides 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 bitsum of flags specifying cvar behavior + * @param description Optional description of the cvar + * @param has_min Optional boolean that specifies if the cvar has a minimum value + * @param min_val Minimum floating point value + * @param has_max Optional boolean that specifies if the cvar has a maximum value + * @param max_val Maximum floating point value + * + * @return Unique cvar pointer + */ +native create_cvar(const name[], const string[], flags = FCVAR_NONE, const description[] = "", 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 + * set_pcvar_* set of functions. + * + * @param name Cvar name + * @param string Default cvar value + * @param flags Optional bitsum of flags specifying cvar behavior + * @param fvalue Unused + * + * @return Unique cvar pointer + */ +native register_cvar(const name[], const string[], flags = FCVAR_NONE, 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 cvar's value is changed. + * + * @note Changing the cvar value from within this forward can lead to infinite + * recursion and should be avoided. + * @note Callback will be called in the following manner: + * + * public cvar_change_callback(pcvar, const old_value[], const new_value[]) + * + * pcvar - Pointer to cvar that was changed + * old_value - String containing the value of the cvar before it was changed + * new_value - String containing the new value of the cvar + * + * The return value is ignored + * + * @param pcvar Pointer to cvar + * @param callback Name of callback function + * + * @return Callback handle that can be used with [disable|enable]_cvar_hook + * @error Invalid cvar pointer or invalid callback function + */ +native cvarhook:hook_cvar_change(pcvar, const callback[]); + +/** + * Stops a cvar hook forward from triggering. + * + * @note Use the handle returned by hook_cvar_change as the parameter here. + * + * @param handle Forward to stop + * @error Invalid hook handle + */ +native disable_cvar_hook(cvarhook:handle); + +/** + * Starts a cvar hook forward back up. + * + * @note Use the handle returned by hook_cvar_change as the parameter here. + * + * @param handle Forward to back up + * @error Invalid hook 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); + +/** + * Returns an boolean value from a cvar via direct pointer access. + * + * @param pcvar Pointer to cvar to retrieve value from + * + * @return Cvar value, converted to bool + * @error If an invalid cvar pointer is specified, an error is thrown. + */ +native bool:get_pcvar_bool(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); + +/** + * Sets a boolean 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_bool(pcvar, bool: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[]); + +/** + * Cvar bound values used with get/set_pcvar_bounds() + */ +enum CvarBounds +{ + CvarBound_Upper = 0, + CvarBound_Lower +}; + +/** + * Retrieves the specified value bounds of a cvar. + * + * @param pcvar Pointer to cvar + * @param type Type of bound to retrieve, CvarBound_Lower or CvarBound_Upper + * @param value Variable to store the specified bound to + * + * @return True if the cvar has the specified bound set, false otherwise. + * @error If an invalid cvar pointer or CvarBounds value, an error is thrown. + */ +native bool:get_pcvar_bounds(pcvar, CvarBounds:type, &Float:value); + +/** + * Sets the specified bounds of a cvar. + * + * @param pcvar Pointer to cvar + * @param type Type of bound to set, CvarBound_Lower or CvarBound_Upper + * @param set If set to true, cvar will use specified bound. If false, bound will be removed + * @param value Floating point value to use as the specified bound + * + * @error If an invalid cvar pointer or CvarBounds value, an error is thrown. + */ +native set_pcvar_bounds(pcvar, CvarBounds:type, bool:set, Float:value = 0.0); + +/** + * Binds a cvar's integer value to a global variable. The variable will then + * always contain the current cvar value as it is automatically kept up to date. + * + * @note The variable *has* to be a global or a static variable. Local variables + * created within functions can not be used for technical reasons. + * @note Variables can not be bound to multiple cvars. + * + * @param pcvar Pointer to cvar + * @param var Global variable to keep updated + * + * @error Invalid cvar pointer, invalid provided variable or cvar/variable already binded. + */ +native bind_pcvar_num(pcvar, &any:var); + +/** + * Binds a cvar's float value to a global variable. The variable will then + * always contain the current cvar value as it is automatically kept up to date. + * + * @note The variable *has* to be a global or a static variable. Local variables + * created within functions can not be used for technical reasons. + * @note Variables can not be bound to multiple cvars. + * + * @param pcvar Pointer to cvar + * @param var Global variable to keep updated + * + * @error Invalid cvar pointer, invalid provided variable or cvar/variable already binded. + */ +native bind_pcvar_float(pcvar, &Float:var); + +/** + * Binds a cvar's string value to a global array. The array will then + * always contain the current cvar value as it is automatically kept up to date. + * + * @note The array *has* to be a global or a static array. Local arrays + * created within functions can not be used for technical reasons. + * @note Arrays can not be bound to multiple cvars. + * + * @param pcvar Pointer to cvar + * @param var Global array to keep updated + * @param varlen Maximum length of string array + * + * @error Invalid cvar pointer, invalid provided variable or cvar/variable already binded. + */ +native bind_pcvar_string(pcvar, any:var[], varlen); + +/** + * 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 + * @param description Variable to store cvar description to + * @param desc_len Maximum length of string buffer + * + * @return 1 on success, 0 if index is invalid + */ +native get_plugins_cvar(num, name[], namelen, &flags=0, &plugin_id=0, &pcvar_handle=0, description[]="", desc_len=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[]=""); diff --git a/plugins/multilingual.sma b/plugins/multilingual.sma index 28dbc721..6c41a2fe 100755 --- a/plugins/multilingual.sma +++ b/plugins/multilingual.sma @@ -28,9 +28,9 @@ public plugin_init() register_dictionary("multilingual.txt") register_dictionary("common.txt") register_dictionary("languages.txt") - - g_cvarClientLanguages = register_cvar("amx_client_languages", "1") + g_cvarDisplayClientMessage = register_cvar("amx_language_display_msg", "1") + g_cvarClientLanguages = get_cvar_pointer("amx_client_languages") g_cvarServerLanguage = get_cvar_pointer("amx_language"); register_clcmd("amx_langmenu", "cmdLangMenu", ADMIN_ALL) diff --git a/public/auto-string.h b/public/auto-string.h new file mode 100644 index 00000000..75e4f8f0 --- /dev/null +++ b/public/auto-string.h @@ -0,0 +1,153 @@ +/* vim: set ts=2 sw=2 tw=99 et: + * + * Copyright (C) 2012 David Anderson + * + * This file is part of SourcePawn. + * + * SourcePawn is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * SourcePawn. If not, see http://www.gnu.org/licenses/. + */ +#ifndef _include_auto_string_h_ +#define _include_auto_string_h_ + +#include +#include +#include +#include + +using namespace ke; + +class AutoString +{ + public: + AutoString() : ptr_(NULL), length_(0) + { + } + AutoString(AutoString &&other) + : ptr_(other.ptr_), + length_(other.length_) + { + other.ptr_ = nullptr; + other.length_ = 0; + } + AutoString(const char *ptr) + { + assign(ptr); + } + AutoString(const AString &str) + { + assign(str.chars(), str.length()); + } + AutoString(const char *ptr, size_t len) + { + assign(ptr, len); + } + AutoString(const AutoString &other) + { + assign(other.ptr(), other.length()); + } + ~AutoString() + { + free(ptr_); + } + + AutoString &operator =(const char *ptr) { + free(ptr_); + assign(ptr); + return *this; + } + AutoString &operator =(const AutoString &other) { + free(ptr_); + assign(other.ptr(), other.length()); + return *this; + } + AutoString &operator =(AutoString &&other) { + Swap(other.ptr_, ptr_); + Swap(other.length_, length_); + return *this; + } + + AutoString operator +(const AutoString &other) const { + size_t len = length() + other.length(); + char *buf = (char *)malloc(len + 1); + memcpy(buf, ptr(), length()); + memcpy(buf + length(), other.ptr(), other.length()); + buf[len] = '\0'; + + AutoString r; + r.ptr_ = buf; + r.length_ = len; + return r; + } + + AutoString operator +(const char *other) const { + size_t other_length = strlen(other); + size_t len = length() + other_length; + char *buf = (char *)malloc(len + 1); + memcpy(buf, ptr(), length()); + memcpy(buf + length(), other, other_length); + buf[len] = '\0'; + + AutoString r; + r.ptr_ = buf; + r.length_ = len; + return r; + } + + AutoString operator +(unsigned val) const { + char buffer[24]; + _snprintf(buffer, sizeof(buffer), "%d", val); + return *this + buffer; + } + + size_t length() const { + return length_; + } + + bool operator !() const { + return !length_; + } + + const char *ptr() const { + return ptr_ ? ptr_ : ""; + } + operator const char *() const { + return ptr(); + } + + private: + void assign(const char *ptr) { + if (!ptr) { + ptr_ = NULL; + length_ = 0; + return; + } + assign(ptr, strlen(ptr)); + } + void assign(const char *ptr, size_t length) { + if (!ptr) { + ptr_ = NULL; + length_ = 0; + return; + } + length_ = length; + ptr_ = (char *)malloc(length_ + 1); + memcpy(ptr_, ptr, length_); + ptr_[length_] = '\0'; + } + + private: + char *ptr_; + size_t length_; +}; + +#endif // _include_spcomp_auto_string_h_ diff --git a/public/memtools/CDetour/detourhelpers.h b/public/memtools/CDetour/detourhelpers.h index 291d8df2..b500cff7 100644 --- a/public/memtools/CDetour/detourhelpers.h +++ b/public/memtools/CDetour/detourhelpers.h @@ -34,6 +34,7 @@ #if defined(__linux__) || defined(__APPLE__) #include + #include #ifndef PAGE_SIZE #define PAGE_SIZE 4096 #endif diff --git a/public/memtools/CDetour/detours.h b/public/memtools/CDetour/detours.h index 89c2b238..b0335191 100644 --- a/public/memtools/CDetour/detours.h +++ b/public/memtools/CDetour/detours.h @@ -32,10 +32,12 @@ #ifndef _INCLUDE_SOURCEMOD_DETOURS_H_ #define _INCLUDE_SOURCEMOD_DETOURS_H_ -#include "amxxmodule.h" //#include //#include #include "detourhelpers.h" +#include + +typedef int32_t cell; /** * CDetours class for SourceMod Extensions by pRED* diff --git a/public/sm_namehashset.h b/public/sm_namehashset.h new file mode 100644 index 00000000..9524987b --- /dev/null +++ b/public/sm_namehashset.h @@ -0,0 +1,201 @@ +/** + * vim: set ts=4 sw=4 tw=99 noet : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#ifndef _include_sourcemod_namehashset_h_ +#define _include_sourcemod_namehashset_h_ + +/** + * @file sm_namehashset.h + * + * @brief Stores a set of uniquely named objects. + */ + +#include +#include +#include +#include + +//namespace SourceMod +//{ + +// The HashPolicy type must have this method: +// static bool matches(const char *key, const T &value); +// +// Depending on what lookup types are used. +// +// If these members are available on T, then the HashPolicy type can be left +// default. It is okay to use |T *|, the functions will still be looked up +// on |T|. +template +class NameHashSet : public ke::SystemAllocatorPolicy +{ + typedef detail::CharsAndLength CharsAndLength; + + // Default policy type: the two types are different. Use them directly. + template + struct Policy + { + typedef KeyType Payload; + + static uint32_t hash(const CharsAndLength &key) + { + return key.hash(); + } + + static bool matches(const CharsAndLength &key, const KeyType &value) + { + return KeyPolicyType::matches(key.chars(), value); + } + }; + + // Specialization: the types are equal, and T is a pointer. Strip the + // pointer off so we can access T:: for match functions. + template + struct Policy + { + typedef KeyType *Payload; + + static uint32_t hash(const detail::CharsAndLength &key) + { + return key.hash(); + } + + static bool matches(const CharsAndLength &key, const KeyType *value) + { + return KeyType::matches(key.chars(), value); + } + }; + + typedef ke::HashTable, ke::SystemAllocatorPolicy> Internal; + +public: + NameHashSet() + { + if (!table_.init()) + this->reportOutOfMemory(); + } + + typedef typename Internal::Result Result; + typedef typename Internal::Insert Insert; + typedef typename Internal::iterator iterator; + + Result find(const char *aKey) + { + return table_.find(aKey); + } + + Insert findForAdd(const char *aKey) + { + return table_.findForAdd(aKey); + } + + void add(Insert &i, const T &value) + { + return table_.add(i, value); + } + + void add(Insert &i, T &&value) + { + return table_.add(i, value); + } + + bool retrieve(const char *aKey, T *value) + { + CharsAndLength key(aKey); + Result r = table_.find(aKey); + if (!r.found()) + return false; + *value = *r; + return true; + } + + bool insert(const char *aKey, const T &value) + { + CharsAndLength key(aKey); + Insert i = table_.findForAdd(key); + if (i.found()) + return false; + return table_.add(i, value); + } + + bool insert(const char *aKey, T &&value) + { + CharsAndLength key(aKey); + Insert i = table_.findForAdd(key); + if (i.found()) + return false; + return table_.add(i, value); + } + + bool contains(const char *aKey) + { + CharsAndLength key(aKey); + Result r = table_.find(aKey); + return r.found(); + } + + bool remove(const char *aKey) + { + CharsAndLength key(aKey); + Result r = table_.find(key); + if (!r.found()) + return false; + table_.remove(r); + return true; + } + + void remove(Result &r) + { + table_.remove(r); + } + + void clear() + { + table_.clear(); + } + + size_t mem_usage() const + { + return table_.estimateMemoryUse(); + } + + iterator iter() + { + return iterator(&table_); + } + +private: + Internal table_; +}; + +//} + +#endif // _include_sourcemod_namehashset_h_ diff --git a/support/PackageScript b/support/PackageScript index 8fa1e99f..868013e6 100644 --- a/support/PackageScript +++ b/support/PackageScript @@ -245,6 +245,7 @@ scripting_files = [ 'include/csstats.inc', 'include/cstrike.inc', 'include/csx.inc', + 'include/cvars.inc', 'include/datapack.inc', 'include/dbi.inc', 'include/dodconst.inc',