iw4x-client/src/Components/Modules/Dvar.cpp

387 lines
11 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
2017-01-19 16:23:59 -05:00
namespace Components
{
2021-12-04 13:34:19 -05:00
const char* Dvar::ArchiveDvarPath = "userraw/archivedvars.cfg";
2017-01-19 16:23:59 -05:00
2018-12-17 08:29:18 -05:00
Dvar::Var::Var(const std::string& dvarName) : Var()
2017-01-19 16:23:59 -05:00
{
this->dvar = Game::Dvar_FindVar(dvarName.data());
2022-02-03 06:44:35 -05:00
// If the dvar can't be found it will be registered as an empty string dvar
2022-02-19 18:06:56 -05:00
if (this->dvar == nullptr)
2017-01-19 16:23:59 -05:00
{
2022-02-19 18:06:56 -05:00
this->dvar = const_cast<Game::dvar_t*>(Game::Dvar_SetFromStringByNameFromSource(dvarName.data(), "",
2022-02-03 06:44:35 -05:00
Game::DvarSetSource::DVAR_SOURCE_INTERNAL));
2017-01-19 16:23:59 -05:00
}
}
template <> Game::dvar_t* Dvar::Var::get()
{
return this->dvar;
}
2021-09-08 16:54:43 -04:00
template <> const char* Dvar::Var::get()
2017-01-19 16:23:59 -05:00
{
if (this->dvar == nullptr)
return "";
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_STRING
|| this->dvar->type == Game::dvar_type::DVAR_TYPE_ENUM)
2017-01-19 16:23:59 -05:00
{
if (this->dvar->current.string != nullptr)
return this->dvar->current.string;
2017-01-19 16:23:59 -05:00
}
return "";
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> int Dvar::Var::get()
{
2022-02-03 06:44:35 -05:00
if (this->dvar == nullptr)
2022-02-19 18:06:56 -05:00
return 0;
2022-02-03 06:44:35 -05:00
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_INT || this->dvar->type == Game::dvar_type::DVAR_TYPE_ENUM)
2017-01-19 16:23:59 -05:00
{
return this->dvar->current.integer;
}
return 0;
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> unsigned int Dvar::Var::get()
{
2022-02-03 06:44:35 -05:00
if (this->dvar == nullptr)
2022-02-19 18:06:56 -05:00
return 0u;
2022-02-03 06:44:35 -05:00
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_INT)
{
return this->dvar->current.unsignedInt;
}
2022-02-19 18:06:56 -05:00
return 0u;
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> float Dvar::Var::get()
{
2022-02-03 06:44:35 -05:00
if (this->dvar == nullptr)
2022-02-19 18:06:56 -05:00
return 0.f;
2022-02-03 06:44:35 -05:00
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT)
2017-01-19 16:23:59 -05:00
{
return this->dvar->current.value;
}
2022-02-03 06:44:35 -05:00
return 0.f;
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> float* Dvar::Var::get()
{
2022-02-03 06:44:35 -05:00
static Game::vec4_t vector{ 0.f, 0.f, 0.f, 0.f };
2017-01-19 16:23:59 -05:00
2022-02-03 06:44:35 -05:00
if (this->dvar == nullptr)
2022-02-19 18:06:56 -05:00
return vector;
2017-01-19 16:23:59 -05:00
2022-02-19 18:10:35 -05:00
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_2 || this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_3
|| this->dvar->type == Game::dvar_type::DVAR_TYPE_FLOAT_4)
2017-01-19 16:23:59 -05:00
{
2018-05-09 06:04:20 -04:00
return this->dvar->current.vector;
2017-01-19 16:23:59 -05:00
}
2022-02-03 06:44:35 -05:00
return vector;
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> bool Dvar::Var::get()
{
2022-02-03 06:44:35 -05:00
if (this->dvar == nullptr)
2022-02-19 18:06:56 -05:00
return false;
2022-02-03 06:44:35 -05:00
if (this->dvar->type == Game::dvar_type::DVAR_TYPE_BOOL)
2017-01-19 16:23:59 -05:00
{
2018-05-09 06:04:20 -04:00
return this->dvar->current.enabled;
2017-01-19 16:23:59 -05:00
}
return false;
}
2021-09-08 16:54:43 -04:00
2017-01-19 16:23:59 -05:00
template <> std::string Dvar::Var::get()
{
return this->get<const char*>();
}
void Dvar::Var::set(const char* string)
{
assert(this->dvar->type == Game::DVAR_TYPE_STRING);
if (this->dvar)
2017-01-19 16:23:59 -05:00
{
2021-08-31 12:12:25 -04:00
Game::Dvar_SetString(this->dvar, string);
2017-01-19 16:23:59 -05:00
}
}
2021-09-08 16:54:43 -04:00
2018-12-17 08:29:18 -05:00
void Dvar::Var::set(const std::string& string)
2017-01-19 16:23:59 -05:00
{
this->set(string.data());
}
void Dvar::Var::set(int integer)
{
assert(this->dvar->type == Game::DVAR_TYPE_INT);
2017-01-19 16:23:59 -05:00
if (this->dvar)
{
Game::Dvar_SetInt(this->dvar, integer);
2017-01-19 16:23:59 -05:00
}
}
2021-09-09 04:50:49 -04:00
2017-01-19 16:23:59 -05:00
void Dvar::Var::set(float value)
{
assert(this->dvar->type == Game::DVAR_TYPE_FLOAT);
if (this->dvar)
{
Game::Dvar_SetFloat(this->dvar, value);
}
}
void Dvar::Var::set(bool enabled)
{
assert(this->dvar->type == Game::DVAR_TYPE_BOOL);
if (this->dvar)
2017-01-19 16:23:59 -05:00
{
2021-09-09 04:44:04 -04:00
Game::Dvar_SetBool(this->dvar, enabled);
2017-01-19 16:23:59 -05:00
}
}
void Dvar::Var::setRaw(int integer)
{
assert(this->dvar->type == Game::DVAR_TYPE_INT);
2017-01-19 16:23:59 -05:00
if (this->dvar)
{
this->dvar->current.integer = integer;
this->dvar->latched.integer = integer;
2017-01-19 16:23:59 -05:00
}
}
void Dvar::Var::setRaw(float value)
{
assert(this->dvar->type == Game::DVAR_TYPE_FLOAT);
if (this->dvar)
{
this->dvar->current.value = value;
this->dvar->latched.value = value;
}
}
void Dvar::Var::setRaw(bool enabled)
{
assert(this->dvar->type == Game::DVAR_TYPE_BOOL);
if (this->dvar)
{
this->dvar->current.enabled = enabled;
this->dvar->latched.enabled = enabled;
}
}
2022-03-21 18:35:18 -04:00
template<> Dvar::Var Dvar::Register(const char* dvarName, bool value, Dvar::Flag flag, const char* description)
2017-01-19 16:23:59 -05:00
{
return Game::Dvar_RegisterBool(dvarName, value, flag.val, description);
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2022-03-21 18:35:18 -04:00
template<> Dvar::Var Dvar::Register(const char* dvarName, const char* value, Dvar::Flag flag, const char* description)
2017-01-19 16:23:59 -05:00
{
return Game::Dvar_RegisterString(dvarName, value, flag.val, description);
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2022-03-21 18:35:18 -04:00
template<> Dvar::Var Dvar::Register(const char* dvarName, int value, int min, int max, Dvar::Flag flag, const char* description)
2017-01-19 16:23:59 -05:00
{
return Game::Dvar_RegisterInt(dvarName, value, min, max, flag.val, description);
2017-01-19 16:23:59 -05:00
}
2021-09-08 16:54:43 -04:00
2022-03-21 18:35:18 -04:00
template<> Dvar::Var Dvar::Register(const char* dvarName, float value, float min, float max, Dvar::Flag flag, const char* description)
2020-07-22 23:35:42 -04:00
{
return Game::Dvar_RegisterFloat(dvarName, value, min, max, flag.val, description);
2020-07-22 23:35:42 -04:00
}
2017-01-19 16:23:59 -05:00
2021-10-04 16:03:56 -04:00
void Dvar::ResetDvarsValue()
{
2021-12-06 07:27:28 -05:00
if (!Utils::IO::FileExists(Dvar::ArchiveDvarPath))
2022-01-24 14:56:17 -05:00
return;
2021-12-06 07:27:28 -05:00
Command::Execute("exec archivedvars.cfg", true);
// Clean up
2021-12-04 13:34:19 -05:00
Utils::IO::RemoveFile(Dvar::ArchiveDvarPath);
2021-10-04 16:03:56 -04:00
}
Game::dvar_t* Dvar::Dvar_RegisterName(const char* name, const char* /*default*/, unsigned __int16 flags, const char* description)
2017-01-19 16:23:59 -05:00
{
// Name watcher
Scheduler::Loop([]
2017-01-19 16:23:59 -05:00
{
static std::string lastValidName = "Unknown Soldier";
auto name = Dvar::Var("name").get<std::string>();
2017-01-19 16:23:59 -05:00
// Don't perform any checks if name didn't change
if (name == lastValidName) return;
std::string saneName = TextRenderer::StripAllTextIcons(TextRenderer::StripColors(Utils::String::Trim(name)));
2017-01-19 16:23:59 -05:00
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
{
2022-06-12 17:07:53 -04:00
Logger::Print("Username '{}' is invalid. It must at least be 3 characters long and not appear empty!\n", name);
2017-01-19 16:23:59 -05:00
Dvar::Var("name").set(lastValidName);
}
else
{
lastValidName = name;
2017-01-31 11:04:54 -05:00
Friends::UpdateName();
2017-01-19 16:23:59 -05:00
}
}, Scheduler::MAIN, 3s); // Don't need to do this every frame
2017-01-19 16:23:59 -05:00
std::string username = "Unknown Soldier";
if (Steam::Proxy::SteamFriends)
{
const char* steamName = Steam::Proxy::SteamFriends->GetPersonaName();
if (steamName && !std::string(steamName).empty())
{
username = steamName;
}
}
return Dvar::Register<const char*>(name, username.data(), flags | Game::dvar_flag::DVAR_ARCHIVE, description).get<Game::dvar_t*>();
2017-01-19 16:23:59 -05:00
}
2022-02-03 06:44:35 -05:00
void Dvar::SetFromStringByNameSafeExternal(const char* dvarName, const char* string)
{
static const char* exceptions[] =
{
"ui_showEndOfGame",
"systemlink",
"splitscreen",
"onlinegame",
"party_maxplayers",
"xblive_privateserver",
"xblive_rankedmatch",
"ui_mptype",
};
for (std::size_t i = 0; i < ARRAYSIZE(exceptions); ++i)
{
2022-02-03 06:44:35 -05:00
if (Utils::String::ToLower(dvarName) == Utils::String::ToLower(exceptions[i]))
{
2022-02-03 06:44:35 -05:00
Game::Dvar_SetFromStringByNameFromSource(dvarName, string, Game::DvarSetSource::DVAR_SOURCE_INTERNAL);
return;
}
}
2022-02-19 18:10:35 -05:00
Dvar::SetFromStringByNameExternal(dvarName, string);
}
2022-02-03 06:44:35 -05:00
void Dvar::SetFromStringByNameExternal(const char* dvarName, const char* string)
{
2022-02-03 06:44:35 -05:00
Game::Dvar_SetFromStringByNameFromSource(dvarName, string, Game::DvarSetSource::DVAR_SOURCE_EXTERNAL);
}
2021-12-04 13:34:19 -05:00
void Dvar::SaveArchiveDvar(const Game::dvar_t* var)
{
if (!Utils::IO::FileExists(Dvar::ArchiveDvarPath))
{
Utils::IO::WriteFile(Dvar::ArchiveDvarPath,
"// generated by IW4x, do not modify\n");
}
Utils::IO::WriteFile(Dvar::ArchiveDvarPath,
Utils::String::VA("seta %s \"%s\"\n", var->name, Game::Dvar_DisplayableValue(var)), true);
}
void Dvar::DvarSetFromStringByNameStub(const char* dvarName, const char* value)
2021-10-03 16:23:26 -04:00
{
2021-12-04 13:34:19 -05:00
// Save the dvar original value if it has the archive flag
const auto* dvar = Game::Dvar_FindVar(dvarName);
if (dvar != nullptr && dvar->flags & Game::dvar_flag::DVAR_ARCHIVE)
2021-12-04 13:34:19 -05:00
{
Dvar::SaveArchiveDvar(dvar);
}
Utils::Hook::Call<void(const char*, const char*)>(0x4F52E0)(dvarName, value);
2021-10-03 16:23:26 -04:00
}
2017-01-19 16:23:59 -05:00
Dvar::Dvar()
{
// set flags of cg_drawFPS to archive
Utils::Hook::Or<BYTE>(0x4F8F69, Game::dvar_flag::DVAR_ARCHIVE);
2017-01-19 16:23:59 -05:00
// un-cheat camera_thirdPersonCrosshairOffset and add archive flags
Utils::Hook::Xor<BYTE>(0x447B41, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE);
2017-01-19 16:23:59 -05:00
// un-cheat cg_fov and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8E35, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE);
2020-12-04 16:04:50 -05:00
// un-cheat cg_fovscale and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8E68, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE);
2017-01-19 16:23:59 -05:00
// un-cheat cg_debugInfoCornerOffset and add archive flags
Utils::Hook::Xor<BYTE>(0x4F8FC2, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE);
2017-01-19 16:23:59 -05:00
// remove archive flags for cg_hudchatposition
Utils::Hook::Xor<BYTE>(0x4F9992, Game::dvar_flag::DVAR_ARCHIVE);
2017-01-19 16:23:59 -05:00
// remove write protection from fs_game
Utils::Hook::Xor<DWORD>(0x6431EA, Game::dvar_flag::DVAR_WRITEPROTECTED);
2017-01-19 16:23:59 -05:00
2022-03-17 14:50:20 -04:00
// set cg_fov max to 160.0
// because that's the max on SP
static float cg_Fov = 160.0f;
Utils::Hook::Set<float*>(0x4F8E28, &cg_Fov);
2017-01-19 16:23:59 -05:00
// set max volume to 1
static float volume = 1.0f;
Utils::Hook::Set<float*>(0x408078, &volume);
// Uncheat ui_showList
Utils::Hook::Xor<BYTE>(0x6310DC, Game::dvar_flag::DVAR_CHEAT);
2017-01-19 16:23:59 -05:00
// Uncheat ui_debugMode
Utils::Hook::Xor<BYTE>(0x6312DE, Game::dvar_flag::DVAR_CHEAT);
2017-01-19 16:23:59 -05:00
// Hook dvar 'name' registration
Utils::Hook(0x40531C, Dvar::Dvar_RegisterName, HOOK_CALL).install()->quick();
// un-cheat safeArea_* and add archive flags
Utils::Hook::Xor<INT>(0x42E3F5, Game::dvar_flag::DVAR_READONLY | Game::dvar_flag::DVAR_ARCHIVE); //safeArea_adjusted_horizontal
Utils::Hook::Xor<INT>(0x42E423, Game::dvar_flag::DVAR_READONLY | Game::dvar_flag::DVAR_ARCHIVE); //safeArea_adjusted_vertical
Utils::Hook::Xor<BYTE>(0x42E398, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE); //safeArea_horizontal
Utils::Hook::Xor<BYTE>(0x42E3C4, Game::dvar_flag::DVAR_CHEAT | Game::dvar_flag::DVAR_ARCHIVE); //safeArea_vertical
// Don't allow setting cheat protected dvars via menus
Utils::Hook(0x63C897, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x63CA96, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x63CDB5, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x635E47, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
2022-02-03 06:44:35 -05:00
// Script_SetDvar
Utils::Hook(0x63444C, Dvar::SetFromStringByNameSafeExternal, HOOK_CALL).install()->quick();
// Slider
Utils::Hook(0x636159, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x636189, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x6364EA, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x636207, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x636608, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
Utils::Hook(0x636695, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
// Entirely block setting cheat dvars internally without sv_cheats
//Utils::Hook(0x4F52EC, Dvar::SetFromStringByNameExternal, HOOK_CALL).install()->quick();
2021-10-04 16:03:56 -04:00
// Hook Dvar_SetFromStringByName inside CG_SetClientDvarFromServer so we can reset dvars when the player leaves the server
Utils::Hook(0x59386A, Dvar::DvarSetFromStringByNameStub, HOOK_CALL).install()->quick();
2021-12-04 13:34:19 -05:00
2021-12-06 07:35:06 -05:00
// If the game closed abruptly, the dvars would not have been restored
Scheduler::Once(Dvar::ResetDvarsValue, Scheduler::Pipeline::MAIN);
2017-01-19 16:23:59 -05:00
}
Dvar::~Dvar()
{
2021-12-04 13:34:19 -05:00
Utils::IO::RemoveFile(Dvar::ArchiveDvarPath);
2017-01-19 16:23:59 -05:00
}
}