Cvars: Adjust more things

- Moved some functions in CvarManager
- Fixed detour enabled all the time
- Fixed bounds not properly handled
- Refreshed data of regisetered cvars at map change
This commit is contained in:
Arkshine 2015-01-28 23:51:43 +01:00
parent 187b187ef2
commit f8baef15ca
3 changed files with 168 additions and 127 deletions

View File

@ -154,7 +154,7 @@ void CvarManager::CreateCvarHook(void)
} }
} }
cvar_t* CvarManager::CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags, CvarInfo* CvarManager::CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, int flags,
const char* helpText, bool hasMin, float min, bool hasMax, float max) const char* helpText, bool hasMin, float min, bool hasMax, float max)
{ {
cvar_t* var = nullptr; cvar_t* var = nullptr;
@ -215,11 +215,27 @@ cvar_t* CvarManager::CreateCvar(const char* name, const char* value, const char*
// Make sure that whether an existing or new cvar is set to the given value. // Make sure that whether an existing or new cvar is set to the given value.
CVAR_DIRECTSET(var, value); CVAR_DIRECTSET(var, value);
} }
else if (info->pluginId == -1)
{
// In situation where a plugin has been modified/recompiled
// or new added plugins, and a change map occurs. We want to keep data up to date.
info->bound.hasMin = hasMin;
info->bound.minVal = min;
info->bound.hasMax = hasMax;
info->bound.maxVal = max;
info->defaultval = value;
info->description = helpText;
info->pluginId = pluginId;
}
// Detour is disabled on map change. // Detour is disabled on map change.
// Don't enable it unless there are things to do.
if (info->bound.hasMin || info->bound.hasMax)
{
m_HookDetour->EnableDetour(); m_HookDetour->EnableDetour();
}
return info->var; return info;
} }
CvarInfo* CvarManager::FindCvar(const char* name) CvarInfo* CvarManager::FindCvar(const char* name)
@ -227,9 +243,6 @@ CvarInfo* CvarManager::FindCvar(const char* name)
cvar_t* var = nullptr; cvar_t* var = nullptr;
CvarInfo* info = nullptr; CvarInfo* info = nullptr;
// Detour is disabled on map change.
m_HookDetour->EnableDetour();
// Do we have already cvar in cache? // Do we have already cvar in cache?
if (CacheLookup(name, &info)) if (CacheLookup(name, &info))
{ {
@ -316,6 +329,104 @@ AutoForward* CvarManager::HookCvarChange(cvar_t* var, AMX* amx, cell param, cons
return forward; return forward;
} }
bool CvarManager::BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen)
{
if (varofs > amx->hlw) // If variable address is not inside global area, we can't bind it.
{
LogError(amx, AMX_ERR_NATIVE, "A global variable must be provided");
return false;
}
int pluginId = g_plugins.findPluginFast(amx)->getId();
cell* address = get_amxaddr(amx, varofs);
// To avoid unexpected behavior, probably better to error such situations.
for (size_t i = 0; i < info->binds.length(); ++i)
{
CvarBind* bind = info->binds[i];
if (bind->pluginId == pluginId)
{
if (bind->varAddress == address)
{
LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars");
return false;
}
}
}
CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen);
info->binds.append(bind);
// Update right away variable with current cvar value.
switch (type)
{
case CvarBind::CvarType_Int:
*bind->varAddress = atoi(info->var->string);
break;
case CvarBind::CvarType_Float:
*bind->varAddress = amx_ftoc(info->var->value);
break;
case CvarBind::CvarType_String:
set_amxstring_simple(bind->varAddress, info->var->string, bind->varLength);
break;
}
// Detour is disabled on map change.
m_HookDetour->EnableDetour();
return true;
}
bool CvarManager::SetCvarMin(CvarInfo* info, bool set, float value, int pluginId)
{
info->bound.hasMin = set;
info->bound.minPluginId = pluginId;
if (set)
{
if (info->bound.hasMax && value > info->bound.maxVal)
{
return false;
}
info->bound.minVal = value;
// Detour is disabled on map change.
m_HookDetour->EnableDetour();
// Update if needed.
CVAR_SET_FLOAT(info->var->name, value);
}
return true;
}
bool CvarManager::SetCvarMax(CvarInfo* info, bool set, float value, int pluginId)
{
info->bound.hasMax = set;
info->bound.maxPluginId = pluginId;
if (set)
{
if (info->bound.hasMin && value < info->bound.minVal)
{
return false;
}
info->bound.maxVal = value;
// Detour is disabled on map change.
m_HookDetour->EnableDetour();
// Update if needed.
CVAR_SET_FLOAT(info->var->name, value);
}
return true;
}
size_t CvarManager::GetRegCvarsCount() size_t CvarManager::GetRegCvarsCount()
{ {
return m_AmxmodxCvars; return m_AmxmodxCvars;
@ -475,6 +586,11 @@ void CvarManager::OnPluginUnloaded()
delete (*cvar)->hooks[i]; delete (*cvar)->hooks[i];
} }
if ((*cvar)->amxmodx) // Mark registered cvars so we can refresh default datas at next map.
{
(*cvar)->pluginId = -1;
}
(*cvar)->binds.clear(); (*cvar)->binds.clear();
(*cvar)->hooks.clear(); (*cvar)->hooks.clear();
} }

