[Dvar]: Protect saved dvars by default (#694)
This commit is contained in:
parent
9f39834090
commit
406499d919
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user