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