View File

@ -150,7 +150,7 @@ class CvarManager
void CreateCvarHook(); void CreateCvarHook();
cvar_t* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId, CvarInfo* CreateCvar(const char* name, const char* value, const char* plugin, int pluginId,
int flags = 0, const char* helpText = "", int flags = 0, const char* helpText = "",
bool hasMin = false, float min = 0, bool hasMin = false, float min = 0,
bool hasMax = false, float max = 0); bool hasMax = false, float max = 0);
@ -160,6 +160,9 @@ class CvarManager
bool CacheLookup(const char* name, CvarInfo** info); bool CacheLookup(const char* name, CvarInfo** info);
AutoForward* HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback); AutoForward* HookCvarChange(cvar_t* var, AMX* amx, cell param, const char** callback);
bool BindCvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen = 0);
bool SetCvarMin(CvarInfo* info, bool set, float value, int pluginId);
bool SetCvarMax(CvarInfo* info, bool set, float value, int pluginId);
size_t GetRegCvarsCount(); size_t GetRegCvarsCount();

View File

@ -23,32 +23,6 @@ static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params)
const char* helpText = get_amxstring(amx, params[4], 2, length); const char* helpText = get_amxstring(amx, params[4], 2, length);
int flags = params[3]; int flags = params[3];
bool hasMin = params[5] != 0;
bool hasMax = params[7] != 0;
float minVal = 0;
float maxVal = 0;
if (hasMin)
{
minVal = amx_ctof(params[6]);
if (hasMax && minVal > maxVal)
{
LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound");
return 0;
}
}
if (hasMax)
{
maxVal = amx_ctof(params[8]);
if (hasMin && maxVal < minVal)
{
LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound");
return 0;
}
}
CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx); CPluginMngr::CPlugin *plugin = g_plugins.findPluginFast(amx);
@ -57,9 +31,31 @@ static cell AMX_NATIVE_CALL create_cvar(AMX *amx, cell *params)
plugin->AddToFailCounter(1); plugin->AddToFailCounter(1);
} }
cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText, hasMin, minVal, hasMax, maxVal); CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags, helpText);
return reinterpret_cast<cell>(var); if (info)
{
bool hasMin = params[5] != 0;
bool hasMax = params[7] != 0;
float minVal = amx_ctof(params[6]);
float maxVal = amx_ctof(params[8]);
if (!g_CvarManager.SetCvarMin(info, hasMin, minVal, plugin->getId()))
{
LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound");
return 0;
}
if (!g_CvarManager.SetCvarMax(info, hasMax, maxVal, plugin->getId()))
{
LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound");
return 0;
}
return reinterpret_cast<cell>(info->var);
}
return 0;
} }
// register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0) // register_cvar(const name[], const string[], flags=0, Float:fvalue=0.0)
@ -79,9 +75,14 @@ static cell AMX_NATIVE_CALL register_cvar(AMX *amx, cell *params)
plugin->AddToFailCounter(1); plugin->AddToFailCounter(1);
} }
cvar_t* var = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags); CvarInfo* info = g_CvarManager.CreateCvar(name, value, plugin->getName(), plugin->getId(), flags);
return reinterpret_cast<cell>(var); if (info)
{
return reinterpret_cast<cell>(info->var);
}
return 0;
} }
// cvar_exists(const cvar[]) // cvar_exists(const cvar[])
@ -368,53 +369,6 @@ static cell AMX_NATIVE_CALL get_pcvar_bounds(AMX *amx, cell *params)
return hasBound; return hasBound;
} }
bool bind_pcvar(CvarInfo* info, CvarBind::CvarType type, AMX* amx, cell varofs, size_t varlen = 0)
{
if (varofs > amx->hlw) // If variable address is not inside global area, we can't bind it.
{
LogError(amx, AMX_ERR_NATIVE, "A global variable must be provided");
return false;
}
int pluginId = g_plugins.findPluginFast(amx)->getId();
cell* address = get_amxaddr(amx, varofs);
// To avoid unexpected behavior, probably better to error such situations.
for (size_t i = 0; i < info->binds.length(); ++i)
{
CvarBind* bind = info->binds[i];
if (bind->pluginId == pluginId)
{
if (bind->varAddress == address)
{
LogError(amx, AMX_ERR_NATIVE, "A same variable can't be binded with several cvars");
return false;
}
}
}
CvarBind* bind = new CvarBind(pluginId, type, get_amxaddr(amx, varofs), varlen);
info->binds.append(bind);
// Update right away variable with current cvar value.
switch (type)
{
case CvarBind::CvarType_Int:
*bind->varAddress = atoi(info->var->string);
break;
case CvarBind::CvarType_Float:
*bind->varAddress = amx_ftoc(info->var->value);
break;
case CvarBind::CvarType_String:
set_amxstring_simple(bind->varAddress, info->var->string, bind->varLength);
break;
}
return true;
}
// bind_pcvar_float(pcvar, &Float:var) // bind_pcvar_float(pcvar, &Float:var)
static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params) static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params)
{ {
@ -427,7 +381,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_float(AMX *amx, cell *params)
return 0; return 0;
} }
return bind_pcvar(info, CvarBind::CvarType_Float, amx, params[2]); return g_CvarManager.BindCvar(info, CvarBind::CvarType_Float, amx, params[2]);
} }
// bind_pcvar_num(pcvar, &any:var) // bind_pcvar_num(pcvar, &any:var)
@ -442,7 +396,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_num(AMX *amx, cell *params)
return 0; return 0;
} }
return bind_pcvar(info, CvarBind::CvarType_Int, amx, params[2]); return g_CvarManager.BindCvar(info, CvarBind::CvarType_Int, amx, params[2]);
} }
// bind_pcvar_string(pcvar, any:var[], varlen) // bind_pcvar_string(pcvar, any:var[], varlen)
@ -457,7 +411,7 @@ static cell AMX_NATIVE_CALL bind_pcvar_string(AMX *amx, cell *params)
return 0; return 0;
} }
return bind_pcvar(info, CvarBind::CvarType_String, amx, params[2], params[3]); return g_CvarManager.BindCvar(info, CvarBind::CvarType_String, amx, params[2], params[3]);
} }
// set_pcvar_flags(pcvar, flags) // set_pcvar_flags(pcvar, flags)
@ -538,53 +492,26 @@ static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params)
bool set = params[3] != 0; bool set = params[3] != 0;
int pluginId = g_plugins.findPluginFast(amx)->getId(); int pluginId = g_plugins.findPluginFast(amx)->getId();
float value = 0; float value = amx_ctof(params[4]);
bool should_update = false;
switch (params[2]) switch (params[2])
{ {
case CvarBound_Lower: case CvarBound_Lower:
{ {
info->bound.hasMin = set; if (!g_CvarManager.SetCvarMin(info, set, value, pluginId))
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"); LogError(amx, AMX_ERR_NATIVE, "A lower bound can't be above an upper bound");
return 0; return 0;
} }
should_update = true;
info->bound.minVal = value;
info->bound.minPluginId = pluginId;
}
break; break;
} }
case CvarBound_Upper: case CvarBound_Upper:
{ {
info->bound.hasMax = set; if (!g_CvarManager.SetCvarMax(info, set, value, pluginId))
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"); LogError(amx, AMX_ERR_NATIVE, "An upper bound can't be below a lower bound");
return 0; return 0;
} }
should_update = true;
info->bound.maxVal = value;
info->bound.maxPluginId = pluginId;
}
break; break;
} }
default: default:
@ -594,11 +521,6 @@ static cell AMX_NATIVE_CALL set_pcvar_bounds(AMX *amx, cell *params)
} }
} }
if (should_update)
{
CVAR_SET_FLOAT(ptr->name, value);
}
return 1; return 1;
} }