Refactor config manager, move config variable handling

Move all code for handling of config variables from console to config manager. The console no longer depends on the config manager, instead the config manager now depends on the console.

Add `struct`s to manage config variables of different types (int, color and string). The config manager now keeps a list of all config variables, so usage of the preprocessor can be avoided except for code to initially create all config variables. Additionally, a separate list of just the game config variables (config variables with `CFGFLAG_GAME`) is kept to optimize the `ResetGameSettings` function, as this function is called whenever connecting to a server and should be fast. Previously, this function was even less efficient because it preformed a linear search for every individual game config variable to find the respective command data.

Move console commands that opperate only on config variables (`reset`, `toggle` and `+toggle`) to config manager. Ensure that these commands only opperate on the desired config variables (client or server, respectively) by checking `IConsole::FlagMask`.

Add `IConfigManager::SetReadOnly` function to set/unset config variables as read-only instead of manually overriding the command handlers for the `sv_rescue` and `sv_test_cmds` config variables. This also fixes that read-only config variables could still be changed by using the `reset` command. A console message is now printed when trying to change a read-only config variable. Removing the special handling for these two config variables is additionally useful so the console does not need to keep a pointer to config values and manager.

Use a `CHeap` for the config variables, their help texts and the previous values of string config variables to avoid many separate allocations as well usage of static variables. Also use the heap to store the unknown commands instead of using `std::string`s.

Properly trigger command chain when resetting config variables with the `reset` command and when resetting game settings on map loading. Closes #7461.

Format default value for color variables as RGB/RGBA hex with dollar sign prefix. Closes #5523.

Add log message when using `reset` with a variable that does not exist. Use `log_error` instead of `dbg_msg` when saving config file fails.

Support unlimited number of config save callbacks instead of at most 16. The code also becomes more readable by using an `std::vector` instead of a fixed-size array and a separate num variable.

Consistently name `MACRO_CONFIG_*` parameters when declaring the macros.

Add `IConsole::CMDLINE_LENGTH` constant to represent the maximum length of the console input and thereby reduce usage of magic numbers for buffer sizes.
This commit is contained in:
Robert Müller 2023-11-22 23:07:08 +01:00
parent 1cf80edb2a
commit 159ddf5534
16 changed files with 577 additions and 436 deletions

View file

@ -4467,8 +4467,8 @@ int main(int argc, const char **argv)
}
pEngine->Init();
pConfigManager->Init();
pConsole->Init();
pConfigManager->Init();
// register all console commands
pClient->RegisterCommands();

View file

@ -12,8 +12,9 @@ public:
typedef void (*SAVECALLBACKFUNC)(IConfigManager *pConfig, void *pUserData);
virtual void Init() = 0;
virtual void Reset() = 0;
virtual void Reset(const char *pScriptName) = 0;
virtual void ResetGameSettings() = 0;
virtual void SetReadOnly(const char *pScriptName, bool ReadOnly) = 0;
virtual bool Save() = 0;
virtual class CConfig *Values() = 0;

View file

@ -34,6 +34,8 @@ public:
TEMPCMD_HELP_LENGTH = 192,
TEMPCMD_PARAMS_LENGTH = 96,
CMDLINE_LENGTH = 512,
CLIENT_ID_GAME = -2,
CLIENT_ID_NO_GAME = -3,
};
@ -117,8 +119,6 @@ public:
virtual void SetAccessLevel(int AccessLevel) = 0;
virtual void ResetGameSettings() = 0;
static LEVEL ToLogLevel(int ConsoleLevel);
static int ToLogLevelFilter(int ConsoleLevel);

View file

@ -153,8 +153,8 @@ int main(int argc, const char **argv)
}
pEngine->Init();
pConfigManager->Init();
pConsole->Init();
pConfigManager->Init();
// register all console commands
pServer->RegisterCommands();
@ -173,8 +173,8 @@ int main(int argc, const char **argv)
if(argc > 1)
pConsole->ParseArguments(argc - 1, &argv[1]);
pConsole->Register("sv_test_cmds", "", CFGFLAG_SERVER, CServer::ConTestingCommands, pConsole, "Turns testing commands aka cheats on/off (setting only works in initial config)");
pConsole->Register("sv_rescue", "", CFGFLAG_SERVER, CServer::ConRescue, pConsole, "Allow /rescue command so players can teleport themselves out of freeze (setting only works in initial config)");
pConfigManager->SetReadOnly("sv_test_cmds", true);
pConfigManager->SetReadOnly("sv_rescue", true);
const int Mode = g_Config.m_Logappend ? IOFLAG_APPEND : IOFLAG_WRITE;
if(g_Config.m_Logfile[0])

View file

