From a75c616e689df9c6eb948871b8da6857b9b673c8 Mon Sep 17 00:00:00 2001 From: quaK Date: Wed, 30 Apr 2025 12:49:15 +0300 Subject: [PATCH] dvars refactor --- src/client/component/dvars.cpp | 417 ++++++++++++++++++++----------- src/client/component/patches.cpp | 10 +- src/client/game/structs.hpp | 23 ++ 3 files changed, 307 insertions(+), 143 deletions(-) diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp index dcddec74..0f2a5e2d 100644 --- a/src/client/component/dvars.cpp +++ b/src/client/component/dvars.cpp @@ -8,54 +8,195 @@ #include #include +#include // Include this header for intrinsic functions +#define __ROR4__(value, shift) _rotr(value, shift) // Define __ROR4__ using _rotr intrinsic +#define __ROL4__(value, shift) _rotl(value, shift) // Define __ROL4__ using _rotl intrinsic + namespace dvars { - struct dvar_base + namespace crypt { + void hash_boolean(game::DvarValue* value) // Unused + { + int hashed = value->boolean_.enabled; // this is always 0 in the actual game + int temp = 0; + unsigned int key = 0x89E1A665; + int xorKey = 0x87C6B47F; + + while (key != 0xE9CC2CC0) + { + switch (key) + { + case 0x89E1A665: + temp = static_cast(hashed); + xorKey = 0x008B237C; + break; + case 0x1C9C36AA: + temp = static_cast(hashed) ^ 0x7434; + xorKey = 0xAB74F2A4; + hashed = __ROR4__(hashed, 16); + break; + case 0x6006EB8D: + temp = static_cast(hashed) ^ 0x9133; + xorKey = 0xA6F5E979; + hashed = temp ^ __ROL4__(hashed, 16); + break; + case 0x896A8519: + temp ^= 0x52D0; + xorKey = 0x6B8E2B15; + hashed = __ROL4__(hashed, 16); + break; + case 0xC6F302F4: + xorKey = 0x2F3F2E34; + hashed = __ROR4__(hashed, 16); + break; + case 0xE2E4AE0C: + hashed ^= temp; + xorKey = 0x82E24581; + break; + case 0xF6B9AD6A: + temp ^= 0xCA71; + xorKey = 0x52DB7D55; + break; + } + key ^= xorKey; + } + + value->boolean_.hashedValue = hashed; + } + + void hash_integer(game::DvarValue* value) + { + int hashed = value->integer_.integer; + int temp = 0; + int xorKey = 0x87C6B47F; + unsigned int key = 0x89E1A665; + + while (key != 0xE9CC2CC0) + { + switch (key) + { + case 0x89E1A665: + temp = static_cast(hashed); + xorKey = 0x008B237C; + break; + case 0x1C9C36AA: + temp = static_cast(hashed) ^ 0x7434; + xorKey = 0xAB74F2A4; + hashed = __ROR4__(hashed, 16); + break; + case 0x6006EB8D: + temp = static_cast(hashed) ^ 0x9133; + xorKey = 0xA6F5E979; + hashed = temp ^ __ROL4__(hashed, 16); + break; + case 0x896A8519: + temp ^= 0x52D0; + xorKey = 0x6B8E2B15; + hashed = __ROL4__(hashed, 16); + break; + case 0xC6F302F4: + xorKey = 0x2F3F2E34; + hashed = __ROR4__(hashed, 16); + break; + case 0xE2E4AE0C: + hashed ^= temp; + xorKey = 0x82E24581; + break; + case 0xF6B9AD6A: + temp ^= 0xCA71; + xorKey = 0x52DB7D55; + break; + } + key ^= xorKey; + } + + value->integer_.hashedValue = hashed; + } + + void hash_enum(game::DvarValue* value) + { + hash_integer(value); + } + + void hash(game::DvarType type, game::DvarValue* value) + { + switch (type) + { + case game::DvarType::boolean: + hash_boolean(value); + break; + case game::DvarType::integer: + hash_integer(value); + break; + case game::DvarType::enumeration: + hash_enum(value); + break; + default: + break; + } + } + + int unhash_integer(game::dvar_t* dvar) + { + int original = dvar->current.integer_.integer; + if (original == 0) + return 0; + + int result = dvar->current.integer_.hashedValue; + int temp = 0; + int xorKey = 0x040ABA5A; + unsigned int key = 0x19B62CC6; + + while (key != 0x9E5E5A15) + { + switch (key) { + case 0x19B62CC6: + temp = static_cast(result); + xorKey = 0xC1BCD395; + break; + case 0x4AD465E7: + temp ^= 0xCA71; + xorKey = 0x05CA2DF8; + break; + case 0x8F9CFC5: + xorKey = 0x0A2F246E; + result = __ROL4__(temp ^ result, 16); + break; + case 0x6B2A7033: + temp ^= 0x52D0; + xorKey = 0xAF9030E3; + break; + case 0xC4BA40D0: + result = __ROR4__(result, 16); + xorKey = 0xCC438F15; + break; + case 0xD80AFF53: + result = temp ^ __ROR4__(result, 16) ^ 0x9133; + temp = static_cast(result); + xorKey = 0xB3208F60; + break; + case 0xEF93D298: + temp = static_cast(result) ^ 0x7434; + xorKey = 0x09C60C3F; + break; + } + key ^= xorKey; + } + + // if (result != original) ExitProcess(0); + return result; + } + } + + struct dvar_combined + { + std::string string{}; + game::DvarValue value{}; + game::DvarLimits limits{}; unsigned int flags{}; }; - struct dvar_bool : dvar_base - { - bool value{}; - }; - - struct dvar_float : dvar_base - { - float value{}; - float min{}; - float max{}; - }; - - struct dvar_vector2 : dvar_base - { - float x{}; - float y{}; - float min{}; - float max{}; - }; - - struct dvar_vector3 : dvar_base - { - float x{}; - float y{}; - float z{}; - float min{}; - float max{}; - }; - - struct dvar_int : dvar_base - { - int value{}; - int min{}; - int max{}; - }; - - struct dvar_string : dvar_base - { - std::string value{}; - }; - namespace { template @@ -94,75 +235,70 @@ namespace dvars namespace override { - static std::unordered_map register_bool_overrides; - static std::unordered_map register_float_overrides; - static std::unordered_map register_int_overrides; - static std::unordered_map register_string_overrides; - static std::unordered_map register_vector2_overrides; - static std::unordered_map register_vector3_overrides; + static std::unordered_map> register_overrides; void register_bool(const std::string& name, const bool value, const unsigned int flags) { - dvar_bool values; - values.value = value; + dvar_combined values; + values.value.enabled = value; values.flags = flags; - register_bool_overrides[name] = std::move(values); + register_overrides[game::DvarType::boolean][name] = std::move(values); } void register_float(const std::string& name, const float value, const float min, const float max, const unsigned int flags) { - dvar_float values; - values.value = value; - values.min = min; - values.max = max; + dvar_combined values; + values.value.value = value; + values.limits.value.min = min; + values.limits.value.max = max; values.flags = flags; - register_float_overrides[name] = std::move(values); + register_overrides[game::DvarType::value][name] = std::move(values); } void register_int(const std::string& name, const int value, const int min, const int max, const unsigned int flags) { - dvar_int values; - values.value = value; - values.min = min; - values.max = max; + dvar_combined values; + values.value.integer = value; + values.limits.integer.min = min; + values.limits.integer.max = max; values.flags = flags; - register_int_overrides[name] = std::move(values); + register_overrides[game::DvarType::integer][name] = std::move(values); } void register_string(const std::string& name, const std::string& value, const unsigned int flags) { - dvar_string values; - values.value = value; + dvar_combined values; + values.string = value; values.flags = flags; - register_string_overrides[name] = std::move(values); + register_overrides[game::DvarType::string][name] = std::move(values); } void register_vec2(const std::string& name, float x, float y, float min, float max, const unsigned int flags) { - dvar_vector2 values; - values.x = x; - values.y = y; - values.min = min; - values.max = max; + dvar_combined values; + values.value.vector[0] = x; + values.value.vector[1] = y; + values.limits.vector.min = min; + values.limits.vector.max = max; values.flags = flags; - register_vector2_overrides[name] = std::move(values); + register_overrides[game::DvarType::vec2][name] = std::move(values); } void register_vec3(const std::string& name, float x, float y, float z, float min, float max, const unsigned int flags) { - dvar_vector3 values; - values.x = x; - values.y = y; - values.z = z; - values.min = min; - values.max = max; + dvar_combined values; + values.value.vector[0] = x; + values.value.vector[1] = y; + values.value.vector[2] = z; + values.limits.vector.min = min; + values.limits.vector.max = max; values.flags = flags; - register_vector3_overrides[name] = std::move(values); + register_overrides[game::DvarType::vec3][name] = std::move(values); } } @@ -188,99 +324,107 @@ namespace dvars } } - utils::hook::detour dvar_register_bool_hook; - utils::hook::detour dvar_register_float_hook; - utils::hook::detour dvar_register_int_hook; - utils::hook::detour dvar_register_string_hook; - utils::hook::detour dvar_register_vector2_hook; - utils::hook::detour dvar_register_vector3_hook; - - game::dvar_t* dvar_register_bool(const char* name, bool value, unsigned int flags, const char* description) + void inline dvar_register_bool(const char* name, bool& value, unsigned int& flags, const char* description) { - auto* var = find_dvar(override::register_bool_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::boolean], name); if (var) { - value = var->value; + value = var->value.enabled; flags = var->flags; } - - return dvar_register_bool_hook.invoke(name, value, flags, description); } - game::dvar_t* dvar_register_float(const char* name, float value, float min, float max, unsigned int flags, const char* description) + void inline dvar_register_float(const char* name, float& value, float& min, float& max, unsigned int flags, const char* description) { - auto* var = find_dvar(override::register_float_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::value], name); if (var) { - value = var->value; - min = var->min; - max = var->max; + value = var->value.value; + min = var->limits.value.min; + max = var->limits.value.max; flags = var->flags; } - - return dvar_register_float_hook.invoke(name, value, min, max, flags, description); } - game::dvar_t* dvar_register_int(const char* name, int value, int min, int max, unsigned int flags, const char* description) + void inline dvar_register_int(const char* name, int& value, int& min, int& max, unsigned int& flags, const char* description) { - auto* var = find_dvar(override::register_int_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::integer], name); if (var) { - value = var->value; - min = var->min; - max = var->max; + value = var->value.integer; + min = var->limits.integer.min; + max = var->limits.integer.max; flags = var->flags; } - - return dvar_register_int_hook.invoke(name, value, min, max, flags, description); } - game::dvar_t* dvar_register_string(const char* name, const char* value, unsigned int flags, const char* description) + void inline dvar_register_string(const char* name, const char* value, unsigned int& flags, const char* description) { - auto* var = find_dvar(override::register_string_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::string], name); if (var) { - value = var->value.data(); + value = var->string.data(); flags = var->flags; } - - return dvar_register_string_hook.invoke(name, value, flags, description); } - game::dvar_t* dvar_register_vector2(const char* name, float x, float y, float min, float max, - unsigned int flags, const char* description) + void inline dvar_register_vector2(const char* name, float& x, float& y, float& min, float& max, + unsigned int& flags, const char* description) { - auto* var = find_dvar(override::register_vector2_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::vec2], name); if (var) { - x = var->x; - y = var->y; - min = var->min; - max = var->max; + x = var->value.vector[0]; + y = var->value.vector[1]; + min = var->limits.vector.min; + max = var->limits.vector.max; flags = var->flags; } - - return dvar_register_vector2_hook.invoke(name, x, y, min, max, flags, description); } - game::dvar_t* dvar_register_vector3(const char* name, float x, float y, float z, float min, - float max, unsigned int flags, const char* description) + void inline dvar_register_vector3(const char* name, float& x, float& y, float& z, float& min, + float& max, unsigned int& flags, const char* description) { - auto* var = find_dvar(override::register_vector3_overrides, name); + auto* var = find_dvar(override::register_overrides[game::DvarType::vec3], name); if (var) { - x = var->x; - y = var->y; - z = var->z; - min = var->min; - max = var->max; + x = var->value.vector[0]; + y = var->value.vector[1]; + z = var->value.vector[2]; + min = var->limits.vector.min; + max = var->limits.vector.max; flags = var->flags; } - - return dvar_register_vector3_hook.invoke(name, x, y, z, min, max, flags, description); } - std::recursive_mutex _mutex; + void inline check_dvar_overrides(const char* name, game::DvarType& type, unsigned int& flags, game::DvarValue* value, game::DvarLimits* domain, const char* description) + { + switch (type) + { + case game::DvarType::boolean: + dvar_register_bool(name, value->enabled, flags, description); + break; + case game::DvarType::value: + dvar_register_float(name, value->value, domain->value.min, domain->value.max, flags, description); + break; + case game::DvarType::integer: + dvar_register_int(name, value->integer, domain->integer.min, domain->integer.max, flags, description); + break; + case game::DvarType::string: + dvar_register_string(name, value->string, flags, description); + break; + case game::DvarType::vec2: + dvar_register_vector2(name, value->vector[0], value->vector[1], domain->vector.min, domain->vector.max, flags, description); + break; + case game::DvarType::vec3: + dvar_register_vector3(name, value->vector[0], value->vector[1], value->vector[2], domain->vector.min, domain->vector.max, flags, description); + break; + default: + break; + } + + dvars::crypt::hash(type, value); + } utils::hook::detour dvar_register_new_hook; utils::hook::detour dvar_re_register_hook; @@ -290,7 +434,6 @@ namespace dvars game::dvar_t* dvar_register_new(const char* name, unsigned int checksum, game::DvarType type, unsigned int flags, game::DvarValue* value, game::DvarLimits* domain, char level, const char* description) { - std::lock_guard $(_mutex); auto* dvar = dvar_register_new_hook.invoke(name, checksum, type, flags, value, domain, level, description); if (dvar && name) @@ -305,11 +448,9 @@ namespace dvars return dvar; } - void dvar_re_register(game::dvar_t* dvar, const char* name, game::DvarType type, unsigned int flags, + inline void dvar_re_register(game::dvar_t* dvar, const char* name, game::DvarType type, unsigned int flags, game::DvarValue* resetValue, game::DvarLimits* domain, char level, const char* description) { - std::lock_guard $(_mutex); - if (dvar && name) { const auto disabled = find_dvar(disable::re_register_disables, name); @@ -330,8 +471,6 @@ namespace dvars game::dvar_t* dvar_de_register(game::dvar_t* dvar) { - std::lock_guard $(_mutex); - auto name = dvars::dvar_get_name(dvar); if (dvar && !name.empty()) { @@ -354,7 +493,8 @@ namespace dvars game::dvar_t* dvar_register_variant(const char* name, unsigned int checksum, game::DvarType type, unsigned int flags, game::DvarValue* value, game::DvarLimits* domain, const char* description) { - std::lock_guard $(_mutex); + check_dvar_overrides(name, type, flags, value, domain, description); + auto* dvar = dvar_register_variant_hook.invoke(name, checksum, type, flags, value, domain, description); if (dvar) @@ -377,13 +517,6 @@ namespace dvars public: void post_unpack() override { - dvar_register_bool_hook.create(0x140CEB380, &dvar_register_bool); - dvar_register_float_hook.create(0x140CEB890, &dvar_register_float); - dvar_register_int_hook.create(0x140CEB920, &dvar_register_int); - dvar_register_string_hook.create(0x140CEBD50, &dvar_register_string); - dvar_register_vector2_hook.create(0x140CEBF50, &dvar_register_vector2); - dvar_register_vector3_hook.create(0x140CEBFE0, &dvar_register_vector3); - dvar_register_new_hook.create(0x140CEBA60, dvar_register_new); dvar_re_register_hook.create(0x140CEC210, dvar_re_register); dvar_de_register_hook.create(0x140CE9F30, dvar_de_register); diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index d0459330..1f82ba41 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -267,7 +267,15 @@ namespace patches utils::hook::jump(0x140B7A920, init_network_dvars_stub); // some [data validation] anti tamper thing that kills performance - dvars::override::register_int("dvl", 0, 0, 0, game::DVAR_FLAG_READ); + dvars::override::register_int("dvl", 0, 0, 0, game::DVAR_FLAG_NONE); + dvars::override::register_int("data_validation_allow_drop", 0, 0, 0, game::DVAR_FLAG_NONE); + utils::hook::set(0x1405C9FA0, 0xC3); // ValidateData + utils::hook::set(0x1405C9300, 0xC3); // ValidateMetaData + utils::hook::set(0x1405C9D70, 0xC3); // UpdateValidationDataInternal + utils::hook::set(0x1405C9590, 0xC3); // RegisterValidationData + utils::hook::set(0x1405C9960, 0xC3); // ShutdownValidationData + utils::hook::set(0x1405C8EC0, 0xC3); // FreeValidationData + utils::hook::set(0x1405C90C0, 0xC3); // killswitches dvars::override::register_bool("mission_team_contracts_enabled", true, game::DVAR_FLAG_READ); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 4e331f9c..bce9a37b 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -122,6 +122,25 @@ namespace game rgb = 9, // Color without alpha }; + struct DvarValueBool + { + bool enabled; + char pad[3]; + int hashedValue; + }; + + struct DvarValueInt + { + int integer; + int hashedValue; + }; + + struct DvarValueEnum + { + int defaultIndex; + int hashedValue; + }; + union DvarValue { bool enabled; @@ -131,6 +150,10 @@ namespace game float vector[4]; const char* string; char color[4]; + + DvarValueBool boolean_; + DvarValueInt integer_; + DvarValueEnum enumeration_; }; struct $A37BA207B3DDD6345C554D4661813EDD