[Dvar]: Protect saved dvars by default (#694)

This commit is contained in:
Edo 2023-01-03 09:23:08 +00:00 committed by GitHub
parent 9f39834090
commit 406499d919
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 6 additions and 48 deletions

View File

@ -39,7 +39,7 @@
| `-version` | Print IW4x build info on startup. | | `-version` | Print IW4x build info on startup. |
| `-zonebuilder` | Start the interactive zonebuilder tool console instead of starting the game. | | `-zonebuilder` | Start the interactive zonebuilder tool console instead of starting the game. |
| `-nosteam` | Disable friends feature and do not update Steam about the game's current status just like an invisible mode. | | `-nosteam` | Disable friends feature and do not update Steam about the game's current status just like an invisible mode. |
| `-protect-saved-dvars` | Block the server from modifying saved/archive dvars. | | `-unprotect-dvars` | Allow the server to modify saved/archive dvars. |
## Disclaimer ## Disclaimer

View File

@ -2,14 +2,11 @@
namespace Components namespace Components
{ {
const char* Dvar::ArchiveDvarPath = "userraw/archivedvars.cfg";
Dvar::Var Dvar::Name; Dvar::Var Dvar::Name;
Dvar::Var::Var(const std::string& dvarName) Dvar::Var::Var(const std::string& dvarName)
: dvar_(Game::Dvar_FindVar(dvarName.data()))
{ {
this->dvar_ = Game::Dvar_FindVar(dvarName.data());
// If the dvar can't be found it will be registered as an empty string dvar // If the dvar can't be found it will be registered as an empty string dvar
if (this->dvar_ == nullptr) if (this->dvar_ == nullptr)
{ {
@ -206,16 +203,6 @@ namespace Components
return Game::Dvar_RegisterFloat(dvarName, value, min, max, flag, description); return Game::Dvar_RegisterFloat(dvarName, value, min, max, flag, description);
} }
void Dvar::ResetDvarsValue()
{
if (!Utils::IO::FileExists(ArchiveDvarPath))
return;
Command::Execute("exec archivedvars.cfg", true);
// Clean up
Utils::IO::RemoveFile(ArchiveDvarPath);
}
Game::dvar_t* Dvar::Dvar_RegisterName(const char* name, const char* /*default*/, std::uint16_t flags, const char* description) Game::dvar_t* Dvar::Dvar_RegisterName(const char* name, const char* /*default*/, std::uint16_t flags, const char* description)
{ {
// Name watcher // Name watcher
@ -291,44 +278,31 @@ namespace Components
Game::Dvar_SetFromStringByNameFromSource(dvarName, string, Game::DVAR_SOURCE_EXTERNAL); Game::Dvar_SetFromStringByNameFromSource(dvarName, string, Game::DVAR_SOURCE_EXTERNAL);
} }
bool Dvar::AreArchiveDvarsProtected() bool Dvar::AreArchiveDvarsUnprotected()
{ {
static std::optional<bool> flag; static std::optional<bool> flag;
if (!flag.has_value()) if (!flag.has_value())
{ {
flag.emplace(Flags::HasFlag("protect-saved-dvars")); flag.emplace(Flags::HasFlag("unprotect-dvars"));
} }
return flag.value(); return flag.value();
} }
void Dvar::SaveArchiveDvar(const Game::dvar_t* var)
{
if (!Utils::IO::FileExists(ArchiveDvarPath))
{
Utils::IO::WriteFile(ArchiveDvarPath, "// generated by IW4x, do not modify\n", false);
}
Utils::IO::WriteFile(ArchiveDvarPath, std::format("set {} \"{}\"\n", var->name, Game::Dvar_DisplayableValue(var)), true);
}
void Dvar::DvarSetFromStringByName_Stub(const char* dvarName, const char* value) void Dvar::DvarSetFromStringByName_Stub(const char* dvarName, const char* value)
{ {
// Save the dvar original value if it has the archive flag // Save the dvar original value if it has the archive flag
const auto* dvar = Game::Dvar_FindVar(dvarName); const auto* dvar = Game::Dvar_FindVar(dvarName);
if (dvar != nullptr && dvar->flags & Game::DVAR_ARCHIVE) if (dvar != nullptr && dvar->flags & Game::DVAR_ARCHIVE)
{ {
if (AreArchiveDvarsProtected()) if (!AreArchiveDvarsUnprotected())
{ {
Logger::Print(Game::CON_CHANNEL_CONSOLEONLY, "Not allowing server to override saved dvar '{}'\n", dvar->name); Logger::Print(Game::CON_CHANNEL_CONSOLEONLY, "Not allowing server to override saved dvar '{}'\n", dvar->name);
return; return;
} }
#ifdef DEBUG_DVARS
Logger::Print(Game::CON_CHANNEL_CONSOLEONLY, "Server is overriding saved dvar '{}'\n", dvarName); Logger::Print(Game::CON_CHANNEL_CONSOLEONLY, "Server is overriding saved dvar '{}'\n", dvarName);
#endif
SaveArchiveDvar(dvar);
} }
if (dvar != nullptr && std::strcmp(dvar->name, "com_errorResolveCommand") == 0) if (dvar != nullptr && std::strcmp(dvar->name, "com_errorResolveCommand") == 0)
@ -467,12 +441,6 @@ namespace Components
// Hook Dvar_SetFromStringByName inside CG_SetClientDvarFromServer so we can reset dvars when the player leaves the server // Hook Dvar_SetFromStringByName inside CG_SetClientDvarFromServer so we can reset dvars when the player leaves the server
Utils::Hook(0x59386A, DvarSetFromStringByName_Stub, HOOK_CALL).install()->quick(); Utils::Hook(0x59386A, DvarSetFromStringByName_Stub, HOOK_CALL).install()->quick();
// If the game closed abruptly, the dvars would not have been restored
Scheduler::Once(ResetDvarsValue, Scheduler::Pipeline::MAIN);
// Reset archive dvars when client leaves a server
Events::OnSteamDisconnect(ResetDvarsValue);
// For debugging // For debugging
Utils::Hook(0x6483FA, Dvar_RegisterVariant_Stub, HOOK_JUMP).install()->quick(); Utils::Hook(0x6483FA, Dvar_RegisterVariant_Stub, HOOK_JUMP).install()->quick();
Utils::Hook(0x648438, Dvar_RegisterVariant_Stub, HOOK_JUMP).install()->quick(); Utils::Hook(0x648438, Dvar_RegisterVariant_Stub, HOOK_JUMP).install()->quick();
@ -480,9 +448,4 @@ namespace Components
// Fix crash // Fix crash
Utils::Hook(0x4B7120, Dvar_EnumToString_Stub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4B7120, Dvar_EnumToString_Stub, HOOK_JUMP).install()->quick();
} }
Dvar::~Dvar()
{
Utils::IO::RemoveFile(ArchiveDvarPath);
}
} }

View File

@ -32,16 +32,12 @@ namespace Components
}; };
Dvar(); Dvar();
~Dvar();
// Only strings and bools use this type of declaration // Only strings and bools use this type of declaration
template<typename T> static Var Register(const char* dvarName, T value, std::uint16_t flag, const char* description); template<typename T> static Var Register(const char* dvarName, T value, std::uint16_t flag, const char* description);
template<typename T> static Var Register(const char* dvarName, T value, T min, T max, std::uint16_t flag, const char* description); template<typename T> static Var Register(const char* dvarName, T value, T min, T max, std::uint16_t flag, const char* description);
static void ResetDvarsValue();
private: private:
static const char* ArchiveDvarPath;
static Var Name; static Var Name;
static Game::dvar_t* Dvar_RegisterName(const char* name, const char* defaultVal, std::uint16_t flags, const char* description); static Game::dvar_t* Dvar_RegisterName(const char* name, const char* defaultVal, std::uint16_t flags, const char* description);
@ -49,8 +45,7 @@ namespace Components
static void SetFromStringByNameExternal(const char* dvarName, const char* string); static void SetFromStringByNameExternal(const char* dvarName, const char* string);
static void SetFromStringByNameSafeExternal(const char* dvarName, const char* string); static void SetFromStringByNameSafeExternal(const char* dvarName, const char* string);
static bool AreArchiveDvarsProtected(); static bool AreArchiveDvarsUnprotected();
static void SaveArchiveDvar(const Game::dvar_t* var);
static void DvarSetFromStringByName_Stub(const char* dvarName, const char* value); static void DvarSetFromStringByName_Stub(const char* dvarName, const char* value);
static void OnRegisterVariant(Game::dvar_t* dvar); static void OnRegisterVariant(Game::dvar_t* dvar);