diff --git a/shared/sdk/CVar.cpp b/shared/sdk/CVar.cpp index 697615ca..392903c4 100644 --- a/shared/sdk/CVar.cpp +++ b/shared/sdk/CVar.cpp @@ -311,13 +311,39 @@ std::optional find_cvar_data(std::wstring_view modul SPDLOG_INFO("Found {} at {:x}", utility::narrow(name.data()), (uintptr_t)*result); } - return result; + return ConsoleVariableDataWrapper{*result, name.data()}; } IConsoleVariable** find_cvar(std::wstring_view module_name, std::wstring_view name, bool stop_at_first_mov) { SPDLOG_INFO("Attempting to locate {} {} cvar", utility::narrow(module_name.data()), utility::narrow(name.data())); + const auto module = sdk::get_ue_module(module_name.data()); + + // Attempt to locate it by way of the console manager first. + try { + const auto console_manager = sdk::FConsoleManager::get(); + + if (console_manager != nullptr) { + const auto cvar = console_manager->find(name.data()); + + if (cvar != nullptr) { + const auto module_data = utility::scan_ptr(module, (uintptr_t)cvar); + + if (module_data) { + SPDLOG_INFO("Found {} at {:x} (via console manager)", utility::narrow(name.data()), (uintptr_t)*module_data); + return (IConsoleVariable**)*module_data; + } else { + SPDLOG_ERROR("Failed to find {} in module data!", utility::narrow(name.data())); + } + } else { + SPDLOG_ERROR("Failed to find {} in console manager!", utility::narrow(name.data())); + } + } + } catch(...) { + + } + const auto str = utility::scan_string(module, name.data()); if (!str) { @@ -328,7 +354,7 @@ IConsoleVariable** find_cvar(std::wstring_view module_name, std::wstring_view na const auto str_ref = utility::scan_displacement_reference(module, *str); if (!str_ref) { - SPDLOG_ERROR("Failed to find {} string reference!"); + SPDLOG_ERROR("Failed to find {} string reference!", utility::narrow(name.data())); return nullptr; } @@ -387,13 +413,7 @@ bool set_cvar_data_int(std::wstring_view module, std::wstring_view name, int val return false; } - auto cvar = cvar_data->get(); - - if (cvar == nullptr) { - return false; - } - - cvar->set(value); + cvar_data->set(value); return true; } catch (...) { static std::unordered_map bad_cvars{}; @@ -414,13 +434,7 @@ bool set_cvar_data_float(std::wstring_view module, std::wstring_view name, float return false; } - auto cvar = cvar_data->get(); - - if (cvar == nullptr) { - return false; - } - - cvar->set(value); + cvar_data->set(value); return true; } catch (...) { static std::unordered_map bad_cvars{}; diff --git a/shared/sdk/CVar.hpp b/shared/sdk/CVar.hpp index 42e47603..913682e4 100644 --- a/shared/sdk/CVar.hpp +++ b/shared/sdk/CVar.hpp @@ -9,6 +9,10 @@ #include #include +#include + +#include "threading/GameThreadWorker.hpp" +#include "ConsoleManager.hpp" #include "TArray.hpp" namespace sdk { @@ -17,7 +21,7 @@ struct TConsoleVariableData { static inline std::recursive_mutex s_mutex{}; static inline std::unordered_map s_valid_states{}; - void set(T value) { + bool set(T value) { { std::scoped_lock _{s_mutex}; @@ -34,12 +38,13 @@ struct TConsoleVariableData { } if (!s_valid_states[this]) { - return; + return false; } } this->values[0] = value; this->values[1] = value; + return true; } T get(int index = 0) const { @@ -135,14 +140,51 @@ class ConsoleVariableDataWrapper { return *(TConsoleVariableData**)this->m_cvar; } + template + void set_via_console_manager(T value) { + if (m_name.empty()) { + return; + } + + if (m_real_cvar != nullptr) { + GameThreadWorker::get().enqueue([cvar = m_real_cvar, value]() { + cvar->Set(std::to_wstring(value).c_str()); + }); + + return; + } + + try { + const auto console_manager = sdk::FConsoleManager::get(); + + if (console_manager != nullptr) { + auto cvar = (sdk::IConsoleVariable*)console_manager->find(m_name); + + if (cvar != nullptr) { + m_real_cvar = cvar; + spdlog::info("Fallback to real cvar for {}", utility::narrow(m_name)); + + GameThreadWorker::get().enqueue([cvar, value]() { + cvar->Set(std::to_wstring(value).c_str()); + }); + } + } + } catch(...) { + + } + } + template void set(T value) { if (this->m_cvar == nullptr || *this->m_cvar == nullptr) { + set_via_console_manager(value); return; } auto data = *(TConsoleVariableData**)this->m_cvar; - data->set(value); + if (!data->set(value)) { + set_via_console_manager(value); + } } ConsoleVariableDataWrapper(uintptr_t address) @@ -151,12 +193,21 @@ class ConsoleVariableDataWrapper { } + ConsoleVariableDataWrapper(uintptr_t address, const std::wstring& name) + : m_cvar{ (void**)address }, + m_name{ name } + { + + } + uintptr_t address() const { return (uintptr_t)m_cvar; } private: - void** m_cvar; + void** m_cvar{nullptr}; + std::wstring m_name{L""}; + sdk::IConsoleVariable* m_real_cvar{nullptr}; }; // In some games, likely due to obfuscation, the cvar description is missing