Cvars: Adjust few things
- Hook is not as post, because allowing blocking change is not really that useful and this makes a context more simpler. - Setting a min bound > max bound and reversely throw an error - set_pcvar_bounds set cvar value on new min/max bound. - Remove error "A cvar can't be binded with several variables", it's okay to no error such situation.
This commit is contained in:
parent
1a5e1928ec
commit
e4a7e67783
|
@ -14,10 +14,7 @@
|
||||||
|
|
||||||
CvarManager g_CvarManager;
|
CvarManager g_CvarManager;
|
||||||
|
|
||||||
/**
|
DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value)
|
||||||
* Returns true to call original function, otherwise false to block it.
|
|
||||||
*/
|
|
||||||
bool Cvar_DirectSet_Custom(cvar_t* var, const char* value)
|
|
||||||
{
|
{
|
||||||
CvarInfo* info = nullptr;
|
CvarInfo* info = nullptr;
|
||||||
|
|
||||||
|
@ -25,7 +22,8 @@ bool Cvar_DirectSet_Custom(cvar_t* var, const char* value)
|
||||||
|| strcmp(var->string, value) == 0 // Make sure old and new values are different to not trigger callbacks.
|
|| strcmp(var->string, value) == 0 // Make sure old and new values are different to not trigger callbacks.
|
||||||
|| !g_CvarManager.CacheLookup(var->name, &info)) // No data in cache, nothing to do.
|
|| !g_CvarManager.CacheLookup(var->name, &info)) // No data in cache, nothing to do.
|
||||||
{
|
{
|
||||||
return true;
|
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->bound.hasMin || info->bound.hasMax) // cvar_s doesn't have min/max mechanism, so we check things here.
|
if (info->bound.hasMin || info->bound.hasMax) // cvar_s doesn't have min/max mechanism, so we check things here.
|
||||||
|
@ -47,36 +45,20 @@ bool Cvar_DirectSet_Custom(cvar_t* var, const char* value)
|
||||||
if (oob) // Found value out of bound, set new value and block original call.
|
if (oob) // Found value out of bound, set new value and block original call.
|
||||||
{
|
{
|
||||||
CVAR_SET_FLOAT(var->name, fvalue);
|
CVAR_SET_FLOAT(var->name, fvalue);
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ke::AString oldValue; // We save old value since it will be likely changed after original function called.
|
||||||
|
|
||||||
if (!info->hooks.empty())
|
if (!info->hooks.empty())
|
||||||
{
|
{
|
||||||
int lastResult = 0;
|
oldValue = var->string;
|
||||||
|
|
||||||
for (size_t i = 0; i < info->hooks.length(); ++i)
|
|
||||||
{
|
|
||||||
CvarHook* hook = info->hooks[i];
|
|
||||||
|
|
||||||
if (hook->forward->state == AutoForward::FSTATE_OK) // Our callback can be enable/disabled by natives.
|
|
||||||
{
|
|
||||||
int result = executeForwards(hook->forward->id, reinterpret_cast<cvar_t*>(var), var->string, value);
|
|
||||||
|
|
||||||
if (result >= lastResult)
|
|
||||||
{
|
|
||||||
lastResult = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastResult) // A plugin wants to block the forward.
|
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info->binds.empty()) // Time to update our available binds.
|
if (!info->binds.empty())
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < info->binds.length(); ++i)
|
for (size_t i = 0; i < info->binds.length(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -86,33 +68,35 @@ bool Cvar_DirectSet_Custom(cvar_t* var, const char* value)
|
||||||
{
|
{
|
||||||
case CvarBind::CvarType_Int:
|
case CvarBind::CvarType_Int:
|
||||||
{
|
{
|
||||||
*bind->varAddress = atoi(value);
|
*bind->varAddress = atoi(var->string);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CvarBind::CvarType_Float:
|
case CvarBind::CvarType_Float:
|
||||||
{
|
{
|
||||||
float fvalue = atof(value);
|
float fvalue = atof(var->string);
|
||||||
*bind->varAddress = amx_ftoc(fvalue);
|
*bind->varAddress = amx_ftoc(fvalue);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CvarBind::CvarType_String:
|
case CvarBind::CvarType_String:
|
||||||
{
|
{
|
||||||
set_amxstring_simple(bind->varAddress, value, bind->varLength);
|
set_amxstring_simple(bind->varAddress, var->string, bind->varLength);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to block.
|
if (!info->hooks.empty())
|
||||||
return true;
|
{
|
||||||
}
|
for (size_t i = 0; i < info->hooks.length(); ++i)
|
||||||
|
{
|
||||||
|
CvarHook* hook = info->hooks[i];
|
||||||
|
|
||||||
DETOUR_DECL_STATIC2(Cvar_DirectSet, void, struct cvar_s*, var, const char*, value)
|
if (hook->forward->state == AutoForward::FSTATE_OK) // Our callback can be enable/disabled by natives.
|
||||||
{
|
{
|
||||||
if (Cvar_DirectSet_Custom(var, value))
|
executeForwards(hook->forward->id, reinterpret_cast<cvar_t*>(var), oldValue.chars(), var->string);
|
||||||
{
|
}
|
||||||
DETOUR_STATIC_CALL(Cvar_DirectSet)(var, value);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,12 +149,8 @@ void CvarManager::CreateCvarHook(void)
|
||||||
|
|
||||||
if (functionAddress)
|
if (functionAddress)
|
||||||
{
|
{
|
||||||
|
// Disabled by default.
|
||||||
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress);
|
m_HookDetour = DETOUR_CREATE_STATIC_FIXED(Cvar_DirectSet, (void *)functionAddress);
|
||||||
|
|
||||||
if (m_HookDetour)
|
|
||||||
{
|
|
||||||
m_HookDetour->EnableDetour();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +355,7 @@ void CvarManager::OnConsoleCommand()
|
||||||
|
|
||||||
int argcount = CMD_ARGC();
|
int argcount = CMD_ARGC();
|
||||||
|
|
||||||
// amxx cvars <partial cvar name> <index from listing>
|
// amxx cvars [partial plugin name] [index from listing]
|
||||||
// E.g.:
|
// E.g.:
|
||||||
// amxx cvars test <- list all cvars from plugin name starting by "test"
|
// amxx cvars test <- list all cvars from plugin name starting by "test"
|
||||||
// amxx cvars 2 <- show informations about cvar in position 2 from "amxx cvars" list
|
// amxx cvars 2 <- show informations about cvar in position 2 from "amxx cvars" list
|
||||||
|
|
|
@ -367,15 +367,10 @@ bool bind_pcvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs,
|
||||||
if (bind->varAddress == address)
|
if (bind->varAddress == address)
|
||||||
{
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars");
|
LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars");
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogError(amx, AMX_ERR_NATIVE, "A cvar can't be binded with several variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen);
|
CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen);
|
||||||
|
|
||||||
|
@ -521,23 +516,66 @@ static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params)
|
||||||
|
|
||||||
bool set = params[3] > 0 ? true : false;
|
bool set = params[3] > 0 ? true : false;
|
||||||
int pluginId = g_plugins.findPluginFast(amx)->getId();
|
int pluginId = g_plugins.findPluginFast(amx)->getId();
|
||||||
|
float value = 0;
|
||||||
|
bool should_update = false;
|
||||||
|
|
||||||
switch (params[2])
|
switch (params[2])
|
||||||
{
|
{
|
||||||
case CvarBound_Lower:
|
case CvarBound_Lower:
|
||||||
|
{
|
||||||
info->bound.hasMin = set;
|
info->bound.hasMin = set;
|
||||||
info->bound.minVal = set ? amx_ctof(params[4]) : 0;
|
|
||||||
|
if (set)
|
||||||
|
{
|
||||||
|
value = amx_ctof(params[4]);
|
||||||
|
|
||||||
|
if (info->bound.hasMax && value > info->bound.maxVal)
|
||||||
|
{
|
||||||
|
LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
should_update = true;
|
||||||
|
|
||||||
|
info->bound.minVal = value;
|
||||||
info->bound.minPluginId = pluginId;
|
info->bound.minPluginId = pluginId;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CvarBound_Upper:
|
case CvarBound_Upper:
|
||||||
|
{
|
||||||
info->bound.hasMax = set;
|
info->bound.hasMax = set;
|
||||||
info->bound.maxVal = set ? amx_ctof(params[4]) : 0;
|
|
||||||
|
if (set)
|
||||||
|
{
|
||||||
|
value = amx_ctof(params[4]);
|
||||||
|
|
||||||
|
if (info->bound.hasMin && value < info->bound.minVal)
|
||||||
|
{
|
||||||
|
LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
should_update = true;
|
||||||
|
|
||||||
|
info->bound.maxVal = value;
|
||||||
info->bound.maxPluginId = pluginId;
|
info->bound.maxPluginId = pluginId;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]);
|
LogError(amx, AMX_ERR_NATIVE, "Invalid CvarBounds value: %d", params[2]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_update)
|
||||||
|
{
|
||||||
|
CVAR_SET_FLOAT(ptr->name, value);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,9 @@ native get_cvar_pointer(const cvar[]);
|
||||||
/**
|
/**
|
||||||
* Creates a hook for when a cvar's value is changed.
|
* Creates a hook for when a cvar's value is changed.
|
||||||
*
|
*
|
||||||
|
* @note You cannot prevent cvar changes from happening, you can only change the value again.
|
||||||
|
* @note Be careful not to set a cvar inside a cvar change hook such that
|
||||||
|
* it re-invokes he same callback. This results in infinite recursion.
|
||||||
* @note Callback will be called in the following manner:
|
* @note Callback will be called in the following manner:
|
||||||
*
|
*
|
||||||
* public cvar_change_callback(pcvar, const old_value[], const new_value[])
|
* public cvar_change_callback(pcvar, const old_value[], const new_value[])
|
||||||
|
|
Loading…
Reference in New Issue
Block a user