@ -3096,22 +3096,6 @@ int CServer::Run()
return ErrorShutdown();
}
void CServer::ConTestingCommands(CConsole::IResult *pResult, void *pUser)
{
CConsole *pThis = static_cast<CConsole *>(pUser);
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Value: %d", pThis->Config()->m_SvTestingCommands);
pThis->Print(CConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
void CServer::ConRescue(CConsole::IResult *pResult, void *pUser)
{
CConsole *pThis = static_cast<CConsole *>(pUser);
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Value: %d", pThis->Config()->m_SvRescue);
pThis->Print(CConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
{
if(pResult->NumArguments() > 1)

View file

@ -413,8 +413,6 @@ public:
int Run();
static void ConTestingCommands(IConsole::IResult *pResult, void *pUser);
static void ConRescue(IConsole::IResult *pResult, void *pUser);
static void ConKick(IConsole::IResult *pResult, void *pUser);
static void ConStatus(IConsole::IResult *pResult, void *pUser);
static void ConShutdown(IConsole::IResult *pResult, void *pUser);

View file

@ -1,65 +1,463 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/log.h>
#include <engine/config.h>
#include <engine/shared/config.h>
#include <engine/shared/console.h>
#include <engine/shared/protocol.h>
#include <engine/storage.h>
CConfig g_Config;
void EscapeParam(char *pDst, const char *pSrc, int Size)
static void EscapeParam(char *pDst, const char *pSrc, int Size)
{
str_escape(&pDst, pSrc, pDst + Size);
}
struct SConfigVariable
{
enum EVariableType
{
VAR_INT,
VAR_COLOR,
VAR_STRING,
};
IConsole *m_pConsole;
const char *m_pScriptName;
EVariableType m_Type;
int m_Flags;
const char *m_pHelp;
// Note that this only applies to the console command and the SetValue function,
// but the underlying config variable can still be modified programatically.
bool m_ReadOnly = false;
SConfigVariable(IConsole *pConsole, const char *pScriptName, EVariableType Type, int Flags, const char *pHelp) :
m_pConsole(pConsole),
m_pScriptName(pScriptName),
m_Type(Type),
m_Flags(Flags),
m_pHelp(pHelp)
{
}
virtual ~SConfigVariable() = default;
virtual void Register() = 0;
virtual bool IsDefault() const = 0;
virtual void Serialize(char *pOut, size_t Size) const = 0;
virtual void ResetToDefault() = 0;
virtual void ResetToOld() = 0;
protected:
void ExecuteLine(const char *pLine)
{
m_pConsole->ExecuteLine(pLine, (m_Flags & CFGFLAG_GAME) != 0 ? IConsole::CLIENT_ID_GAME : -1);
}
bool CheckReadOnly()
{
if(!m_ReadOnly)
return false;
char aBuf[IConsole::CMDLINE_LENGTH + 64];
str_format(aBuf, sizeof(aBuf), "The config variable '%s' cannot be changed right now.", m_pScriptName);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
return true;
}
};
struct SIntConfigVariable : public SConfigVariable
{
int *m_pVariable;
int m_Default;
int m_Min;
int m_Max;
int m_OldValue;
SIntConfigVariable(IConsole *pConsole, const char *pScriptName, EVariableType Type, int Flags, const char *pHelp, int *pVariable, int Default, int Min, int Max) :
SConfigVariable(pConsole, pScriptName, Type, Flags, pHelp),
m_pVariable(pVariable),
m_Default(Default),
m_Min(Min),
m_Max(Max),
m_OldValue(Default)
{
*m_pVariable = m_Default;
}
~SIntConfigVariable() override = default;
static void CommandCallback(IConsole::IResult *pResult, void *pUserData)
{
SIntConfigVariable *pData = static_cast<SIntConfigVariable *>(pUserData);
if(pResult->NumArguments())
{
if(pData->CheckReadOnly())
return;
int Value = pResult->GetInteger(0);
// do clamping
if(pData->m_Min != pData->m_Max)
{
if(Value < pData->m_Min)
Value = pData->m_Min;
if(pData->m_Max != 0 && Value > pData->m_Max)
Value = pData->m_Max;
}
*pData->m_pVariable = Value;
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
pData->m_OldValue = Value;
}
else
{
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "Value: %d", *pData->m_pVariable);
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
}
void Register() override
{
m_pConsole->Register(m_pScriptName, "?i", m_Flags, CommandCallback, this, m_pHelp);
}
bool IsDefault() const override
{
return *m_pVariable == m_Default;
}
void Serialize(char *pOut, size_t Size, int Value) const
{
str_format(pOut, Size, "%s %i", m_pScriptName, Value);
}
void Serialize(char *pOut, size_t Size) const override
{
Serialize(pOut, Size, *m_pVariable);
}
void SetValue(int Value)
{
if(CheckReadOnly())
return;
char aBuf[IConsole::CMDLINE_LENGTH];
Serialize(aBuf, sizeof(aBuf), Value);
ExecuteLine(aBuf);
}
void ResetToDefault() override
{
SetValue(m_Default);
}
void ResetToOld() override
{
SetValue(m_OldValue);
}
};
struct SColorConfigVariable : public SConfigVariable
{
unsigned *m_pVariable;
unsigned m_Default;
bool m_Light;
bool m_Alpha;
unsigned m_OldValue;
SColorConfigVariable(IConsole *pConsole, const char *pScriptName, EVariableType Type, int Flags, const char *pHelp, unsigned *pVariable, unsigned Default) :
SConfigVariable(pConsole, pScriptName, Type, Flags, pHelp),
m_pVariable(pVariable),
m_Default(Default),
m_Light(Flags & CFGFLAG_COLLIGHT),
m_Alpha(Flags & CFGFLAG_COLALPHA),
m_OldValue(Default)
{
*m_pVariable = m_Default;
}
~SColorConfigVariable() override = default;
static void CommandCallback(IConsole::IResult *pResult, void *pUserData)
{
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
if(pResult->NumArguments())
{
if(pData->CheckReadOnly())
return;
const ColorHSLA Color = pResult->GetColor(0, pData->m_Light);
const unsigned Value = Color.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
*pData->m_pVariable = Value;
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
pData->m_OldValue = Value;
}
else
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
ColorHSLA Hsla = ColorHSLA(*pData->m_pVariable, true);
if(pData->m_Light)
Hsla = Hsla.UnclampLighting();
str_format(aBuf, sizeof(aBuf), "H: %d°, S: %d%%, L: %d%%", round_truncate(Hsla.h * 360), round_truncate(Hsla.s * 100), round_truncate(Hsla.l * 100));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
const ColorRGBA Rgba = color_cast<ColorRGBA>(Hsla);
str_format(aBuf, sizeof(aBuf), "R: %d, G: %d, B: %d, #%06X", round_truncate(Rgba.r * 255), round_truncate(Rgba.g * 255), round_truncate(Rgba.b * 255), Rgba.Pack(false));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
if(pData->m_Alpha)
{
str_format(aBuf, sizeof(aBuf), "A: %d%%", round_truncate(Hsla.a * 100));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
}
}
void Register() override
{
m_pConsole->Register(m_pScriptName, "?i", m_Flags, CommandCallback, this, m_pHelp);
}
bool IsDefault() const override
{
return *m_pVariable == m_Default;
}
void Serialize(char *pOut, size_t Size, unsigned Value) const
{
str_format(pOut, Size, "%s %u", m_pScriptName, Value);
}
void Serialize(char *pOut, size_t Size) const override
{
Serialize(pOut, Size, *m_pVariable);
}
void SetValue(unsigned Value)
{
if(CheckReadOnly())
return;
char aBuf[IConsole::CMDLINE_LENGTH];
Serialize(aBuf, sizeof(aBuf), Value);
ExecuteLine(aBuf);
}
void ResetToDefault() override
{
SetValue(m_Default);
}
void ResetToOld() override
{
SetValue(m_OldValue);
}
};
struct SStringConfigVariable : public SConfigVariable
{
char *m_pStr;
const char *m_pDefault;
size_t m_MaxSize;
char *m_pOldValue;
SStringConfigVariable(IConsole *pConsole, const char *pScriptName, EVariableType Type, int Flags, const char *pHelp, char *pStr, const char *pDefault, size_t MaxSize, char *pOldValue) :
SConfigVariable(pConsole, pScriptName, Type, Flags, pHelp),
m_pStr(pStr),
m_pDefault(pDefault),
m_MaxSize(MaxSize),
m_pOldValue(pOldValue)
{
str_copy(m_pStr, m_pDefault, m_MaxSize);
str_copy(m_pOldValue, m_pDefault, m_MaxSize);
}
~SStringConfigVariable() override = default;
static void CommandCallback(IConsole::IResult *pResult, void *pUserData)
{
SStringConfigVariable *pData = static_cast<SStringConfigVariable *>(pUserData);
if(pResult->NumArguments())
{
if(pData->CheckReadOnly())
return;
const char *pString = pResult->GetString(0);
if(!str_utf8_check(pString))
{
char aTemp[4];
size_t Length = 0;
while(*pString)
{
size_t Size = str_utf8_encode(aTemp, static_cast<unsigned char>(*pString++));
if(Length + Size < pData->m_MaxSize)
{
mem_copy(pData->m_pStr + Length, aTemp, Size);
Length += Size;
}
else
break;
}
pData->m_pStr[Length] = '\0';
}
else
str_copy(pData->m_pStr, pString, pData->m_MaxSize);
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
str_copy(pData->m_pOldValue, pData->m_pStr, pData->m_MaxSize);
}
else
{
char aBuf[1024];
str_format(aBuf, sizeof(aBuf), "Value: %s", pData->m_pStr);
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
}
void Register() override
{
m_pConsole->Register(m_pScriptName, "?r", m_Flags, CommandCallback, this, m_pHelp);
}
bool IsDefault() const override
{
return str_comp(m_pStr, m_pDefault) == 0;
}
void Serialize(char *pOut, size_t Size, const char *pValue) const
{
str_copy(pOut, m_pScriptName, Size);
str_append(pOut, " \"", Size);
const int OutLen = str_length(pOut);
EscapeParam(pOut + OutLen, pValue, Size - OutLen - 1); // -1 to ensure space for final quote
str_append(pOut, "\"", Size);
}
void Serialize(char *pOut, size_t Size) const override
{
Serialize(pOut, Size, m_pStr);
}
void SetValue(const char *pValue)
{
if(CheckReadOnly())
return;
char aBuf[2048];
Serialize(aBuf, sizeof(aBuf), pValue);
ExecuteLine(aBuf);
}
void ResetToDefault() override
{
SetValue(m_pDefault);
}
void ResetToOld() override
{
SetValue(m_pOldValue);
}
};
CConfigManager::CConfigManager()
{
m_pStorage = 0;
m_pConsole = nullptr;
m_pStorage = nullptr;
m_ConfigFile = 0;
m_NumCallbacks = 0;
m_Failed = false;
}
void CConfigManager::Init()
{
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
Reset();
}
void CConfigManager::Reset()
{
#define MACRO_CONFIG_INT(Name, ScriptName, def, min, max, flags, desc) g_Config.m_##Name = def;
#define MACRO_CONFIG_COL(Name, ScriptName, def, flags, desc) MACRO_CONFIG_INT(Name, ScriptName, def, 0, 0, flags, desc)
#define MACRO_CONFIG_STR(Name, ScriptName, len, def, flags, desc) str_copy(g_Config.m_##Name, def, len);
const auto &&AddVariable = [this](SConfigVariable *pVariable) {
m_vpAllVariables.push_back(pVariable);
if((pVariable->m_Flags & CFGFLAG_GAME) != 0)
m_vpGameVariables.push_back(pVariable);
pVariable->Register();
};
#define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Flags, Desc) \
{ \
const char *pHelp = Min == Max ? Desc " (default: " #Def ")" : Max == 0 ? Desc " (default: " #Def ", min: " #Min ")" : Desc " (default: " #Def ", min: " #Min ", max: " #Max ")"; \
AddVariable(m_ConfigHeap.Allocate<SIntConfigVariable>(m_pConsole, #ScriptName, SConfigVariable::VAR_INT, Flags, pHelp, &g_Config.m_##Name, Def, Min, Max)); \
}
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) \
{ \
const size_t HelpSize = (size_t)str_length(Desc) + 32; \
char *pHelp = static_cast<char *>(m_ConfigHeap.Allocate(HelpSize)); \
const bool Alpha = ((Flags)&CFGFLAG_COLALPHA) != 0; \
str_format(pHelp, HelpSize, "%s (default: $%0*X)", Desc, Alpha ? 8 : 6, color_cast<ColorRGBA>(ColorHSLA(Def, Alpha)).Pack(Alpha)); \
AddVariable(m_ConfigHeap.Allocate<SColorConfigVariable>(m_pConsole, #ScriptName, SConfigVariable::VAR_COLOR, Flags, pHelp, &g_Config.m_##Name, Def)); \
}
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \
{ \
const size_t HelpSize = (size_t)str_length(Desc) + str_length(Def) + 64; \
char *pHelp = static_cast<char *>(m_ConfigHeap.Allocate(HelpSize)); \
str_format(pHelp, HelpSize, "%s (default: \"%s\", max length: %d)", Desc, Def, Len - 1); \
char *pOldValue = static_cast<char *>(m_ConfigHeap.Allocate(Len)); \
AddVariable(m_ConfigHeap.Allocate<SStringConfigVariable>(m_pConsole, #ScriptName, SConfigVariable::VAR_STRING, Flags, pHelp, g_Config.m_##Name, Def, Len, pOldValue)); \
}
#include "config_variables.h"
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
m_pConsole->Register("reset", "s[config-name]", CFGFLAG_SERVER | CFGFLAG_CLIENT | CFGFLAG_STORE, Con_Reset, this, "Reset a config to its default value");
m_pConsole->Register("toggle", "s[config-option] i[value 1] i[value 2]", CFGFLAG_SERVER | CFGFLAG_CLIENT, Con_Toggle, this, "Toggle config value");
m_pConsole->Register("+toggle", "s[config-option] i[value 1] i[value 2]", CFGFLAG_CLIENT, Con_ToggleStroke, this, "Toggle config value via keypress");
}
void CConfigManager::Reset(const char *pScriptName)
{
#define MACRO_CONFIG_INT(Name, ScriptName, def, min, max, flags, desc) \
if(str_comp(pScriptName, #ScriptName) == 0) \
{ \
g_Config.m_##Name = def; \
return; \
};
#define MACRO_CONFIG_COL(Name, ScriptName, def, flags, desc) MACRO_CONFIG_INT(Name, ScriptName, def, 0, 0, flags, desc)
#define MACRO_CONFIG_STR(Name, ScriptName, len, def, flags, desc) \
if(str_comp(pScriptName, #ScriptName) == 0) \
{ \
str_copy(g_Config.m_##Name, def, len); \
return; \
};
for(SConfigVariable *pVariable : m_vpAllVariables)
{
if((pVariable->m_Flags & m_pConsole->FlagMask()) != 0 && str_comp(pScriptName, pVariable->m_pScriptName) == 0)
{
pVariable->ResetToDefault();
return;
}
}
#include "config_variables.h"
char aBuf[IConsole::CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Invalid command: '%s'.", pScriptName);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
void CConfigManager::ResetGameSettings()
{
for(SConfigVariable *pVariable : m_vpGameVariables)
{
pVariable->ResetToOld();
}
}
void CConfigManager::SetReadOnly(const char *pScriptName, bool ReadOnly)
{
for(SConfigVariable *pVariable : m_vpAllVariables)
{
if(str_comp(pScriptName, pVariable->m_pScriptName) == 0)
{
pVariable->m_ReadOnly = ReadOnly;
return;
}
}
char aBuf[IConsole::CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Invalid command for SetReadOnly: '%s'", pScriptName);
dbg_assert(false, aBuf);
}
bool CConfigManager::Save()
@ -72,47 +470,30 @@ bool CConfigManager::Save()
if(!m_ConfigFile)
{
dbg_msg("config", "ERROR: opening %s failed", aConfigFileTmp);
log_error("config", "ERROR: opening %s failed", aConfigFileTmp);
return false;
}
m_Failed = false;
char aLineBuf[1024 * 2];
char aEscapeBuf[1024 * 2];
#define MACRO_CONFIG_INT(Name, ScriptName, def, min, max, flags, desc) \
if((flags)&CFGFLAG_SAVE && g_Config.m_##Name != (def)) \
{ \
str_format(aLineBuf, sizeof(aLineBuf), "%s %i", #ScriptName, g_Config.m_##Name); \
WriteLine(aLineBuf); \
}
#define MACRO_CONFIG_COL(Name, ScriptName, def, flags, desc) \
if((flags)&CFGFLAG_SAVE && g_Config.m_##Name != (def)) \
{ \
str_format(aLineBuf, sizeof(aLineBuf), "%s %u", #ScriptName, g_Config.m_##Name); \
WriteLine(aLineBuf); \
}
#define MACRO_CONFIG_STR(Name, ScriptName, len, def, flags, desc) \
if((flags)&CFGFLAG_SAVE && str_comp(g_Config.m_##Name, def) != 0) \
{ \
EscapeParam(aEscapeBuf, g_Config.m_##Name, sizeof(aEscapeBuf)); \
str_format(aLineBuf, sizeof(aLineBuf), "%s \"%s\"", #ScriptName, aEscapeBuf); \
WriteLine(aLineBuf); \
}
#include "config_variables.h"
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
for(int i = 0; i < m_NumCallbacks; i++)
m_aCallbacks[i].m_pfnFunc(this, m_aCallbacks[i].m_pUserData);
for(const auto &Command : m_vUnknownCommands)
char aLineBuf[2048];
for(const SConfigVariable *pVariable : m_vpAllVariables)
{
WriteLine(Command.c_str());
if((pVariable->m_Flags & CFGFLAG_SAVE) != 0 && !pVariable->IsDefault())
{
pVariable->Serialize(aLineBuf, sizeof(aLineBuf));
WriteLine(aLineBuf);
}
}
for(const auto &Callback : m_vCallbacks)
{
Callback.m_pfnFunc(this, Callback.m_pUserData);
}
for(const char *pCommand : m_vpUnknownCommands)
{
WriteLine(pCommand);
}
if(io_sync(m_ConfigFile) != 0)
@ -127,13 +508,13 @@ bool CConfigManager::Save()
if(m_Failed)
{
dbg_msg("config", "ERROR: writing to %s failed", aConfigFileTmp);
log_error("config", "ERROR: writing to %s failed", aConfigFileTmp);
return false;
}
if(!m_pStorage->RenameFile(aConfigFileTmp, CONFIG_FILE, IStorage::TYPE_SAVE))
{
dbg_msg("config", "ERROR: renaming %s to " CONFIG_FILE " failed", aConfigFileTmp);
log_error("config", "ERROR: renaming %s to " CONFIG_FILE " failed", aConfigFileTmp);
return false;
}
@ -142,10 +523,7 @@ bool CConfigManager::Save()
void CConfigManager::RegisterCallback(SAVECALLBACKFUNC pfnFunc, void *pUserData)
{
dbg_assert(m_NumCallbacks < MAX_CALLBACKS, "too many config callbacks");
m_aCallbacks[m_NumCallbacks].m_pfnFunc = pfnFunc;
m_aCallbacks[m_NumCallbacks].m_pUserData = pUserData;
m_NumCallbacks++;
m_vCallbacks.emplace_back(pfnFunc, pUserData);
}
void CConfigManager::WriteLine(const char *pLine)
@ -160,7 +538,76 @@ void CConfigManager::WriteLine(const char *pLine)
void CConfigManager::StoreUnknownCommand(const char *pCommand)
{
m_vUnknownCommands.emplace_back(pCommand);
m_vpUnknownCommands.push_back(m_ConfigHeap.StoreString(pCommand));
}
void CConfigManager::Con_Reset(IConsole::IResult *pResult, void *pUserData)
{
static_cast<CConfigManager *>(pUserData)->Reset(pResult->GetString(0));
}
void CConfigManager::Con_Toggle(IConsole::IResult *pResult, void *pUserData)
{
CConfigManager *pConfigManager = static_cast<CConfigManager *>(pUserData);
IConsole *pConsole = pConfigManager->m_pConsole;
const char *pScriptName = pResult->GetString(0);
for(SConfigVariable *pVariable : pConfigManager->m_vpAllVariables)
{
if((pVariable->m_Flags & pConsole->FlagMask()) == 0 ||
str_comp(pScriptName, pVariable->m_pScriptName) != 0)
{
continue;
}
if(pVariable->m_Type == SConfigVariable::VAR_INT)
{
SIntConfigVariable *pIntVariable = static_cast<SIntConfigVariable *>(pVariable);
pIntVariable->SetValue(*pIntVariable->m_pVariable == pResult->GetInteger(1) ? pResult->GetInteger(2) : pResult->GetInteger(1));
}
else if(pVariable->m_Type == SConfigVariable::VAR_COLOR)
{
SColorConfigVariable *pColorVariable = static_cast<SColorConfigVariable *>(pVariable);
const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f;
const ColorHSLA Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light);
pColorVariable->SetValue(Value.Pack(Darkest, pColorVariable->m_Alpha));
}
else if(pVariable->m_Type == SConfigVariable::VAR_STRING)
{
SStringConfigVariable *pStringVariable = static_cast<SStringConfigVariable *>(pVariable);
pStringVariable->SetValue(str_comp(pStringVariable->m_pStr, pResult->GetString(1)) == 0 ? pResult->GetString(2) : pResult->GetString(1));
}
return;
}
char aBuf[IConsole::CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Invalid command: '%s'.", pScriptName);
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
void CConfigManager::Con_ToggleStroke(IConsole::IResult *pResult, void *pUserData)
{
CConfigManager *pConfigManager = static_cast<CConfigManager *>(pUserData);
IConsole *pConsole = pConfigManager->m_pConsole;
const char *pScriptName = pResult->GetString(1);
for(SConfigVariable *pVariable : pConfigManager->m_vpAllVariables)
{
if((pVariable->m_Flags & pConsole->FlagMask()) == 0 ||
pVariable->m_Type != SConfigVariable::VAR_INT ||
str_comp(pScriptName, pVariable->m_pScriptName) != 0)
{
continue;
}
SIntConfigVariable *pIntVariable = static_cast<SIntConfigVariable *>(pVariable);
pIntVariable->SetValue(pResult->GetInteger(0) == 0 ? pResult->GetInteger(3) : pResult->GetInteger(2));
return;
}
char aBuf[IConsole::CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Invalid command: '%s'.", pScriptName);
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
}
IConfigManager *CreateConfigManager() { return new CConfigManager; }

View file

@ -4,9 +4,11 @@
#define ENGINE_SHARED_CONFIG_H
#include <base/detect.h>
#include <engine/config.h>
#include <string>
#include <engine/config.h>
#include <engine/console.h>
#include <engine/shared/memheap.h>
#include <vector>
// include protocol for MAX_CLIENT used in config_variables
@ -20,13 +22,13 @@
class CConfig
{
public:
#define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Save, Desc) \
#define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Flags, Desc) \
static constexpr int ms_##Name = Def; \
int m_##Name;
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Save, Desc) \
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) \
static constexpr unsigned ms_##Name = Def; \
unsigned m_##Name;
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Save, Desc) \
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \
static constexpr const char *ms_p##Name = Def; \
char m_##Name[Len]; // Flawfinder: ignore
#include "config_variables.h"
@ -58,31 +60,41 @@ enum
class CConfigManager : public IConfigManager
{
enum
{
MAX_CALLBACKS = 16
};
IConsole *m_pConsole;
class IStorage *m_pStorage;
struct CCallback
IOHANDLE m_ConfigFile;
bool m_Failed;
struct SCallback
{
SAVECALLBACKFUNC m_pfnFunc;
void *m_pUserData;
SCallback(SAVECALLBACKFUNC pfnFunc, void *pUserData) :
m_pfnFunc(pfnFunc),
m_pUserData(pUserData)
{
}
};
std::vector<SCallback> m_vCallbacks;
class IStorage *m_pStorage;
IOHANDLE m_ConfigFile;
bool m_Failed;
CCallback m_aCallbacks[MAX_CALLBACKS];
int m_NumCallbacks;
std::vector<struct SConfigVariable *> m_vpAllVariables;
std::vector<struct SConfigVariable *> m_vpGameVariables;
std::vector<const char *> m_vpUnknownCommands;
CHeap m_ConfigHeap;
std::vector<std::string> m_vUnknownCommands;
static void Con_Reset(IConsole::IResult *pResult, void *pUserData);
static void Con_Toggle(IConsole::IResult *pResult, void *pUserData);
static void Con_ToggleStroke(IConsole::IResult *pResult, void *pUserData);
public:
CConfigManager();
void Init() override;
void Reset() override;
void Reset(const char *pScriptName) override;
void ResetGameSettings() override;
void SetReadOnly(const char *pScriptName, bool ReadOnly) override;
bool Save() override;
CConfig *Values() override { return &g_Config; }

View file

@ -459,7 +459,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
{
if(Stroke)
{
char aBuf[96];
char aBuf[CMDLINE_LENGTH + 64];
str_format(aBuf, sizeof(aBuf), "Command '%s' cannot be executed from a map.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
@ -468,7 +468,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
{
if(Stroke)
{
char aBuf[96];
char aBuf[CMDLINE_LENGTH + 64];
str_format(aBuf, sizeof(aBuf), "Command '%s' cannot be executed from a non-map config file.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
str_format(aBuf, sizeof(aBuf), "Hint: Put the command in '%s.cfg' instead of '%s.map.cfg' ", g_Config.m_SvMap, g_Config.m_SvMap);
@ -489,8 +489,8 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
{
if(ParseArgs(&Result, pCommand->m_pParams))
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Invalid arguments... Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
char aBuf[TEMPCMD_NAME_LENGTH + TEMPCMD_PARAMS_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
}
else if(m_StoreCommands && pCommand->m_Flags & CFGFLAG_STORE)
@ -532,7 +532,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
}
else if(Stroke)
{
char aBuf[256];
char aBuf[CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "Access for command %s denied.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
@ -543,7 +543,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID, bo
// ends at the first whitespace, which breaks for unknown commands (filenames) containing spaces.
if(!m_pfnUnknownCommandCallback(pStr, m_pUnknownCommandUserdata))
{
char aBuf[512 + 32];
char aBuf[CMDLINE_LENGTH + 32];
str_format(aBuf, sizeof(aBuf), "No such command: %s.", Result.m_pCommand);
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
}
@ -655,15 +655,10 @@ void CConsole::Con_Exec(IResult *pResult, void *pUserData)
((CConsole *)pUserData)->ExecuteFile(pResult->GetString(0), -1, true, IStorage::TYPE_ALL);
}
void CConsole::Con_Reset(IResult *pResult, void *pUserData)
{
((CConsole *)pUserData)->ConfigManager()->Reset(pResult->GetString(0));
}
void CConsole::ConCommandAccess(IResult *pResult, void *pUser)
{
CConsole *pConsole = static_cast<CConsole *>(pUser);
char aBuf[128];
char aBuf[CMDLINE_LENGTH + 64];
CCommand *pCommand = pConsole->FindCommand(pResult->GetString(0), CFGFLAG_SERVER);
if(pCommand)
{
@ -738,136 +733,6 @@ void CConsole::ConUserCommandStatus(IResult *pResult, void *pUser)
pConsole->ConCommandStatus(&Result, pConsole);
}
struct CIntVariableData
{
IConsole *m_pConsole;
int *m_pVariable;
int m_Min;
int m_Max;
int m_OldValue;
};
struct CColVariableData
{
IConsole *m_pConsole;
unsigned *m_pVariable;
bool m_Light;
bool m_Alpha;
unsigned m_OldValue;
};
struct CStrVariableData
{
IConsole *m_pConsole;
char *m_pStr;
int m_MaxSize;
char *m_pOldValue;
};
static void IntVariableCommand(IConsole::IResult *pResult, void *pUserData)
{
CIntVariableData *pData = (CIntVariableData *)pUserData;
if(pResult->NumArguments())
{
int Val = pResult->GetInteger(0);
// do clamping
if(pData->m_Min != pData->m_Max)
{
if(Val < pData->m_Min)
Val = pData->m_Min;
if(pData->m_Max != 0 && Val > pData->m_Max)
Val = pData->m_Max;
}
*(pData->m_pVariable) = Val;
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
pData->m_OldValue = Val;
}
else
{
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "Value: %d", *(pData->m_pVariable));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
}
static void ColVariableCommand(IConsole::IResult *pResult, void *pUserData)
{
CColVariableData *pData = (CColVariableData *)pUserData;
if(pResult->NumArguments())
{
ColorHSLA Col = pResult->GetColor(0, pData->m_Light);
int Val = Col.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
*(pData->m_pVariable) = Val;
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
pData->m_OldValue = Val;
}
else
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "Value: %u", *(pData->m_pVariable));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
ColorHSLA Hsla(*(pData->m_pVariable), true);
if(pData->m_Light)
Hsla = Hsla.UnclampLighting();
str_format(aBuf, sizeof(aBuf), "H: %d°, S: %d%%, L: %d%%", round_truncate(Hsla.h * 360), round_truncate(Hsla.s * 100), round_truncate(Hsla.l * 100));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
ColorRGBA Rgba = color_cast<ColorRGBA>(Hsla);
str_format(aBuf, sizeof(aBuf), "R: %d, G: %d, B: %d, #%06X", round_truncate(Rgba.r * 255), round_truncate(Rgba.g * 255), round_truncate(Rgba.b * 255), Rgba.Pack(false));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
if(pData->m_Alpha)
{
str_format(aBuf, sizeof(aBuf), "A: %d%%", round_truncate(Hsla.a * 100));
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
}
}
static void StrVariableCommand(IConsole::IResult *pResult, void *pUserData)
{
CStrVariableData *pData = (CStrVariableData *)pUserData;
if(pResult->NumArguments())
{
const char *pString = pResult->GetString(0);
if(!str_utf8_check(pString))
{
char aTemp[4];
int Length = 0;
while(*pString)
{
int Size = str_utf8_encode(aTemp, static_cast<unsigned char>(*pString++));
if(Length + Size < pData->m_MaxSize)
{
mem_copy(pData->m_pStr + Length, aTemp, Size);
Length += Size;
}
else
break;
}
pData->m_pStr[Length] = 0;
}
else
str_copy(pData->m_pStr, pString, pData->m_MaxSize);
if(pResult->m_ClientID != IConsole::CLIENT_ID_GAME)
str_copy(pData->m_pOldValue, pData->m_pStr, pData->m_MaxSize);
}
else
{
char aBuf[1024];
str_format(aBuf, sizeof(aBuf), "Value: %s", pData->m_pStr);
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
}
void CConsole::TraverseChain(FCommandCallback *ppfnCallback, void **ppUserData)
{
while(*ppfnCallback == Con_Chain)
@ -878,85 +743,6 @@ void CConsole::TraverseChain(FCommandCallback *ppfnCallback, void **ppUserData)
}
}
void CConsole::ConToggle(IConsole::IResult *pResult, void *pUser)
{
CConsole *pConsole = static_cast<CConsole *>(pUser);
char aBuf[512 + 32] = {0};
CCommand *pCommand = pConsole->FindCommand(pResult->GetString(0), pConsole->m_FlagMask);
if(pCommand)
{
FCommandCallback pfnCallback = pCommand->m_pfnCallback;
void *pUserData = pCommand->m_pUserData;
TraverseChain(&pfnCallback, &pUserData);
if(pfnCallback == IntVariableCommand)
{
CIntVariableData *pData = static_cast<CIntVariableData *>(pUserData);
int Val = *(pData->m_pVariable) == pResult->GetInteger(1) ? pResult->GetInteger(2) : pResult->GetInteger(1);
str_format(aBuf, sizeof(aBuf), "%s %i", pResult->GetString(0), Val);
pConsole->ExecuteLine(aBuf);
aBuf[0] = 0;
}
else if(pfnCallback == StrVariableCommand)
{
CStrVariableData *pData = static_cast<CStrVariableData *>(pUserData);
const char *pStr = !str_comp(pData->m_pStr, pResult->GetString(1)) ? pResult->GetString(2) : pResult->GetString(1);
str_format(aBuf, sizeof(aBuf), "%s \"", pResult->GetString(0));
char *pDst = aBuf + str_length(aBuf);
str_escape(&pDst, pStr, aBuf + sizeof(aBuf));
str_append(aBuf, "\"");
pConsole->ExecuteLine(aBuf);
aBuf[0] = 0;
}
else if(pfnCallback == ColVariableCommand)
{
CColVariableData *pData = static_cast<CColVariableData *>(pUserData);
bool Light = pData->m_Light;
float Darkest = Light ? 0.5f : 0.0f;
bool Alpha = pData->m_Alpha;
unsigned Cur = *pData->m_pVariable;
ColorHSLA Val = Cur == pResult->GetColor(1, Light).Pack(Darkest, Alpha) ? pResult->GetColor(2, Light) : pResult->GetColor(1, Light);
str_format(aBuf, sizeof(aBuf), "%s %u", pResult->GetString(0), Val.Pack(Darkest, Alpha));
pConsole->ExecuteLine(aBuf);
aBuf[0] = 0;
}
else
str_format(aBuf, sizeof(aBuf), "Invalid command: '%s'.", pResult->GetString(0));
}
else
str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0));
if(aBuf[0] != 0)
pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
void CConsole::ConToggleStroke(IConsole::IResult *pResult, void *pUser)
{
CConsole *pConsole = static_cast<CConsole *>(pUser);
char aBuf[512 + 32] = {0};
CCommand *pCommand = pConsole->FindCommand(pResult->GetString(1), pConsole->m_FlagMask);
if(pCommand)
{
FCommandCallback pfnCallback = pCommand->m_pfnCallback;
void *pUserData = pCommand->m_pUserData;
TraverseChain(&pfnCallback, &pUserData);
if(pfnCallback == IntVariableCommand)
{
int Val = pResult->GetInteger(0) == 0 ? pResult->GetInteger(3) : pResult->GetInteger(2);
str_format(aBuf, sizeof(aBuf), "%s %i", pResult->GetString(1), Val);
pConsole->ExecuteLine(aBuf);
aBuf[0] = 0;
}
else
str_format(aBuf, sizeof(aBuf), "Invalid command: '%s'.", pResult->GetString(1));
}
else
str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(1));
if(aBuf[0] != 0)
pConsole->Print(OUTPUT_LEVEL_STANDARD, "console", aBuf);
}
CConsole::CConsole(int FlagMask)
{
m_FlagMask = FlagMask;
@ -977,10 +763,6 @@ CConsole::CConsole(int FlagMask)
// register some basic commands
Register("echo", "r[text]", CFGFLAG_SERVER, Con_Echo, this, "Echo the text");
Register("exec", "r[file]", CFGFLAG_SERVER | CFGFLAG_CLIENT, Con_Exec, this, "Execute the specified file");
Register("reset", "s[config-name]", CFGFLAG_SERVER | CFGFLAG_CLIENT | CFGFLAG_STORE, Con_Reset, this, "Reset a config to its default value");
Register("toggle", "s[config-option] i[value 1] i[value 2]", CFGFLAG_SERVER | CFGFLAG_CLIENT, ConToggle, this, "Toggle config value");
Register("+toggle", "s[config-option] i[value 1] i[value 2]", CFGFLAG_CLIENT, ConToggleStroke, this, "Toggle config value via keypress");
Register("access_level", "s[command] ?i[accesslevel]", CFGFLAG_SERVER, ConCommandAccess, this, "Specify command accessibility (admin = 0, moderator = 1, helper = 2, all = 3)");
Register("access_status", "i[accesslevel]", CFGFLAG_SERVER, ConCommandStatus, this, "List all commands which are accessible for admin = 0, moderator = 1, helper = 2, all = 3");
@ -1018,39 +800,7 @@ CConsole::~CConsole()
void CConsole::Init()
{
m_pConfigManager = Kernel()->RequestInterface<IConfigManager>();
m_pConfig = m_pConfigManager->Values();
m_pStorage = Kernel()->RequestInterface<IStorage>();
// TODO: this should disappear
#define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Flags, Desc) \
{ \
static CIntVariableData Data = {this, &g_Config.m_##Name, Min, Max, Def}; \
Register(#ScriptName, "?i", Flags, IntVariableCommand, &Data, \
Min == Max ? Desc " (default: " #Def ")" : Max == 0 ? Desc " (default: " #Def ", min: " #Min ")" : Desc " (default: " #Def ", min: " #Min ", max: " #Max ")"); \
}
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) \
{ \
static CColVariableData Data = {this, &g_Config.m_##Name, static_cast<bool>((Flags)&CFGFLAG_COLLIGHT), \
static_cast<bool>((Flags)&CFGFLAG_COLALPHA), Def}; \
Register(#ScriptName, "?i", Flags, ColVariableCommand, &Data, Desc " (default: " #Def ")"); \
}
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \
{ \
static char s_aOldValue[Len] = Def; \
static CStrVariableData Data = {this, g_Config.m_##Name, Len, s_aOldValue}; \
static char s_aHelp[256]; \
str_format(s_aHelp, sizeof(s_aHelp), "%s (default: \"%s\", max length: %d)", Desc, Def, Len - 1); \
Register(#ScriptName, "?r", Flags, StrVariableCommand, &Data, s_aHelp); \
}
#include "config_variables.h"
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
}
void CConsole::ParseArguments(int NumArgs, const char **ppArguments)
@ -1274,54 +1024,6 @@ const IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int Fl
std::unique_ptr<IConsole> CreateConsole(int FlagMask) { return std::make_unique<CConsole>(FlagMask); }
void CConsole::ResetGameSettings()
{
#define MACRO_CONFIG_INT(Name, ScriptName, Def, Min, Max, Flags, Desc) \
{ \
if(((Flags)&CFGFLAG_GAME) == CFGFLAG_GAME) \
{ \
CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_GAME); \
void *pUserData = pCommand->m_pUserData; \
FCommandCallback pfnCallback = pCommand->m_pfnCallback; \
TraverseChain(&pfnCallback, &pUserData); \
CIntVariableData *pData = (CIntVariableData *)pUserData; \
*pData->m_pVariable = pData->m_OldValue; \
} \
}
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) \
{ \
if(((Flags)&CFGFLAG_GAME) == CFGFLAG_GAME) \
{ \
CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_GAME); \
void *pUserData = pCommand->m_pUserData; \
FCommandCallback pfnCallback = pCommand->m_pfnCallback; \
TraverseChain(&pfnCallback, &pUserData); \
CColVariableData *pData = (CColVariableData *)pUserData; \
*pData->m_pVariable = pData->m_OldValue; \
} \
}
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \
{ \
if(((Flags)&CFGFLAG_GAME) == CFGFLAG_GAME) \
{ \
CCommand *pCommand = FindCommand(#ScriptName, CFGFLAG_GAME); \
void *pUserData = pCommand->m_pUserData; \
FCommandCallback pfnCallback = pCommand->m_pfnCallback; \
TraverseChain(&pfnCallback, &pUserData); \
CStrVariableData *pData = (CStrVariableData *)pUserData; \
str_copy(pData->m_pStr, pData->m_pOldValue, pData->m_MaxSize); \
} \
}
#include "config_variables.h"
#undef MACRO_CONFIG_INT
#undef MACRO_CONFIG_COL
#undef MACRO_CONFIG_STR
}
int CConsole::CResult::GetVictim() const
{
return m_Victim;

View file

@ -46,8 +46,6 @@ class CConsole : public IConsole
};
CExecFile *m_pFirstExec;
IConfigManager *m_pConfigManager;
CConfig *m_pConfig;
IStorage *m_pStorage;
int m_AccessLevel;
@ -59,9 +57,6 @@ class CConsole : public IConsole
static void Con_Chain(IResult *pResult, void *pUserData);
static void Con_Echo(IResult *pResult, void *pUserData);
static void Con_Exec(IResult *pResult, void *pUserData);
static void Con_Reset(IResult *pResult, void *pUserData);
static void ConToggle(IResult *pResult, void *pUser);
static void ConToggleStroke(IResult *pResult, void *pUser);
static void ConCommandAccess(IResult *pResult, void *pUser);
static void ConCommandStatus(IConsole::IResult *pResult, void *pUser);
@ -194,9 +189,6 @@ class CConsole : public IConsole
bool m_Cheated;
public:
IConfigManager *ConfigManager() { return m_pConfigManager; }
CConfig *Config() { return m_pConfig; }
CConsole(int FlagMask);
~CConsole();
@ -225,7 +217,7 @@ public:
void InitChecksum(CChecksumData *pData) const override;
void SetAccessLevel(int AccessLevel) override { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_USER)); }
void ResetGameSettings() override;
// DDRace
static void ConUserCommandStatus(IConsole::IResult *pResult, void *pUser);

View file

@ -227,7 +227,7 @@ void CGameConsole::CInstance::PossibleArgumentsCompleteCallback(int Index, const
if(pInstance->m_CompletionChosenArgument == Index)
{
// get command
char aBuf[512];
char aBuf[IConsole::CMDLINE_LENGTH];
StrCopyUntilSpace(aBuf, sizeof(aBuf), pInstance->GetString());
str_append(aBuf, " ");
@ -256,7 +256,7 @@ bool CGameConsole::CInstance::OnInput(const IInput::CEvent &Event)
str_copy(pEntry, m_Input.GetString(), m_Input.GetLength() + 1);
}
// print out the user's commands before they get run
char aBuf[256];
char aBuf[IConsole::CMDLINE_LENGTH + 3];
str_format(aBuf, sizeof(aBuf), "> %s", m_Input.GetString());
m_pGameConsole->PrintLine(m_Type, aBuf);
}
@ -400,7 +400,7 @@ bool CGameConsole::CInstance::OnInput(const IInput::CEvent &Event)
// find the current command
{
char aBuf[512];
char aBuf[IConsole::CMDLINE_LENGTH];
StrCopyUntilSpace(aBuf, sizeof(aBuf), GetString());
const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask,
m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands());

View file

@ -40,7 +40,7 @@ class CGameConsole : public CComponent
CStaticRingBuffer<char, 64 * 1024, CRingBufferBase::FLAG_RECYCLE> m_History;
char *m_pHistoryEntry;
CLineInputBuffered<512> m_Input;
CLineInputBuffered<IConsole::CMDLINE_LENGTH> m_Input;
const char *m_pName;
int m_Type;
int m_BacklogCurPage;
@ -59,9 +59,9 @@ class CGameConsole : public CComponent
CGameConsole *m_pGameConsole;
char m_aCompletionBuffer[128];
char m_aCompletionBuffer[IConsole::CMDLINE_LENGTH];
int m_CompletionChosen;
char m_aCompletionBufferArgument[128];
char m_aCompletionBufferArgument[IConsole::CMDLINE_LENGTH];
int m_CompletionChosenArgument;
int m_CompletionFlagmask;
float m_CompletionRenderOffset;

View file

@ -530,7 +530,7 @@ void CGameClient::OnConnected()
m_GameWorld.m_WorldConfig.m_InfiniteAmmo = true;
mem_zero(&m_GameInfo, sizeof(m_GameInfo));
m_PredictedDummyID = -1;
Console()->ResetGameSettings();
ConfigManager()->ResetGameSettings();
LoadMapSettings();
if(Client()->State() != IClient::STATE_DEMOPLAYBACK && g_Config.m_ClAutoDemoOnConnect)

View file

@ -3422,7 +3422,8 @@ void CGameContext::ConchainSettingUpdate(IConsole::IResult *pResult, void *pUser
void CGameContext::OnConsoleInit()
{
m_pServer = Kernel()->RequestInterface<IServer>();
m_pConfig = Kernel()->RequestInterface<IConfigManager>()->Values();
m_pConfigManager = Kernel()->RequestInterface<IConfigManager>();
m_pConfig = m_pConfigManager->Values();
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_pEngine = Kernel()->RequestInterface<IEngine>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
@ -3477,7 +3478,8 @@ void CGameContext::OnInit(const void *pPersistentData)
const CPersistentData *pPersistent = (const CPersistentData *)pPersistentData;
m_pServer = Kernel()->RequestInterface<IServer>();
m_pConfig = Kernel()->RequestInterface<IConfigManager>()->Values();
m_pConfigManager = Kernel()->RequestInterface<IConfigManager>();
m_pConfig = m_pConfigManager->Values();
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_pEngine = Kernel()->RequestInterface<IEngine>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
@ -3949,7 +3951,7 @@ void CGameContext::OnShutdown(void *pPersistentData)
}
DeleteTempfile();
Console()->ResetGameSettings();
ConfigManager()->ResetGameSettings();
Collision()->Dest();
delete m_pController;
m_pController = 0;

View file

@ -47,6 +47,7 @@ enum
};
class CCharacter;
class IConfigManager;
class CConfig;
class CHeap;
class CPlayer;
@ -77,6 +78,7 @@ private:
class CGameContext : public IGameServer
{
IServer *m_pServer;
IConfigManager *m_pConfigManager;
CConfig *m_pConfig;
IConsole *m_pConsole;
IEngine *m_pEngine;
@ -155,6 +157,7 @@ class CGameContext : public IGameServer
public:
IServer *Server() const { return m_pServer; }
IConfigManager *ConfigManager() const { return m_pConfigManager; }
CConfig *Config() { return m_pConfig; }
IConsole *Console() { return m_pConsole; }
IEngine *Engine() { return m_pEngine; }

View file

@ -157,7 +157,7 @@ void CTeeHistorian::WriteHeader(const CGameInfo *pGameInfo)
First = false; \
}
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Save, Desc) MACRO_CONFIG_INT(Name, ScriptName, Def, 0, 0, Save, Desc)
#define MACRO_CONFIG_COL(Name, ScriptName, Def, Flags, Desc) MACRO_CONFIG_INT(Name, ScriptName, Def, 0, 0, Flags, Desc)
#define MACRO_CONFIG_STR(Name, ScriptName, Len, Def, Flags, Desc) \
if((Flags)&CFGFLAG_SERVER && !((Flags)&CFGFLAG_NONTEEHISTORIC) && str_comp(pGameInfo->m_pConfig->m_##Name, (Def)) != 0) \