From 159ddf553462f0f7822d3d1df3fdf84e25b4cbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 22 Nov 2023 23:07:08 +0100 Subject: [PATCH] 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. --- src/engine/client/client.cpp | 2 +- src/engine/config.h | 3 +- src/engine/console.h | 4 +- src/engine/server/main.cpp | 6 +- src/engine/server/server.cpp | 16 - src/engine/server/server.h | 2 - src/engine/shared/config.cpp | 585 ++++++++++++++++++++++--- src/engine/shared/config.h | 46 +- src/engine/shared/console.cpp | 312 +------------ src/engine/shared/console.h | 10 +- src/game/client/components/console.cpp | 6 +- src/game/client/components/console.h | 6 +- src/game/client/gameclient.cpp | 2 +- src/game/server/gamecontext.cpp | 8 +- src/game/server/gamecontext.h | 3 + src/game/server/teehistorian.cpp | 2 +- 16 files changed, 577 insertions(+), 436 deletions(-) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index e16d3097b..5d834d014 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -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(); diff --git a/src/engine/config.h b/src/engine/config.h index 79b5b3257..bccf50437 100644 --- a/src/engine/config.h +++ b/src/engine/config.h @@ -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; diff --git a/src/engine/console.h b/src/engine/console.h index ecbd80660..774e06358 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -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); diff --git a/src/engine/server/main.cpp b/src/engine/server/main.cpp index 2f12200ab..ea1987531 100644 --- a/src/engine/server/main.cpp +++ b/src/engine/server/main.cpp @@ -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]) diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 359363a69..b6fff9c1f 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -3096,22 +3096,6 @@ int CServer::Run() return ErrorShutdown(); } -void CServer::ConTestingCommands(CConsole::IResult *pResult, void *pUser) -{ - CConsole *pThis = static_cast(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(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) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 4c9e55922..6b0b3708a 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -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); diff --git a/src/engine/shared/config.cpp b/src/engine/shared/config.cpp index ce930d27f..b262c493a 100644 --- a/src/engine/shared/config.cpp +++ b/src/engine/shared/config.cpp @@ -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 + #include #include +#include #include #include 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(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(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(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(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(*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(); m_pStorage = Kernel()->RequestInterface(); - 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(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(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(ColorHSLA(Def, Alpha)).Pack(Alpha)); \ + AddVariable(m_ConfigHeap.Allocate(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(m_ConfigHeap.Allocate(HelpSize)); \ + str_format(pHelp, HelpSize, "%s (default: \"%s\", max length: %d)", Desc, Def, Len - 1); \ + char *pOldValue = static_cast(m_ConfigHeap.Allocate(Len)); \ + AddVariable(m_ConfigHeap.Allocate(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(pUserData)->Reset(pResult->GetString(0)); +} + +void CConfigManager::Con_Toggle(IConsole::IResult *pResult, void *pUserData) +{ + CConfigManager *pConfigManager = static_cast(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(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(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(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(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(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; } diff --git a/src/engine/shared/config.h b/src/engine/shared/config.h index 63c640fb6..826c0dd61 100644 --- a/src/engine/shared/config.h +++ b/src/engine/shared/config.h @@ -4,9 +4,11 @@ #define ENGINE_SHARED_CONFIG_H #include -#include -#include +#include +#include +#include + #include // 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 m_vCallbacks; - class IStorage *m_pStorage; - IOHANDLE m_ConfigFile; - bool m_Failed; - CCallback m_aCallbacks[MAX_CALLBACKS]; - int m_NumCallbacks; + std::vector m_vpAllVariables; + std::vector m_vpGameVariables; + std::vector m_vpUnknownCommands; + CHeap m_ConfigHeap; - std::vector 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; } diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 39b2bae35..f89bf6810 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -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(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(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(*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(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(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(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(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(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(); - m_pConfig = m_pConfigManager->Values(); m_pStorage = Kernel()->RequestInterface(); - -// 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((Flags)&CFGFLAG_COLLIGHT), \ - static_cast((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 CreateConsole(int FlagMask) { return std::make_unique(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; diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index d16770c46..f5c4c97ea 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -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); diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index f6458dc53..7c2ae0470 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -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()); diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index b088f0642..cadaefd95 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -40,7 +40,7 @@ class CGameConsole : public CComponent CStaticRingBuffer m_History; char *m_pHistoryEntry; - CLineInputBuffered<512> m_Input; + CLineInputBuffered 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; diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 5cd59e236..10db53574 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -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) diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 2f7cf788b..f81ca1af6 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -3422,7 +3422,8 @@ void CGameContext::ConchainSettingUpdate(IConsole::IResult *pResult, void *pUser void CGameContext::OnConsoleInit() { m_pServer = Kernel()->RequestInterface(); - m_pConfig = Kernel()->RequestInterface()->Values(); + m_pConfigManager = Kernel()->RequestInterface(); + m_pConfig = m_pConfigManager->Values(); m_pConsole = Kernel()->RequestInterface(); m_pEngine = Kernel()->RequestInterface(); m_pStorage = Kernel()->RequestInterface(); @@ -3477,7 +3478,8 @@ void CGameContext::OnInit(const void *pPersistentData) const CPersistentData *pPersistent = (const CPersistentData *)pPersistentData; m_pServer = Kernel()->RequestInterface(); - m_pConfig = Kernel()->RequestInterface()->Values(); + m_pConfigManager = Kernel()->RequestInterface(); + m_pConfig = m_pConfigManager->Values(); m_pConsole = Kernel()->RequestInterface(); m_pEngine = Kernel()->RequestInterface(); m_pStorage = Kernel()->RequestInterface(); @@ -3949,7 +3951,7 @@ void CGameContext::OnShutdown(void *pPersistentData) } DeleteTempfile(); - Console()->ResetGameSettings(); + ConfigManager()->ResetGameSettings(); Collision()->Dest(); delete m_pController; m_pController = 0; diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 02c53a352..b5c30f09e 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -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; } diff --git a/src/game/server/teehistorian.cpp b/src/game/server/teehistorian.cpp index 083ccd65d..355916b02 100644 --- a/src/game/server/teehistorian.cpp +++ b/src/game/server/teehistorian.cpp @@ -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) \