diff --git a/source/proxy-dll/component/blackbox.cpp b/source/proxy-dll/component/blackbox.cpp index 41a8419..d9a416f 100644 --- a/source/proxy-dll/component/blackbox.cpp +++ b/source/proxy-dll/component/blackbox.cpp @@ -218,7 +218,7 @@ namespace blackbox std::string generate_crash_info(const LPEXCEPTION_POINTERS exceptioninfo) { - const auto& build_info = game::version_string; + std::string build_info = game::Com_GetVersionString(); const auto main_module = utilities::nt::library{}; const auto rip_address = exceptioninfo->ExceptionRecord->ExceptionAddress; diff --git a/source/proxy-dll/component/command.cpp b/source/proxy-dll/component/command.cpp new file mode 100644 index 0000000..ae72060 --- /dev/null +++ b/source/proxy-dll/component/command.cpp @@ -0,0 +1,212 @@ +#include +#include "command.hpp" +#include "definitions/game.hpp" + +#include +#include +#include + +namespace command +{ + namespace + { + std::unordered_map& get_command_map() + { + static std::unordered_map command_map{}; + return command_map; + } + + std::unordered_map& get_sv_command_map() + { + static std::unordered_map command_map{}; + return command_map; + } + + void execute_custom_command() + { + const params params{}; + const auto command = utilities::string::to_lower(params[0]); + + auto& map = get_command_map(); + const auto entry = map.find(command); + if (entry != map.end()) + { + entry->second(params); + } + } + + void execute_custom_sv_command() + { + const params_sv params{}; + const auto command = utilities::string::to_lower(params[0]); + + auto& map = get_sv_command_map(); + const auto entry = map.find(command); + if (entry != map.end()) + { + entry->second(params); + } + } + + game::CmdArgs* get_cmd_args() + { + return game::Sys_GetTLS()->cmdArgs; + } + } + + params::params() + : nesting_(get_cmd_args()->nesting) + { + assert(this->nesting_ < game::CMD_MAX_NESTING); + } + + params::params(const std::string& text) + : needs_end_(true) + { + auto* cmd_args = get_cmd_args(); + game::Cmd_TokenizeStringKernel(0, 0, text.data(), + 512 - cmd_args->totalUsedArgvPool, false, cmd_args); + + this->nesting_ = cmd_args->nesting; + } + + params::~params() + { + if (this->needs_end_) + { + game::Cmd_EndTokenizedString(); + } + } + + int params::size() const + { + return get_cmd_args()->argc[this->nesting_]; + } + + params_sv::params_sv() + : nesting_(game::sv_cmd_args->nesting) + { + assert(this->nesting_ < game::CMD_MAX_NESTING); + } + + params_sv::params_sv(const std::string& text) + : needs_end_(true) + { + game::SV_Cmd_TokenizeString(text.data()); + this->nesting_ = game::sv_cmd_args->nesting; + } + + params_sv::~params_sv() + { + if (this->needs_end_) + { + game::SV_Cmd_EndTokenizedString(); + } + } + + int params_sv::size() const + { + return game::sv_cmd_args->argc[this->nesting_]; + } + + const char* params_sv::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return game::sv_cmd_args->argv[this->nesting_][index]; + } + + std::string params_sv::join(const int index) const + { + std::string result; + + for (auto i = index; i < this->size(); ++i) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + + return result; + } + + const char* params::get(const int index) const + { + if (index >= this->size()) + { + return ""; + } + + return get_cmd_args()->argv[this->nesting_][index]; + } + + std::string params::join(const int index) const + { + std::string result = {}; + + for (auto i = index; i < this->size(); i++) + { + if (i > index) result.append(" "); + result.append(this->get(i)); + } + return result; + } + + void add(const std::string& command, command_function function, const char* desc) + { + add(command, [f = std::move(function)](const params&) + { + f(); + }); + } + + void add(const std::string& command, command_param_function function, const char* desc) + { + auto lower_command = utilities::string::to_lower(command); + + auto& map = get_command_map(); + const auto is_registered = map.contains(lower_command); + + map[std::move(lower_command)] = std::move(function); + + if (is_registered) + { + return; + } + + auto& allocator = *utilities::memory::get_allocator(); + auto* cmd_function = allocator.allocate(); + auto cmdRef = game::AssetRef(command.data()); + + variables::commands_table.push_back({ command, desc, fnv1a::generate_hash(command.data()) }); + + game::Cmd_AddCommandInternal(&cmdRef, execute_custom_command, cmd_function); + } + + void add_sv(const std::string& command, sv_command_param_function function, const char* desc) + { + auto lower_command = utilities::string::to_lower(command); + + auto& map = get_sv_command_map(); + const auto is_registered = map.contains(lower_command); + + map[std::move(lower_command)] = std::move(function); + + if (is_registered) + { + return; + } + + auto& allocator = *utilities::memory::get_allocator(); + auto cmdRef = game::AssetRef(command.data()); + + variables::commands_table.push_back({ command, desc, fnv1a::generate_hash(command.data()) }); + + game::Cmd_AddCommandInternal(&cmdRef, game::Cbuf_AddServerText_f, + allocator.allocate()); + game::Cmd_AddServerCommandInternal(&cmdRef, execute_custom_sv_command, + allocator.allocate()); + } +} \ No newline at end of file diff --git a/source/proxy-dll/component/command.hpp b/source/proxy-dll/component/command.hpp new file mode 100644 index 0000000..e856cdf --- /dev/null +++ b/source/proxy-dll/component/command.hpp @@ -0,0 +1,67 @@ +#pragma once + +namespace command +{ + class params + { + public: + params(); + params(const std::string& text); + ~params(); + + params(params&&) = delete; + params(const params&) = delete; + + params& operator=(params&&) = delete; + params& operator=(const params&) = delete; + + [[nodiscard]] int size() const; + [[nodiscard]] const char* get(int index) const; + [[nodiscard]] std::string join(int index) const; + + [[nodiscard]] const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + bool needs_end_{false}; + int nesting_; + }; + + class params_sv + { + public: + params_sv(); + params_sv(const std::string& text); + ~params_sv(); + + params_sv(params_sv&&) = delete; + params_sv(const params_sv&) = delete; + + params_sv& operator=(params_sv&&) = delete; + params_sv& operator=(const params_sv&) = delete; + + [[nodiscard]] int size() const; + [[nodiscard]] const char* get(int index) const; + [[nodiscard]] std::string join(int index) const; + + [[nodiscard]] const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + bool needs_end_{false}; + int nesting_; + }; + + using command_function = std::function; + using command_param_function = std::function; + using sv_command_param_function = std::function; + + void add(const std::string& command, command_function function, const char* desc = ""); + void add(const std::string& command, command_param_function function, const char* desc = ""); + + void add_sv(const std::string& command, sv_command_param_function function, const char* desc = ""); +} diff --git a/source/proxy-dll/component/debugging.cpp b/source/proxy-dll/component/debugging.cpp index 340f224..1fe2cee 100644 --- a/source/proxy-dll/component/debugging.cpp +++ b/source/proxy-dll/component/debugging.cpp @@ -1,6 +1,5 @@ #include #include "definitions/game.hpp" -#include "definitions/game_runtime_errors.hpp" #include "component/scheduler.hpp" #include "loader/component_loader.hpp" @@ -74,7 +73,7 @@ namespace debugging void sys_error_stub(uint32_t code, const char* message) { - const char* error_message = game::runtime_errors::get_error_message(code); + const char* error_message = runtime_errors::get_error_message(code); if (error_message) { diff --git a/source/proxy-dll/component/dvars.cpp b/source/proxy-dll/component/dvars.cpp index dacbcd1..4fe486e 100644 --- a/source/proxy-dll/component/dvars.cpp +++ b/source/proxy-dll/component/dvars.cpp @@ -13,7 +13,7 @@ namespace dvars { void fetch_dvar_pointers() { - for (auto& dvar : variables::dvars_record) + for (auto& dvar : variables::dvars_table) { dvar.pointer = spoofcall::invoke(game::Dvar_FindVar, dvar.name.data()); } @@ -248,9 +248,9 @@ namespace dvars { if (hashRef == 0) return NULL; - auto it = std::find_if(variables::dvars_record.begin(), variables::dvars_record.end(), [&hashRef](variables::varEntry& i) { return i.fnv1a == hashRef; }); + auto it = std::find_if(variables::dvars_table.begin(), variables::dvars_table.end(), [&hashRef](variables::varEntry& i) { return i.fnv1a == hashRef; }); - if (it != variables::dvars_record.end() && it->pointer) + if (it != variables::dvars_table.end() && it->pointer) { return reinterpret_cast(it->pointer); } @@ -265,9 +265,9 @@ namespace dvars game::dvar_t* find_dvar(const std::string& nameRef) { - auto it = std::find_if(variables::dvars_record.begin(), variables::dvars_record.end(), [&nameRef](variables::varEntry& i) { return utilities::string::compare(i.name, nameRef); }); + auto it = std::find_if(variables::dvars_table.begin(), variables::dvars_table.end(), [&nameRef](variables::varEntry& i) { return utilities::string::compare(i.name, nameRef); }); - if (it != variables::dvars_record.end() && it->pointer) + if (it != variables::dvars_table.end() && it->pointer) { return reinterpret_cast(it->pointer); } diff --git a/source/proxy-dll/component/game_console.cpp b/source/proxy-dll/component/game_console.cpp index dcf094b..3c65166 100644 --- a/source/proxy-dll/component/game_console.cpp +++ b/source/proxy-dll/component/game_console.cpp @@ -184,7 +184,7 @@ namespace game_console { double required_ratio = exact ? 1.00 : 0.01; - for (const auto& dvar : variables::dvars_record) + for (const auto& dvar : variables::dvars_table) { if (dvars::find_dvar(dvar.fnv1a) && utilities::string::match(input, dvar.name) >= required_ratio) { @@ -202,7 +202,7 @@ namespace game_console suggestions.push_back({ input, "", fnv1a::generate_hash(input.data()), reinterpret_cast(dvars::find_dvar(input)) }); } - for (const auto& cmd : variables::commands_record) + for (const auto& cmd : variables::commands_table) { if (utilities::string::match(input, cmd.name) >= required_ratio) { @@ -374,7 +374,13 @@ namespace game_console auto width = (con.screen_max[0] - con.screen_min[0]) - 12.0f; auto height = ((con.screen_max[1] - con.screen_min[1]) - 32.0f) - 12.0f; - game::R_AddCmdDrawText(game::version_string.data(), 0x7FFFFFFF, R_DrawTextFont, x, ((height - 16.0f) + y) + con.font_height, con.font_scale, con.font_scale, 0.0f, con_outputVersionStringColor, 0); + char sysinfo_version[256]; + bool result1 = utilities::hook::invoke(game::Live_SystemInfo, 0, 0, sysinfo_version, 256); + char sysinfo_livebits[256]; + bool result2 = utilities::hook::invoke(game::Live_SystemInfo, 0, 1, sysinfo_livebits, 256); + const char* info = utilities::string::va("Project-BO4 1.0.0, Engine Version: %s, LiveBits: %s", sysinfo_version, sysinfo_livebits); + + game::R_AddCmdDrawText(info, 0x7FFFFFFF, R_DrawTextFont, x, ((height - 16.0f) + y) + con.font_height, con.font_scale, con.font_scale, 0.0f, con_outputVersionStringColor, 0); draw_output_scrollbar(x, y, width, height, output); draw_output_text(x, y, output); diff --git a/source/proxy-dll/component/gsc_funcs.cpp b/source/proxy-dll/component/gsc_funcs.cpp index 50e4d27..ff75819 100644 --- a/source/proxy-dll/component/gsc_funcs.cpp +++ b/source/proxy-dll/component/gsc_funcs.cpp @@ -3,7 +3,6 @@ #include "gsc_custom.hpp" #include "hashes.hpp" #include "definitions/game.hpp" -#include "definitions/game_runtime_errors.hpp" #include "definitions/xassets.hpp" #include "loader/component_loader.hpp" #include "component/scheduler.hpp" @@ -53,7 +52,7 @@ namespace gsc_funcs vsprintf_s(buffer[inst], message, va); va_end(va); - game::ScrVm_Error(game::runtime_errors::custom_error_id, inst, buffer[inst], terminal); + game::ScrVm_Error(runtime_errors::custom_error_id, inst, buffer[inst], terminal); } const char* lookup_hash(game::scriptInstance_t inst, const char* type, uint64_t hash) @@ -1329,13 +1328,13 @@ namespace gsc_funcs break; default: // put custom message for our id - if (code == game::runtime_errors::custom_error_id) + if (code == runtime_errors::custom_error_id) { game::scrVarPub[inst].error_message = unused; } else { - game::scrVarPub[inst].error_message = game::runtime_errors::get_error_message(code); + game::scrVarPub[inst].error_message = runtime_errors::get_error_message(code); } break; } diff --git a/source/proxy-dll/component/logger.cpp b/source/proxy-dll/component/logger.cpp index f474033..ff7bf53 100644 --- a/source/proxy-dll/component/logger.cpp +++ b/source/proxy-dll/component/logger.cpp @@ -72,11 +72,6 @@ namespace logger write(LOG_TYPE_INFO, " T8-Mod Initializing ... %s[0x%llX]", utilities::nt::library{}.get_name().c_str(), utilities::nt::library{}.get_ptr()); write(LOG_TYPE_INFO, "======================================================================================================="); } - - void post_unpack() override - { - /* PLACE_HOLDER */ - } }; } REGISTER_COMPONENT(logger::component) \ No newline at end of file diff --git a/source/proxy-dll/component/mods.cpp b/source/proxy-dll/component/mods.cpp index da60a40..ea2c18e 100644 --- a/source/proxy-dll/component/mods.cpp +++ b/source/proxy-dll/component/mods.cpp @@ -1,15 +1,15 @@ #include -#include "definitions/xassets.hpp" -#include "definitions/game.hpp" - -#include "game_console.hpp" - #include "gsc_funcs.hpp" #include "gsc_custom.hpp" #include "dvars.hpp" #include "hashes.hpp" - +#include "command.hpp" +#include "game_console.hpp" #include "loader/component_loader.hpp" + +#include "definitions/xassets.hpp" +#include "definitions/game.hpp" + #include #include @@ -1094,7 +1094,7 @@ namespace mods { mod_storage storage{}; - void load_mods_cmd() + void mods_reload_f() { if (!game::Com_IsRunningUILevel()) { @@ -1267,8 +1267,7 @@ namespace mods { hksl_loadfile_hook.create(0x14375D6A0_g, hksl_loadfile_stub); bg_cache_sync_hook.create(0x1405CE0B0_g, bg_cache_sync_stub); - // register load mods command - Cmd_AddCommand("reload_mods", load_mods_cmd); + command::add("reload_mods", mods_reload_f, "Reload the shield mods"); } }; } diff --git a/source/proxy-dll/definitions/discovery.cpp b/source/proxy-dll/definitions/discovery.cpp deleted file mode 100644 index 4b13267..0000000 --- a/source/proxy-dll/definitions/discovery.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include -#include "discovery.hpp" -#include "loader/component_loader.hpp" - -#include -#include - -std::unordered_map symbols_list; - -size_t operator"" _d(const char* str, const size_t len) -{ - auto itr = symbols_list.find(std::string(str, len)); - if (itr != symbols_list.end()) return itr->second; // found you! - - //return find_missing_symbol(name); -} - -namespace discovery -{ - void export_address_list_to_json() - { - /* PLACE_HOLDER */ - } - - void import_address_list_from_json() - { - /* PLACE_HOLDER */ - } - - void start_address_list_discovery() - { - auto follow_jmp = [](size_t addr) -> size_t { - return *(int32_t*)(addr + 1) + addr + 5; - }; - - auto follow_lea = [](size_t addr) -> size_t { - return *(int32_t*)(addr + 3) + addr + 7; - }; - - std::vector signature_list; // SYMBOL NAME , SIGNATURE, DISTANCE, SIGNATURE RELATION - - // Main Symbols - signature_list.push_back({ "com_error", "4C 89 4C 24 ? 55 53 56 57 48", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "live_get_connectivity_info", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 48 8B DA C7 02", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "draw_text_cmd", "48 89 6C 24 ? 41 54 41 56 41 57 48 83 EC 30 80", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "ui_get_font_handle", "48 89 5C 24 ? 57 48 83 EC 30 8B DA 48 8B F9 83", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "scr_place_get_view", "E8 ? ? ? ? 48 85 C0 74 11 4C 8D", 0, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "r_text_height", "E8 ? ? ? ? 66 0F 6E C0 0F 5B C0 F3 0F 59 C6 F3 0F", 0, SIG_RELEVANCE_JMP_FROM }); - - // Platform Symbols - signature_list.push_back({ "bnet_is_disabled", "40 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 45 85", 0x17, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "bnet_is_connected", "48 83 EC 28 48 8B 0D ? ? ? ? E8 ? ? ? ? 84 C0 74 5A", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "bnet_patch_unk1", "48 83 EC 28 48 8B 0D ? ? ? ? E8 ? ? ? ? 84 C0 75 11", 0, SIG_RELEVANCE_DIRECT_HIT }); // Annoying function related to bnet; crashes game - signature_list.push_back({ "bnet_patch_unk2", "E8 ? ? ? ? 8B CF E8 ? ? ? ? 45 33 C0 48", 0, SIG_RELEVANCE_JMP_FROM }); // Annoying function related to bnet; crashes game - signature_list.push_back({ "bnet_patch_unk3", "E8 ? ? ? ? 88 85 ? ? ? ? 48 8B", 0, SIG_RELEVANCE_JMP_FROM }); // BattleNet_IsModeAvailable? - signature_list.push_back({ "bnet_patch_auth3", "E8 ? ? ? ? 84 C0 0F 85 ? ? ? ? 8B CB E8 ? ? ? ? 4C", 0, SIG_RELEVANCE_DIRECT_HIT }); // LiveConnect_BeginCrossAuthPlatform - - // Frame Hooks - signature_list.push_back({ "r_end_frame", "E8 ? ? ? ? 41 F6 DD 1B", 0, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "com_frame", "48 83 EC 48 48 C7 44 24 ? ? ? ? ? 48 8D 0D", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "g_run_frame", "48 8B C4 48 89 58 10 48 89 70 18 48 89 78 20 55 41 54 41 55 41 56 41 57 48 8D A8 C8 F7 FF FF", 0, SIG_RELEVANCE_DIRECT_HIT }); - - // Demonware - signature_list.push_back({ "curl_setup_ssl_verify_peer", "40 53 48 83 EC 20 BA ? ? ? ? 48 8B D9 48 8B", 0x29, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "curl_setup_ssl_verify_host", "40 53 48 83 EC 20 BA ? ? ? ? 48 8B D9 48 8B", 0x15, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "dw_https", "68 74 74 70 73 00", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "dw_prod_umbrella_url", "68 74 74 70 73 3A 2F 2F 70 72 6F 64 2E 75 6D 62 72 65 6C 6C 61 2E 64 65 6D 6F 6E 77 61 72 65 2E 6E 65 74 00", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "dw_prod_uno_url", "68 74 74 70 73 3A 2F 2F 70 72 6F 64 2E 75 6E 6F 2E 64 65 6D 6F 6E 77 61 72 65 2E 6E 65 74 2F 76 31 2E 30 00", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "dw_auth3_url_frmt", "68 74 74 70 73 3A 2F 2F 25 73 3A 25 64 2F 61 75 74 68 2F 00", 0, SIG_RELEVANCE_DIRECT_HIT }); - - // BuildNumber - signature_list.push_back({ "com_get_build_version", "40 53 48 83 EC 40 44 8B 0D", 0, SIG_RELEVANCE_DIRECT_HIT }); - - // UI Symbols - signature_list.push_back({ "ui_get_model_for_controller", "48 63 C1 48 8D 0D ? ? ? ? 0F B7 04", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "ui_create_model_from_path", "45 33 C9 41 B0 01 E9", 0, SIG_RELEVANCE_DIRECT_HIT }); - signature_list.push_back({ "ui_model_set_string", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 8B DA 49 8B F1", 0x4E, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "ui_model_set_int", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 8B DA 49 8B F1", 0x20, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "ui_model_set_bool", "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 20 8B DA 49 8B F1", 0x31, SIG_RELEVANCE_JMP_FROM }); - signature_list.push_back({ "ui_model_set_real", "48 83 EC 28 66 85 C9 74 3A", 0, SIG_RELEVANCE_DIRECT_HIT }); - - - //// Impossible to make signature; should be updated manually - //signature_list.push_back({ "bnet_process_auth3_data", "", 0x000000000_g, SIG_RELEVANCE_IMPOSSIBLE }); - //signature_list.push_back({ "bnet_patch_text_chat", "", 0x000000000_g, SIG_RELEVANCE_IMPOSSIBLE }); - - - logger::write(logger::LOG_TYPE_DEBUG, "[ DISCOVERY ]: Starting signature scan; total defined symbols: %u", signature_list.size()); - - symbols_list.clear(); - int error_count = 0; - - for (sig_instance i : signature_list) - { - if (i.relv == SIG_RELEVANCE_IMPOSSIBLE) - { - symbols_list.insert({ i.name, i.dist }); - continue; - } - - utilities::hook::signature::signature_result scan = utilities::hook::signature(std::string(i.sig, strlen(i.sig))).process(); - - if (scan.size() == 0 || scan.size() > 1) - { - logger::write(logger::LOG_TYPE_DEBUG, "[ DISCOVERY ]: %s while searching for %s", scan.size() ? "Multiple Matches" : "No Hits", i.name); - error_count++; - continue; - } - - if (i.relv == SIG_RELEVANCE_DIRECT_HIT) - { - symbols_list.insert({ i.name, reinterpret_cast(scan[0]) + i.dist }); - } - else if (i.relv == SIG_RELEVANCE_JMP_FROM) - { - symbols_list.insert({ i.name, follow_jmp(reinterpret_cast(scan[0]) + i.dist) }); - } - else - { - symbols_list.insert({ i.name, follow_lea(reinterpret_cast(scan[0]) + i.dist) }); - } - } - -#ifdef DEBUG - logger::write(logger::LOG_TYPE_DEBUG, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); - - if (symbols_list.find("com_get_build_version") != symbols_list.end()) - { - const char* build_version = utilities::hook::invoke(symbols_list["com_get_build_version"]); - logger::write(logger::LOG_TYPE_DEBUG, "Address-List Discovery Results for BlackOps4 %s", build_version); - } - - for (auto symbol : symbols_list) - { - logger::write(logger::LOG_TYPE_DEBUG, "- %-28s: 0x%llX_g", symbol.first.c_str(), reverse_g(symbol.second)); - } - - logger::write(logger::LOG_TYPE_DEBUG, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); -#endif // DEBUG - - logger::write(logger::LOG_TYPE_DEBUG, "[ DISCOVERY ]: Signature scanning complete. %u/%u successful", signature_list.size() - error_count, signature_list.size()); - } - class component final : public component_interface - { - public: - void post_unpack() override - { -#ifdef DEBUG - start_address_list_discovery(); -#endif // DEBUG - - /************************************************************************************************************* - ** NOTE : Updating game code by developers depending on compiler and where and what changes made, most likely - ** will shift addresses. using signature patterns to find addresses at runtime is a good counter to this - ** problem when game gets updated frequently but there should be decent fail-safe mechanism implemented - ** to detect sig-scanning errors when there is signature-breaking changes in binary to prevent misleadings - ** - *************************************************************************************************************/ - } - - int priority() override - { - return 9998; - } - }; -} - -//REGISTER_COMPONENT(discovery::component) diff --git a/source/proxy-dll/definitions/discovery.hpp b/source/proxy-dll/definitions/discovery.hpp deleted file mode 100644 index 4638cc1..0000000 --- a/source/proxy-dll/definitions/discovery.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -size_t operator"" _d(const char* str, size_t len); - -namespace discovery -{ - enum sig_relation - { - SIG_RELEVANCE_IMPOSSIBLE = -1, - SIG_RELEVANCE_DIRECT_HIT = 0, - SIG_RELEVANCE_LEA_FROM = 1, - SIG_RELEVANCE_JMP_FROM = 2 - }; - - struct sig_instance - { - const char* name; - const char* sig; - size_t dist; - sig_relation relv; - }; -} \ No newline at end of file diff --git a/source/proxy-dll/definitions/game.cpp b/source/proxy-dll/definitions/game.cpp index 8c80a6b..b5a866c 100644 --- a/source/proxy-dll/definitions/game.cpp +++ b/source/proxy-dll/definitions/game.cpp @@ -1,14 +1,30 @@ #include #include "game.hpp" -#include "loader/component_loader.hpp" namespace game { - std::string version_string = "VERSION STRING UN-INITIALIZED"; + const char* Com_GetVersionString() + { + static std::string version_string{}; - typedef const char* (__fastcall* Com_GetBuildVersion_t)(); - Com_GetBuildVersion_t Com_GetBuildVersion = (Com_GetBuildVersion_t)0x142892F40_g; + if (version_string.empty()) { + version_string = std::format("BlackOps4 {}", Com_GetBuildVersion()); + } + return version_string.data(); + } + + void verify_game_version() + { + if (*(int*)0x1449CA7E8_g != 13869365) // BlackOps4 CL(13869365) BEYQBBUILD106 DEV [Wed Feb 22 16:31:32 2023] + { + throw std::runtime_error("Unsupported BlackOps4.exe Version. This DLL Expects Latest BNET Build"); + } + +#ifdef DEBUG + logger::write(logger::LOG_TYPE_DEBUG, "[ SYSTEM ]: Verified Game Version '%s'", Com_GetVersionString()); +#endif // DEBUG + } scoped_critical_section::scoped_critical_section(int32_t s, scoped_critical_section_type type) : _s(0), _hasOwnership(false), _isScopedRelease(false), _next(nullptr) { @@ -19,42 +35,4 @@ namespace game { game::ScopedCriticalSectionDestructor(this); } - - namespace - { - void verify_game_version() - { - if (*(int*)0x1449CA7E8_g != 13869365) // BlackOps4 CL(13869365) BEYQBBUILD106 DEV [Wed Feb 22 16:31:32 2023] - { - throw std::runtime_error("Unsupported BlackOps4.exe Version. Update Your game using Battle.net Launcher"); - } - - version_string = std::format("BlackOps4 {}", Com_GetBuildVersion()); - -#ifdef DEBUG - logger::write(logger::LOG_TYPE_DEBUG, "[ SYSTEM ]: game version string: %s", version_string.c_str()); -#endif // DEBUG - } - } - - class component final : public component_interface - { - public: - void pre_start() override - { - /* PLACE_HOLDER */ - } - - void post_unpack() override - { - verify_game_version(); - } - - int priority() override - { - return 9997; - } - }; -} - -REGISTER_COMPONENT(game::component) \ No newline at end of file +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/game.hpp b/source/proxy-dll/definitions/game.hpp index 18cad94..c1e58e4 100644 --- a/source/proxy-dll/definitions/game.hpp +++ b/source/proxy-dll/definitions/game.hpp @@ -1,6 +1,7 @@ #pragma once - -#include "definitions/discovery.hpp" +#include "keys.hpp" +#include "network.hpp" +#include "scripting.hpp" #include "definitions/variables.hpp" #define WEAK __declspec(selectany) @@ -8,22 +9,25 @@ namespace game { ////////////////////////////////////////////////////////////////////////// - // VARIABLES // + // SHIELD // ////////////////////////////////////////////////////////////////////////// - - extern std::string version_string; + + void verify_game_version(); + + const char* Com_GetVersionString(); + + /////////////////////////////////////////////////////////////////////////// + // TYPES // + /////////////////////////////////////////////////////////////////////////// typedef float vec_t; typedef vec_t vec2_t[2]; typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; - typedef uint32_t ScrVarIndex_t; - typedef uint64_t ScrVarNameIndex_t; - - ////////////////////////////////////////////////////////////////////////// - // STRUCTS // - ////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + // STRUCTS // + /////////////////////////////////////////////////////////////////////////// struct BO4_AssetRef_t { @@ -40,508 +44,14 @@ namespace game return m128i; } - typedef void (*xcommand_t)(void); - - struct cmd_function_t + inline BO4_AssetRef_t + AssetRef(const char* nameRef) { - cmd_function_t* next; - uint64_t name; - uint64_t pad0; - uint64_t pad1; - uint64_t pad2; - xcommand_t function; - }; + BO4_AssetRef_t m128i; + m128i.hash = fnv1a::generate_hash(nameRef); - struct GSC_IMPORT_ITEM - { - uint32_t name; - uint32_t name_space; - uint16_t num_address; - uint8_t param_count; - uint8_t flags; - }; - - struct GSC_EXPORT_ITEM - { - uint32_t checksum; - uint32_t address; - uint32_t name; - uint32_t name_space; - uint32_t callback_event; - uint8_t param_count; - uint8_t flags; - }; - - struct GSC_OBJ - { - byte magic[8]; - int32_t crc; - int32_t pad; - uint64_t name; - int32_t include_offset; - uint16_t string_count; - uint16_t exports_count; - int32_t start_data; - int32_t string_offset; - int16_t imports_count; - uint16_t fixup_count; - int32_t ukn2c; - int32_t exports_offset; - int32_t ukn34; - int32_t imports_offset; - uint16_t globalvar_count; - int32_t fixup_offset; - int32_t globalvar_offset; - int32_t script_size; - int32_t requires_implements_offset; - int32_t ukn50; - int32_t data_length; - uint16_t include_count; - byte ukn5a; - byte requires_implements_count; - - inline GSC_EXPORT_ITEM* get_exports() - { - return reinterpret_cast(magic + exports_offset); - } - - inline GSC_IMPORT_ITEM* get_imports() - { - return reinterpret_cast(magic + imports_offset); - } - - inline uint64_t* get_includes() - { - return reinterpret_cast(magic + include_offset); - } - - inline GSC_EXPORT_ITEM* get_exports_end() - { - return get_exports() + exports_count; - } - - inline uint64_t* get_includes_end() - { - return get_includes() + include_count; - } - }; - - - enum scriptInstance_t : int32_t - { - SCRIPTINSTANCE_SERVER = 0x0, - SCRIPTINSTANCE_CLIENT = 0x1, - SCRIPTINSTANCE_MAX = 0x2, - }; - - typedef void (*BuiltinFunction)(scriptInstance_t); - - - struct BO4_BuiltinFunctionDef - { - uint32_t canonId; - uint32_t min_args; - uint32_t max_args; - BuiltinFunction actionFunc; - uint32_t type; - }; - - struct __declspec(align(4)) BO4_scrVarGlobalVars_t - { - uint32_t name; - ScrVarIndex_t id; - bool persist; - }; - - - enum ScrVarType_t : uint32_t { - TYPE_UNDEFINED = 0x0, - TYPE_POINTER = 0x1, - TYPE_STRING = 0x2, - TYPE_VECTOR = 0x3, - TYPE_HASH = 0x4, - TYPE_FLOAT = 0x5, - TYPE_INTEGER = 0x6, - TYPE_UINTPTR = 0x7, - TYPE_ENTITY_OFFSET = 0x8, - TYPE_CODEPOS = 0x9, - TYPE_PRECODEPOS = 0xA, - TYPE_API_FUNCTION = 0xB, - TYPE_SCRIPT_FUNCTION = 0xC, - TYPE_STACK = 0xD, - TYPE_THREAD = 0xE, - TYPE_NOTIFY_THREAD = 0xF, - TYPE_TIME_THREAD = 0x10, - TYPE_FRAME_THREAD = 0x11, - TYPE_CHILD_THREAD = 0x12, - TYPE_CLASS = 0x13, - TYPE_SHARED_STRUCT = 0x14, - TYPE_STRUCT = 0x15, - TYPE_REMOVED_ENTITY = 0x16, - TYPE_ENTITY = 0x17, - TYPE_ARRAY = 0x18, - TYPE_REMOVED_THREAD = 0x19, - TYPE_FREE = 0x1a, - TYPE_THREAD_LIST = 0x1b, - TYPE_ENT_LIST = 0x1c, - TYPE_COUNT - }; - - - struct BO4_scrVarPub { - const char* fieldBuffer; - const char* error_message; - byte* programBuffer; - byte* endScriptBuffer; - byte* programHunkUser; // HunkUser - BO4_scrVarGlobalVars_t globalVars[16]; - ScrVarNameIndex_t entFieldNameIndex; - ScrVarIndex_t freeEntList; - ScrVarIndex_t tempVariable; - uint32_t checksum; - uint32_t entId; - uint32_t varHighWatermark; - uint32_t numScriptThreads; - uint32_t numVarAllocations; - int32_t varHighWatermarkId; - }; - - union ScrVarValueUnion_t - { - int64_t intValue; - uintptr_t uintptrValue; - float floatValue; - int32_t stringValue; - const float* vectorValue; - byte* codePosValue; - ScrVarIndex_t pointerValue; - }; - - struct ScrVarValue_t - { - ScrVarValueUnion_t u; - ScrVarType_t type; - }; - - struct ScrVar_t_Info - { - uint32_t nameType : 3; - uint32_t flags : 5; - uint32_t refCount : 24; - }; - - struct ScrVar_t - { - ScrVarNameIndex_t nameIndex; - ScrVar_t_Info _anon_0; - ScrVarIndex_t nextSibling; - ScrVarIndex_t prevSibling; - ScrVarIndex_t parentId; - ScrVarIndex_t nameSearchHashList; - uint32_t pad0; - }; - - union ScrVarObjectInfo1_t - { - uint64_t object_o; - unsigned int size; - ScrVarIndex_t nextEntId; - ScrVarIndex_t self; - ScrVarIndex_t free; - }; - - union ScrVarObjectInfo2_t - { - uint32_t object_w; - ScrVarIndex_t stackId; - }; - - struct function_stack_t - { - byte* pos; - ScrVarValue_t* top; - ScrVarValue_t* startTop; - ScrVarIndex_t threadId; - uint16_t localVarCount; - uint16_t profileInfoCount; - }; - - struct function_frame_t - { - function_stack_t fs; - }; - - struct ScrVmContext_t - { - ScrVarIndex_t fieldValueId; - ScrVarIndex_t objectId; - byte* lastGoodPos; - ScrVarValue_t* lastGoodTop; - }; - - typedef void (*VM_OP_FUNC)(scriptInstance_t, function_stack_t*, ScrVmContext_t*, bool*); - - - struct BO4_scrVarGlob - { - ScrVarIndex_t* scriptNameSearchHashList; - ScrVar_t* scriptVariables; - ScrVarObjectInfo1_t* scriptVariablesObjectInfo1; - ScrVarObjectInfo2_t* scriptVariablesObjectInfo2; - ScrVarValue_t* scriptValues; - }; - - struct BO4_scrVmPub - { - void* unk0; - void* unk8; - void* executionQueueHeap; // HunkUser - void* timeByValueQueue; // VmExecutionQueueData_t - void* timeByThreadQueue[1024]; // VmExecutionQueue_t - void* frameByValueQueue; // VmExecutionQueueData_t - void* frameByThreadQueue[1024]; // VmExecutionQueue_t - void* timeoutByValueList; // VmExecutionQueueData_t - void* timeoutByThreadList[1024]; // VmExecutionQueue_t - void* notifyByObjectQueue[1024]; // VmExecutionNotifyQueue_t - void* notifyByThreadQueue[1024]; // VmExecutionNotifyQueue_t - void* endonByObjectList[1024]; // VmExecutionNotifyQueue_t - void* endonByThreadList[1024]; // VmExecutionNotifyQueue_t - ScrVarIndex_t* localVars; - ScrVarValue_t* maxstack; - function_frame_t* function_frame; - ScrVarValue_t* top; - function_frame_t function_frame_start[64]; - ScrVarValue_t stack[2048]; - uint32_t time; - uint32_t frame; - int function_count; - int callNesting; - unsigned int inparamcount; - bool showError; - bool systemInitialized; - bool vmInitialized; - bool isShutdown; - }; - - struct objFileInfo_t - { - GSC_OBJ* activeVersion; - int slot; - int refCount; - uint32_t groupId; - }; - - enum keyNum_t - { - K_NONE = 0x00, - K_BUTTON_A = 0x01, - K_BUTTON_B = 0x02, - K_BUTTON_X = 0x03, - K_BUTTON_Y = 0x04, - K_BUTTON_LSHLDR = 0x05, - K_BUTTON_RSHLDR = 0x06, - K_UNK7 = 0x07, - K_UNK8 = 0x08, - K_TAB = 0x09, - K_UNK10 = 0x0A, - K_UNK11 = 0x0B, - K_UNK12 = 0x0C, - K_ENTER = 0x0D, - K_BUTTON_START = 0x0E, - K_BUTTON_BACK = 0x0F, - K_BUTTON_LSTICK = 0x10, - K_BUTTON_RSTICK = 0x11, - K_BUTTON_LTRIG = 0x12, - K_BUTTON_RTRIG = 0x13, - K_UNK20 = 0x14, - K_UNK21 = 0x15, - K_DPAD_UP = 0x16, - K_DPAD_DOWN = 0x17, - K_DPAD_LEFT = 0x18, - K_DPAD_RIGHT = 0x19, - K_UNK26 = 0x1A, - K_ESCAPE = 0x1B, - K_APAD_UP = 0x1C, - K_APAD_DOWN = 0x1D, - K_APAD_LEFT = 0x1E, - K_APAD_RIGHT = 0x1F, - K_SPACE = 0x20, - K_UNK33 = 0x21, - K_UNK34 = 0x22, - K_UNK35 = 0x23, - K_UNK36 = 0x24, - K_UNK37 = 0x25, - K_UNK38 = 0x26, - K_UNK39 = 0x27, - K_UNK40 = 0x28, - K_UNK41 = 0x29, - K_UNK42 = 0x2A, - K_UNK43 = 0x2B, - K_UNK44 = 0x2C, - K_UNK45 = 0x2D, - K_UNK46 = 0x2E, - K_UNK47 = 0x2F, - K_UNK48 = 0x30, - K_UNK49 = 0x31, - K_UNK50 = 0x32, - K_UNK51 = 0x33, - K_UNK52 = 0x34, - K_UNK53 = 0x35, - K_UNK54 = 0x36, - K_UNK55 = 0x37, - K_UNK56 = 0x38, - K_UNK57 = 0x39, - K_UNK58 = 0x3A, - K_SEMICOLON = 0x3B, - K_UNK60 = 0x3C, - K_UNK61 = 0x3D, - K_UNK62 = 0x3E, - K_UNK63 = 0x3F, - K_UNK64 = 0x40, - K_UNK65 = 0x41, - K_UNK66 = 0x42, - K_UNK67 = 0x43, - K_UNK68 = 0x44, - K_UNK69 = 0x45, - K_UNK70 = 0x46, - K_UNK71 = 0x47, - K_UNK72 = 0x48, - K_UNK73 = 0x49, - K_UNK74 = 0x4A, - K_UNK75 = 0x4B, - K_UNK76 = 0x4C, - K_UNK77 = 0x4D, - K_UNK78 = 0x4E, - K_UNK79 = 0x4F, - K_UNK80 = 0x50, - K_UNK81 = 0x51, - K_UNK82 = 0x52, - K_UNK83 = 0x53, - K_UNK84 = 0x54, - K_UNK85 = 0x55, - K_UNK86 = 0x56, - K_UNK87 = 0x57, - K_UNK88 = 0x58, - K_UNK89 = 0x59, - K_UNK90 = 0x5A, - K_UNK91 = 0x5B, - K_UNK92 = 0x5C, - K_UNK93 = 0x5D, - K_UNK94 = 0x5E, - K_UNK95 = 0x5F, - K_GRAVE = 0x60, - K_UNK97 = 0x61, - K_UNK98 = 0x62, - K_UNK99 = 0x63, - K_UNK100 = 0x64, - K_UNK101 = 0x65, - K_UNK102 = 0x66, - K_UNK103 = 0x67, - K_UNK104 = 0x68, - K_UNK105 = 0x69, - K_UNK106 = 0x6A, - K_UNK107 = 0x6B, - K_UNK108 = 0x6C, - K_UNK109 = 0x6D, - K_UNK110 = 0x6E, - K_UNK111 = 0x6F, - K_UNK112 = 0x70, - K_UNK113 = 0x71, - K_UNK114 = 0x72, - K_UNK115 = 0x73, - K_UNK116 = 0x74, - K_UNK117 = 0x75, - K_UNK118 = 0x76, - K_UNK119 = 0x77, - K_UNK120 = 0x78, - K_UNK121 = 0x79, - K_UNK122 = 0x7A, - K_UNK123 = 0x7B, - K_UNK124 = 0x7C, - K_UNK125 = 0x7D, - K_TILDE = 0x7E, - K_BACKSPACE = 0x7F, - K_CAPSLOCK = 0x80, - K_PAUSE = 0x81, - K_PRINTSCREEN = 0x82, - K_SCROLLLOCK = 0x83, - K_UPARROW = 0x84, - K_DOWNARROW = 0x85, - K_LEFTARROW = 0x86, - K_RIGHTARROW = 0x87, - K_LALT = 0x88, - K_RALT = 0x89, - K_LCTRL = 0x8A, - K_RCTRL = 0x8B, - K_LSHIFT = 0x8C, - K_RSHIFT = 0x8D, - K_HIRAGANA = 0x8E, - K_HENKAN = 0x8F, - K_MUHENKAN = 0x90, - K_LWIN = 0x91, - K_RWIN = 0x92, - K_MENU = 0x93, - K_INS = 0x94, - K_DEL = 0x95, - K_PGDN = 0x96, - K_PGUP = 0x97, - K_HOME = 0x98, - K_END = 0x99, - K_F1 = 0x9A, - K_F2 = 0x9B, - K_F3 = 0x9C, - K_F4 = 0x9D, - K_F5 = 0x9E, - K_F6 = 0x9F, - K_F7 = 0xA0, - K_F8 = 0xA1, - K_F9 = 0xA2, - K_F10 = 0xA3, - K_F11 = 0xA4, - K_F12 = 0xA5, - K_UNK166 = 0xA6, - K_UNK167 = 0xA7, - K_UNK168 = 0xA8, - K_KP_HOME = 0xA9, - K_KP_UPARROW = 0xAA, - K_KP_PGUP = 0xAB, - K_KP_LEFTARROW = 0xAC, - K_KP_5 = 0xAD, - K_KP_RIGHTARROW = 0xAE, - K_KP_END = 0xAF, - K_KP_DOWNARROW = 0xB0, - K_KP_PGDN = 0xB1, - K_KP_ENTER = 0xB2, - K_KP_INS = 0xB3, - K_KP_DEL = 0xB4, - K_KP_SLASH = 0xB5, - K_KP_MINUS = 0xB6, - K_KP_PLUS = 0xB7, - K_KP_NUMLOCK = 0xB8, - K_KP_STAR = 0xB9, - K_MOUSE1 = 0xBA, - K_MOUSE2 = 0xBB, - K_MOUSE3 = 0xBC, - K_MOUSE4 = 0xBD, - K_MOUSE5 = 0xBE, - K_MWHEELDOWN = 0xBF, - K_MWHEELUP = 0xC0 - }; - - struct KeyState - { - int down; - int repeats; - int binding; - char pad[20]; - }; // size = 32 - - struct PlayerKeyState - { - bool overstrikeMode; - int anyKeyDown; - KeyState keys[256]; - }; + return m128i; + } struct AssetCache { @@ -596,18 +106,6 @@ namespace game ITEM_TEXTSTYLE_MONOSPACESHADOWED = 132, }; - enum errorParm - { - ERR_FATAL = 0, - ERR_DROP = 1, - ERR_SERVERDISCONNECT = 2, - ERR_DISCONNECT = 3, - ERR_SCRIPT = 4, - ERR_SCRIPT_DROP = 5, - ERR_LOCALIZATION = 6, - ERR_MAPLOADERRORSUMMARY = 7, - }; - enum dvarType_t { DVAR_TYPE_INVALID = 0x0, @@ -724,7 +222,76 @@ namespace game DvarLimits domain; char padding_unk2[8]; }; + + typedef void (*xcommand_t)(void); + + struct cmd_function_t + { + cmd_function_t* next; + BO4_AssetRef_t name; + const char* autoCompleteDir; + const char* autoCompleteExt; + xcommand_t function; + int autoComplete; + }; + struct CmdArgs + { + int nesting; + int localClientNum[8]; + int controllerIndex[8]; + int argshift[8]; + int argc[8]; + const char** argv[8]; + char textPool[8192]; + const char* argvPool[512]; + int usedTextPool[8]; + int totalUsedArgvPool; + int totalUsedTextPool; + }; + + struct va_info_t + { + char va_string[4][1024]; + int index; + }; + + struct TLSData + { + va_info_t* vaInfo; + jmp_buf* errorJmpBuf; + void* traceInfo; + CmdArgs* cmdArgs; + void* errorData; + }; + + /////////////////////////////////////////////////////////////////////////// + // ENUMS // + /////////////////////////////////////////////////////////////////////////// + + enum errorParm + { + ERR_FATAL = 0, + ERR_DROP = 1, + ERR_SERVERDISCONNECT = 2, + ERR_DISCONNECT = 3, + ERR_SCRIPT = 4, + ERR_SCRIPT_DROP = 5, + ERR_LOCALIZATION = 6, + ERR_MAPLOADERRORSUMMARY = 7, + }; + + enum eGameModes + { + MODE_GAME_MATCHMAKING_PLAYLIST = 0x0, + MODE_GAME_MATCHMAKING_MANUAL = 0x1, + MODE_GAME_DEFAULT = 0x2, + MODE_GAME_LEAGUE = 0x3, + MODE_GAME_THEATER = 0x4, + MODE_GAME_COUNT = 0x5, + MODE_GAME_INVALID = 0x5, + }; + enum eModes : int32_t { MODE_ZOMBIES = 0x0, @@ -803,6 +370,10 @@ namespace game CON_LABEL_COUNT = 0x3F }; + /////////////////////////////////////////////////////////////////////////// + // CLASSES // + /////////////////////////////////////////////////////////////////////////// + enum scoped_critical_section_type : int32_t { SCOPED_CRITSECT_NORMAL = 0x0, @@ -822,6 +393,10 @@ namespace game ~scoped_critical_section(); }; + /////////////////////////////////////////////////////////////////////////// + // HAVOK // + /////////////////////////////////////////////////////////////////////////// + struct hks_global {}; struct hks_callstack { @@ -866,9 +441,9 @@ namespace game // ... }; - ////////////////////////////////////////////////////////////////////////// - // SYMBOLS // - ////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + // SYMBOLS // + /////////////////////////////////////////////////////////////////////////// template class symbol @@ -898,25 +473,49 @@ namespace game T* address_; }; - // Main Functions + // Main WEAK symbol Com_Error_{ 0x14288B410_g }; - // mutex + // Sys + WEAK symbol Sys_Milliseconds{ 0x143D89E80_g }; + WEAK symbol Sys_GetTLS{ 0x143C56140_g }; + + // Mutex WEAK symbol ScopedCriticalSectionConstructor{ 0x14289E3C0_g }; WEAK symbol ScopedCriticalSectionDestructor{ 0x14289E440_g }; - // CMD - WEAK symbol Cbuf_AddText{ 0x143CDE880_g }; - // Dvar WEAK symbol Dvar_FindVar{ 0x143CEBE40_g }; WEAK symbol Dvar_FindVar_Hash{ 0x143CEBED0_g }; - // Live Functions + // Cmd + WEAK symbol Cbuf_AddText{ 0x143CDE880_g }; + WEAK symbol Cbuf_ExecuteBuffer{ 0x143CDEBE0_g }; + + WEAK symbol Cmd_AddCommandInternal{ 0x143CDEE80_g }; + WEAK symbol Cbuf_AddServerText_f{ 0x143CDE870_g }; + WEAK symbol Cmd_AddServerCommandInternal{ 0x143CDEEF0_g }; + WEAK symbol Cmd_ExecuteSingleCommand{ 0x143CDF490_g }; + + WEAK symbol Cmd_TokenizeStringKernel{ 0x143CE0750_g }; + + WEAK symbol Cmd_EndTokenizedString{ 0x143CDF070_g }; + WEAK symbol SV_Cmd_TokenizeString{ 0x143CE0A10_g }; + WEAK symbol SV_Cmd_EndTokenizedString{ 0x143CE09C0_g }; + + // NET + WEAK symbol NET_OutOfBandData{ 0x142E06390_g }; + WEAK symbol Sys_SendPacket{ 0x143D89900_g }; + WEAK symbol NetAdr_InitFromString{ 0x142E05230_g }; + WEAK symbol NetAdr_IsTheSameAddr{ 0x142E053A0_g }; + + // Live WEAK symbol Live_GetConnectivityInformation{ 0x1437FA460_g }; - // Rendering Functions - WEAK symbol T8_AddBaseDrawTextCmd{ 0x143616B60_g }; + // Renderer + WEAK symbol T8_AddBaseDrawTextCmd{ 0x143616B60_g }; WEAK symbol R_AddCmdDrawStretchPic{ 0x143616790_g }; WEAK symbol R_TextHeight{ 0x1435B2350_g }; @@ -927,19 +526,18 @@ namespace game WEAK symbol ScrPlace_GetView{ 0x142876E70_g }; + // BuildInfo + WEAK symbol Com_GetBuildVersion{ 0x142892F40_g }; + WEAK symbol Live_SystemInfo{ 0x143804B00_g }; + + // ETC WEAK symbol Com_IsInGame{ 0x14288FDB0_g }; WEAK symbol Com_IsRunningUILevel{ 0x14288FDF0_g }; WEAK symbol Com_SessionMode_GetMode{ 0x14289EFF0_g }; WEAK symbol Com_SessionMode_GetModeForAbbreviation{ 0x14289F000_g }; WEAK symbol Com_SessionMode_GetAbbreviationForMode{0x14289EC70_g}; - WEAK symbol keyCatchers{ 0x148A53F84_g }; - WEAK symbol playerKeys{ 0x148A3EF80_g }; - - WEAK symbol sharedUiInfo{ 0x14F956850_g }; - - // Scr Functions - + // SCR WEAK symbol ScrVm_AddBool{ 0x14276E760_g }; WEAK symbol ScrVm_AddFloat{ 0x14276E9B0_g }; WEAK symbol ScrVm_AddHash{ 0x14276EAB0_g }; @@ -981,23 +579,12 @@ namespace game WEAK symbol gObjFileInfoCount{ 0x1482F76B0_g }; WEAK symbol gObjFileInfo{ 0x1482EFCD0_g }; - // lua functions + // LUA WEAK symbol Lua_CoD_LoadLuaFile{ 0x143962DF0_g }; WEAK symbol Lua_CoD_LuaStateManager_Error{ 0x14398A860_g }; WEAK symbol hks_obj_tolstring{ 0x143755730_g }; WEAK symbol hks_obj_tonumber{ 0x143755A90_g }; - // console labels - WEAK symbol builtinLabels{ 0x144F11530_g }; - // gsc types - WEAK symbol var_typename{ 0x144EED240_g }; - - WEAK symbol Cmd_AddCommandInternal{0x143CDEE80_g}; - -#define Cmd_AddCommand(name, function) \ - static game::cmd_function_t __cmd_func_##function; \ - game::BO4_AssetRef_t __cmd_func_name_##function { (int64_t)fnv1a::generate_hash(name), 0 }; \ - game::Cmd_AddCommandInternal(&__cmd_func_name_##function, function, &__cmd_func_##function) #define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \ T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, -1, 0, 0) @@ -1008,11 +595,26 @@ namespace game #define Com_Error(code, fmt, ...) \ Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__) - class scoped_critical_section_guard_lock - { + + /////////////////////////////////////////////////////////////////////////// + // NAME TABLES // + /////////////////////////////////////////////////////////////////////////// + WEAK symbol var_typename{ 0x144EED240_g }; // GSC Types + + WEAK symbol builtinLabels{ 0x144F11530_g }; // Console Labels + /////////////////////////////////////////////////////////////////////////// + // VARIABLES // + /////////////////////////////////////////////////////////////////////////// + WEAK symbol sharedUiInfo{ 0x14F956850_g }; + WEAK symbol cmd_functions{ 0x14F99B188_g }; + WEAK symbol sv_cmd_args{ 0x14F998070_g }; - }; + WEAK symbol keyCatchers{ 0x148A53F84_g }; + WEAK symbol playerKeys{ 0x148A3EF80_g }; + + // Global game definitions + constexpr auto CMD_MAX_NESTING = 8; } \ No newline at end of file diff --git a/source/proxy-dll/definitions/game_runtime_errors.cpp b/source/proxy-dll/definitions/game_runtime_errors.cpp deleted file mode 100644 index 0c98474..0000000 --- a/source/proxy-dll/definitions/game_runtime_errors.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include "definitions/game.hpp" -#include "definitions/xassets.hpp" -#include "game_runtime_errors.hpp" - - -namespace game::runtime_errors -{ - namespace - { - std::unordered_map errors = - { - { 1045192683, "Scr_RandomFloatRange's second parameter must be greater than the first." }, - { 1047729873, "exitlevel already called" }, - { 104978404, "cannot cast type to canon" }, - { 1072585573, "Raw file is not a file of the right type" }, - { 1088278929, "Raw file is not a file of the right type" }, - { 1099145600, "Can't find asset" }, - { 1132507782, "bad opcode" }, - { 1137123674, "GScr_LUINotifyEvent: Expected Istrings, hash or integers only" }, - { 1252503459, "caller is not an entity" }, - { 1273214009, "CScr_PlayFX: invalid effect" }, - { 1333649786, "IsMature can only be called on a player." }, - { 1364331101, "Object must be an array" }, - { 1377489376, "Gesture key can't have the higher bit set" }, - { 1385570291, "assert fail (with message)" }, - { 1402557361, "bad opcode" }, - { 1403832952, "Attempt to register ClientField failed. Client Field set either already contains a field, or a hash collision has occurred." }, - { 1412130119, "parameter can't be cast to a hash" }, - { 1427704235, "expected struct type to add value pair" }, - { 1480037573, "Invalid canonical name hash" }, - { 1480821566, "Error registering client field. Attempted field size is not acceptable bit number range 1->32" }, - { 1517473035, "Value out of range. Allowed values: 0 to 2" }, - { 1609894461, "bad entity" }, - { 1670707254, "linking error" }, - { 1850691545, "Debug Break" }, - { 1895566756, "dvar is not a 3d vector, but GetDvarVector3D has been called on it" }, - { 1909233687, "Optional argument must be a vector type" }, - { 1915758537, "RegisterClientField can only accept bit ranges between 1 and 32." }, - { 1957162421, "Can't find bgCache entry" }, - { 1999906612, "type is not a integer or float" }, - { 2078816051, "not a valid name for a clientfield set." }, - { 209668787, "RandomInt parm must be positive integer." }, - { 2116335949, "function called with too many parameters" }, - { 219569925, "hasperk() can only be called on local players" }, - { 219686544, "object is not an array index" }, - { 2253722136, "CamAnimScripted can only be called on a player." }, - { 2269096660, "vector scale expecting vector" }, - { 2279633554, "SV_SetConfigstring: bad index" }, - { 2331090760, "stack does not have the pool" }, - { 2344222932, "assert fail" }, - { 2355618801, "Gesture table key can't have the higher bit set" }, - { 2408700928, "not a valid name for a clientfield set." }, - { 2448966512, "string too long" }, - { 245612264, "foreach should be used with an array" }, - { 247375020, "Attempting to register client field in client field set using bits, but system is out of space." }, - { 2479879368, "RegisterClientField can only accept bit ranges between 1 and 32." }, - { 249068885, "Failed to allocate from state pool" }, - { 2517242050, "parameter does not exist" }, - { 2532286589, "error message" }, - { 2538360978, "not a function pointer" }, - { 2572009355, "vector scale expecting vector" }, - { 2606724305, "parameter does not exist" }, - { 2626909173, "exceeded maximum number of script strings" }, - { 2681972741, "bad clientfield for name" }, - { 2687742442, "Forced script exception." }, - { 269518924, "Ammo count must not be negative" }, - { 2706458388, "Trying to get a local client index for a client that is not a local client." }, - { 2734491973, "Error need at least one argument for LUINotifyEvent." }, - { 2737681163, "assert fail (with message)" }, - { 2751867714, "self isn't a field object" }, - { 2792722947, "RegisterClientField can only accept 5 parameters" }, - { 280703902, "parameter does not exist" }, - { 2838301872, "Gesture table key can't have the higher bit set" }, - { 2855209542, "Cannot call IncrementClientField on a non-'counter' type clientfield." }, - { 2940210599, "Invalid Version Handling. Grab Bat !!!" }, - { 3015158315, "getperks() can only be called on local players" }, - { 3016026156, "Can't find asset" }, - { 3030895505, "Whitelist failure for title" }, - { 3059411687, "Argument and parameter count mismatch for LUINotifyEvent" }, - { 3086288875, "playFx called with (0 0 0) forward direction" }, - { 3122940489, "caller is not an entity" }, - { 312545010, "not a vector" }, - { 3143575744, "parameter does not exist" }, - { 317100267, "unmatching types" }, - { 3189465155, "Invalid bgCache type" }, - { 3221522156, "Failed to alloc client field" }, - { 3222417139, "size cannot be applied to type" }, - { 3251676101, "Could not load raw file" }, - { 3255107847, "LUINotifyEvent: entity must be a player entity" }, - { 3288551912, "expected array type to add value pair" }, - { 3385008561, "cannot set field on type" }, - { 3459949409, "Failed to alloc client field - MAX_CLIENTFIELD_FIELDS_IN_SET=512 exceeded." }, - { 3523382186, "ScrEvent map is full, unable to register new event" }, - { 3524483616, "Ammo count must not be negative" }, - { 3592841213, "cannot directly set the origin on AI. Use the teleport command instead." }, - { 359760836, "G_Spawn: no free entities" }, - { 3654063291, "ScrEvent map is full, unable to register new event" }, - { 3679846953, "LUINotifyEvent: entity must be a player entity" }, - { 3699844858, "parameter does not exist" }, - { 3761634992, "not a pointer" }, - { 3894031202, "Can't find gamedata/playeranim/playeranimtypes.txt" }, - { 3967909977, "Trying to get version of a demo when the demo system is idle." }, - { 3990130335, "player getperks(): localClientNum out of range" }, - { 4039057166, "LUINotifyEvent: entity must be a player entity" }, - { 4047738848, "Invalid opcode (Recovery)" }, - { 409067247, "No clientfield named found in set." }, - { 4100218247, "Error sending LUI notify event: LUI event name is not precached." }, - { 4103906837, "Entity is not an item." }, - { 4104994143, "can't allocate more script variables" }, - { 4106063796, "key value provided for array is not valid" }, - { 4163774148, "Optional argument must be a float or integer type" }, - { 4178589916, "Model was not cached by the linker." }, - { 4196473479, "parameter does not exist" }, - { 4213634562, "precacheLeaderboards must be called before any wait statements in the gametype or level script" }, - { 4220857104, "Cannot call IncrementClientField on a 'counter' type clientfield on the frame it is spawned, since newEnts on the clientside will not process 'counter' type clientfields." }, - { 467754466, "Error registering client field. bCallbacksFor0WhenNew (CF_CALLBACK_ZERO_ON_NEW_ENT) is disallowed for CF_SCRIPTMOVERFIELDS." }, - { 512306404, "not a function pointer" }, - { 57350207, "Unknown perk" }, - { 580674660, "Unknown ent type in GScr_GetFieldSetForEntityType." }, - { 619241173, "Failed to allocate from element pool" }, - { 647662103, "parameter can't be cast to a string" }, - { 657813230, "Error registering client field. bCallbacksFor0WhenNew (CF_CALLBACK_ZERO_ON_NEW_ENT) is disallowed for counter type clientfields. Due to it's treatment of the old and new val as a ring buffer, the counter type is not valid on a new snapshot, new ent, or demojump" }, - { 665902298, "Parameter must be an array" }, - { 71894325, "CamAnimScripted or ExtraCamAnimScripted can only be called on a player." }, - { 732489269, "Non-player entity passed to UploadStats()" }, - { 744499668, "too many vehicles" }, - { 750896894, "Invalid bgCache type" }, - { 753495682, "RandomIntRange's second parameter must be greater than the first." }, - { 754846421, "invalid vehicle spawn origin" }, - { 829015102, "var isn't a field object" }, - { 876169112, "key value provided for struct is not valid" }, - { 887228744, "origin being set to NAN." }, - { 904544970, "Attempt to register Client Field post finalization of Client Field registration period failed." }, - { 941828720, "exitlevel already called" }, - { 946363963, "Invalid opcode" }, - { 949934674, "Invalid Version Handling. Grab Bat !!!" }, - { 952690413, "parameter can't be cast to a boolean" }, - { 962032109, "Entity does not exist." }, - { 968521323, "player hasperk(, ): localClientNum out of range" }, - { 4088624643, "Can't find asset" }, - { game::runtime_errors::custom_error_id, "Shield Error" } - }; - } - - const char* get_error_message(uint64_t code) - { - auto it = errors.find(code); - // known error - if (it != errors.end()) - { - return it->second; - } - - // read from the csv - static game::BO4_AssetRef_t custom_errors_file = game::AssetRef(fnv1a::generate_hash("gamedata/shield/custom_errors.csv")); - - xassets::stringtable_header* table = xassets::DB_FindXAssetHeader(xassets::ASSET_TYPE_STRINGTABLE, &custom_errors_file, false, -1).stringtable; - - if (!table || !table->columns_count || table->columns_count < 2) - { - return nullptr; - } - - for (size_t i = 0; i < table->rows_count; i++) - { - auto* rows = &table->values[i * table->columns_count]; - - if (rows[0].type != xassets::STC_TYPE_INT || rows[1].type != xassets::STC_TYPE_STRING) - { - continue; // bad types - } - - if (rows[0].value.hash_value == code) - { - return rows[1].value.string_value; - } - } - - // unknown - return nullptr; - } - -} - diff --git a/source/proxy-dll/definitions/game_runtime_errors.hpp b/source/proxy-dll/definitions/game_runtime_errors.hpp deleted file mode 100644 index 760d67c..0000000 --- a/source/proxy-dll/definitions/game_runtime_errors.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace game::runtime_errors -{ - constexpr uint64_t custom_error_id = 0x42693201; - const char* get_error_message(uint64_t code); -} \ No newline at end of file diff --git a/source/proxy-dll/definitions/keys.cpp b/source/proxy-dll/definitions/keys.cpp new file mode 100644 index 0000000..b490296 --- /dev/null +++ b/source/proxy-dll/definitions/keys.cpp @@ -0,0 +1,7 @@ +#include +#include "keys.hpp" + +namespace game +{ + /* NAMESPACE_PLACE_HOLDER */ +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/keys.hpp b/source/proxy-dll/definitions/keys.hpp new file mode 100644 index 0000000..b7ec881 --- /dev/null +++ b/source/proxy-dll/definitions/keys.hpp @@ -0,0 +1,216 @@ +#pragma once + +namespace game +{ + enum keyNum_t + { + K_NONE = 0x00, + K_BUTTON_A = 0x01, + K_BUTTON_B = 0x02, + K_BUTTON_X = 0x03, + K_BUTTON_Y = 0x04, + K_BUTTON_LSHLDR = 0x05, + K_BUTTON_RSHLDR = 0x06, + K_UNK7 = 0x07, + K_UNK8 = 0x08, + K_TAB = 0x09, + K_UNK10 = 0x0A, + K_UNK11 = 0x0B, + K_UNK12 = 0x0C, + K_ENTER = 0x0D, + K_BUTTON_START = 0x0E, + K_BUTTON_BACK = 0x0F, + K_BUTTON_LSTICK = 0x10, + K_BUTTON_RSTICK = 0x11, + K_BUTTON_LTRIG = 0x12, + K_BUTTON_RTRIG = 0x13, + K_UNK20 = 0x14, + K_UNK21 = 0x15, + K_DPAD_UP = 0x16, + K_DPAD_DOWN = 0x17, + K_DPAD_LEFT = 0x18, + K_DPAD_RIGHT = 0x19, + K_UNK26 = 0x1A, + K_ESCAPE = 0x1B, + K_APAD_UP = 0x1C, + K_APAD_DOWN = 0x1D, + K_APAD_LEFT = 0x1E, + K_APAD_RIGHT = 0x1F, + K_SPACE = 0x20, + K_UNK33 = 0x21, + K_UNK34 = 0x22, + K_UNK35 = 0x23, + K_UNK36 = 0x24, + K_UNK37 = 0x25, + K_UNK38 = 0x26, + K_UNK39 = 0x27, + K_UNK40 = 0x28, + K_UNK41 = 0x29, + K_UNK42 = 0x2A, + K_UNK43 = 0x2B, + K_UNK44 = 0x2C, + K_UNK45 = 0x2D, + K_UNK46 = 0x2E, + K_UNK47 = 0x2F, + K_UNK48 = 0x30, + K_UNK49 = 0x31, + K_UNK50 = 0x32, + K_UNK51 = 0x33, + K_UNK52 = 0x34, + K_UNK53 = 0x35, + K_UNK54 = 0x36, + K_UNK55 = 0x37, + K_UNK56 = 0x38, + K_UNK57 = 0x39, + K_UNK58 = 0x3A, + K_SEMICOLON = 0x3B, + K_UNK60 = 0x3C, + K_UNK61 = 0x3D, + K_UNK62 = 0x3E, + K_UNK63 = 0x3F, + K_UNK64 = 0x40, + K_UNK65 = 0x41, + K_UNK66 = 0x42, + K_UNK67 = 0x43, + K_UNK68 = 0x44, + K_UNK69 = 0x45, + K_UNK70 = 0x46, + K_UNK71 = 0x47, + K_UNK72 = 0x48, + K_UNK73 = 0x49, + K_UNK74 = 0x4A, + K_UNK75 = 0x4B, + K_UNK76 = 0x4C, + K_UNK77 = 0x4D, + K_UNK78 = 0x4E, + K_UNK79 = 0x4F, + K_UNK80 = 0x50, + K_UNK81 = 0x51, + K_UNK82 = 0x52, + K_UNK83 = 0x53, + K_UNK84 = 0x54, + K_UNK85 = 0x55, + K_UNK86 = 0x56, + K_UNK87 = 0x57, + K_UNK88 = 0x58, + K_UNK89 = 0x59, + K_UNK90 = 0x5A, + K_UNK91 = 0x5B, + K_UNK92 = 0x5C, + K_UNK93 = 0x5D, + K_UNK94 = 0x5E, + K_UNK95 = 0x5F, + K_GRAVE = 0x60, + K_UNK97 = 0x61, + K_UNK98 = 0x62, + K_UNK99 = 0x63, + K_UNK100 = 0x64, + K_UNK101 = 0x65, + K_UNK102 = 0x66, + K_UNK103 = 0x67, + K_UNK104 = 0x68, + K_UNK105 = 0x69, + K_UNK106 = 0x6A, + K_UNK107 = 0x6B, + K_UNK108 = 0x6C, + K_UNK109 = 0x6D, + K_UNK110 = 0x6E, + K_UNK111 = 0x6F, + K_UNK112 = 0x70, + K_UNK113 = 0x71, + K_UNK114 = 0x72, + K_UNK115 = 0x73, + K_UNK116 = 0x74, + K_UNK117 = 0x75, + K_UNK118 = 0x76, + K_UNK119 = 0x77, + K_UNK120 = 0x78, + K_UNK121 = 0x79, + K_UNK122 = 0x7A, + K_UNK123 = 0x7B, + K_UNK124 = 0x7C, + K_UNK125 = 0x7D, + K_TILDE = 0x7E, + K_BACKSPACE = 0x7F, + K_CAPSLOCK = 0x80, + K_PAUSE = 0x81, + K_PRINTSCREEN = 0x82, + K_SCROLLLOCK = 0x83, + K_UPARROW = 0x84, + K_DOWNARROW = 0x85, + K_LEFTARROW = 0x86, + K_RIGHTARROW = 0x87, + K_LALT = 0x88, + K_RALT = 0x89, + K_LCTRL = 0x8A, + K_RCTRL = 0x8B, + K_LSHIFT = 0x8C, + K_RSHIFT = 0x8D, + K_HIRAGANA = 0x8E, + K_HENKAN = 0x8F, + K_MUHENKAN = 0x90, + K_LWIN = 0x91, + K_RWIN = 0x92, + K_MENU = 0x93, + K_INS = 0x94, + K_DEL = 0x95, + K_PGDN = 0x96, + K_PGUP = 0x97, + K_HOME = 0x98, + K_END = 0x99, + K_F1 = 0x9A, + K_F2 = 0x9B, + K_F3 = 0x9C, + K_F4 = 0x9D, + K_F5 = 0x9E, + K_F6 = 0x9F, + K_F7 = 0xA0, + K_F8 = 0xA1, + K_F9 = 0xA2, + K_F10 = 0xA3, + K_F11 = 0xA4, + K_F12 = 0xA5, + K_UNK166 = 0xA6, + K_UNK167 = 0xA7, + K_UNK168 = 0xA8, + K_KP_HOME = 0xA9, + K_KP_UPARROW = 0xAA, + K_KP_PGUP = 0xAB, + K_KP_LEFTARROW = 0xAC, + K_KP_5 = 0xAD, + K_KP_RIGHTARROW = 0xAE, + K_KP_END = 0xAF, + K_KP_DOWNARROW = 0xB0, + K_KP_PGDN = 0xB1, + K_KP_ENTER = 0xB2, + K_KP_INS = 0xB3, + K_KP_DEL = 0xB4, + K_KP_SLASH = 0xB5, + K_KP_MINUS = 0xB6, + K_KP_PLUS = 0xB7, + K_KP_NUMLOCK = 0xB8, + K_KP_STAR = 0xB9, + K_MOUSE1 = 0xBA, + K_MOUSE2 = 0xBB, + K_MOUSE3 = 0xBC, + K_MOUSE4 = 0xBD, + K_MOUSE5 = 0xBE, + K_MWHEELDOWN = 0xBF, + K_MWHEELUP = 0xC0 + }; + + struct KeyState + { + int down; + int repeats; + int binding; + char pad[20]; + }; // size = 32 + + struct PlayerKeyState + { + bool overstrikeMode; + int anyKeyDown; + KeyState keys[256]; + }; +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/network.cpp b/source/proxy-dll/definitions/network.cpp new file mode 100644 index 0000000..7620581 --- /dev/null +++ b/source/proxy-dll/definitions/network.cpp @@ -0,0 +1,7 @@ +#include +#include "network.hpp" + +namespace game +{ + /* NAMESPACE_PLACE_HOLDER */ +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/network.hpp b/source/proxy-dll/definitions/network.hpp new file mode 100644 index 0000000..6cc47aa --- /dev/null +++ b/source/proxy-dll/definitions/network.hpp @@ -0,0 +1,59 @@ +#pragma once + +namespace game +{ + struct netipv4_t + { + byte a; + byte b; + byte c; + byte d; + }; + + enum netadrtype_t + { + NA_BOT = 0x0, + NA_BAD = 0x1, + NA_LOOPBACK = 0x2, + NA_RAWIP = 0x3, + NA_IP = 0x4, + }; + + enum netsrc_t + { + NS_NULL = -1, + NS_CLIENT1 = 0x0, + NS_CLIENT2 = 0x1, + NS_CLIENT3 = 0x2, + NS_CLIENT4 = 0x3, + NS_SERVER = 0x4, + NS_MAXCLIENTS = 0x4, + NS_PACKET = 0x5, + }; + + struct netadr_t + { + union + { + netipv4_t ipv4; + uint32_t addr; + }; + + uint16_t port; + netadrtype_t type; + netsrc_t localNetID; + }; + + struct msg_t + { + byte* data; //0x0000 + int maxsize; //0x0008 + int cursize; //0x000C + int readcount; //0x0010 + char pad_unknown[32]; //0x0014 + bool unknown; //0x0034 + bool overflowed; //0x0035 + bool readOnly; //0x0036 + }; + +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/scripting.cpp b/source/proxy-dll/definitions/scripting.cpp new file mode 100644 index 0000000..6877b7d --- /dev/null +++ b/source/proxy-dll/definitions/scripting.cpp @@ -0,0 +1,7 @@ +#include +#include "scripting.hpp" + +namespace game +{ + /* NAMESPACE_PLACE_HOLDER */ +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/scripting.hpp b/source/proxy-dll/definitions/scripting.hpp new file mode 100644 index 0000000..d2f722f --- /dev/null +++ b/source/proxy-dll/definitions/scripting.hpp @@ -0,0 +1,286 @@ +#pragma once + +namespace game +{ + typedef uint32_t ScrVarIndex_t; + typedef uint64_t ScrVarNameIndex_t; + + struct GSC_IMPORT_ITEM + { + uint32_t name; + uint32_t name_space; + uint16_t num_address; + uint8_t param_count; + uint8_t flags; + }; + + struct GSC_EXPORT_ITEM + { + uint32_t checksum; + uint32_t address; + uint32_t name; + uint32_t name_space; + uint32_t callback_event; + uint8_t param_count; + uint8_t flags; + }; + + struct GSC_OBJ + { + byte magic[8]; + int32_t crc; + int32_t pad; + uint64_t name; + int32_t include_offset; + uint16_t string_count; + uint16_t exports_count; + int32_t start_data; + int32_t string_offset; + int16_t imports_count; + uint16_t fixup_count; + int32_t ukn2c; + int32_t exports_offset; + int32_t ukn34; + int32_t imports_offset; + uint16_t globalvar_count; + int32_t fixup_offset; + int32_t globalvar_offset; + int32_t script_size; + int32_t requires_implements_offset; + int32_t ukn50; + int32_t data_length; + uint16_t include_count; + byte ukn5a; + byte requires_implements_count; + + inline GSC_EXPORT_ITEM* get_exports() + { + return reinterpret_cast(magic + exports_offset); + } + + inline GSC_IMPORT_ITEM* get_imports() + { + return reinterpret_cast(magic + imports_offset); + } + + inline uint64_t* get_includes() + { + return reinterpret_cast(magic + include_offset); + } + + inline GSC_EXPORT_ITEM* get_exports_end() + { + return get_exports() + exports_count; + } + + inline uint64_t* get_includes_end() + { + return get_includes() + include_count; + } + }; + + + enum scriptInstance_t : int32_t + { + SCRIPTINSTANCE_SERVER = 0x0, + SCRIPTINSTANCE_CLIENT = 0x1, + SCRIPTINSTANCE_MAX = 0x2, + }; + + typedef void (*BuiltinFunction)(scriptInstance_t); + + + struct BO4_BuiltinFunctionDef + { + uint32_t canonId; + uint32_t min_args; + uint32_t max_args; + BuiltinFunction actionFunc; + uint32_t type; + }; + + struct __declspec(align(4)) BO4_scrVarGlobalVars_t + { + uint32_t name; + ScrVarIndex_t id; + bool persist; + }; + + + enum ScrVarType_t : uint32_t { + TYPE_UNDEFINED = 0x0, + TYPE_POINTER = 0x1, + TYPE_STRING = 0x2, + TYPE_VECTOR = 0x3, + TYPE_HASH = 0x4, + TYPE_FLOAT = 0x5, + TYPE_INTEGER = 0x6, + TYPE_UINTPTR = 0x7, + TYPE_ENTITY_OFFSET = 0x8, + TYPE_CODEPOS = 0x9, + TYPE_PRECODEPOS = 0xA, + TYPE_API_FUNCTION = 0xB, + TYPE_SCRIPT_FUNCTION = 0xC, + TYPE_STACK = 0xD, + TYPE_THREAD = 0xE, + TYPE_NOTIFY_THREAD = 0xF, + TYPE_TIME_THREAD = 0x10, + TYPE_FRAME_THREAD = 0x11, + TYPE_CHILD_THREAD = 0x12, + TYPE_CLASS = 0x13, + TYPE_SHARED_STRUCT = 0x14, + TYPE_STRUCT = 0x15, + TYPE_REMOVED_ENTITY = 0x16, + TYPE_ENTITY = 0x17, + TYPE_ARRAY = 0x18, + TYPE_REMOVED_THREAD = 0x19, + TYPE_FREE = 0x1a, + TYPE_THREAD_LIST = 0x1b, + TYPE_ENT_LIST = 0x1c, + TYPE_COUNT + }; + + + struct BO4_scrVarPub { + const char* fieldBuffer; + const char* error_message; + byte* programBuffer; + byte* endScriptBuffer; + byte* programHunkUser; // HunkUser + BO4_scrVarGlobalVars_t globalVars[16]; + ScrVarNameIndex_t entFieldNameIndex; + ScrVarIndex_t freeEntList; + ScrVarIndex_t tempVariable; + uint32_t checksum; + uint32_t entId; + uint32_t varHighWatermark; + uint32_t numScriptThreads; + uint32_t numVarAllocations; + int32_t varHighWatermarkId; + }; + + union ScrVarValueUnion_t + { + int64_t intValue; + uintptr_t uintptrValue; + float floatValue; + int32_t stringValue; + const float* vectorValue; + byte* codePosValue; + ScrVarIndex_t pointerValue; + }; + + struct ScrVarValue_t + { + ScrVarValueUnion_t u; + ScrVarType_t type; + }; + + struct ScrVar_t_Info + { + uint32_t nameType : 3; + uint32_t flags : 5; + uint32_t refCount : 24; + }; + + struct ScrVar_t + { + ScrVarNameIndex_t nameIndex; + ScrVar_t_Info _anon_0; + ScrVarIndex_t nextSibling; + ScrVarIndex_t prevSibling; + ScrVarIndex_t parentId; + ScrVarIndex_t nameSearchHashList; + uint32_t pad0; + }; + + union ScrVarObjectInfo1_t + { + uint64_t object_o; + unsigned int size; + ScrVarIndex_t nextEntId; + ScrVarIndex_t self; + ScrVarIndex_t free; + }; + + union ScrVarObjectInfo2_t + { + uint32_t object_w; + ScrVarIndex_t stackId; + }; + + struct function_stack_t + { + byte* pos; + ScrVarValue_t* top; + ScrVarValue_t* startTop; + ScrVarIndex_t threadId; + uint16_t localVarCount; + uint16_t profileInfoCount; + }; + + struct function_frame_t + { + function_stack_t fs; + }; + + struct ScrVmContext_t + { + ScrVarIndex_t fieldValueId; + ScrVarIndex_t objectId; + byte* lastGoodPos; + ScrVarValue_t* lastGoodTop; + }; + + typedef void (*VM_OP_FUNC)(scriptInstance_t, function_stack_t*, ScrVmContext_t*, bool*); + + + struct BO4_scrVarGlob + { + ScrVarIndex_t* scriptNameSearchHashList; + ScrVar_t* scriptVariables; + ScrVarObjectInfo1_t* scriptVariablesObjectInfo1; + ScrVarObjectInfo2_t* scriptVariablesObjectInfo2; + ScrVarValue_t* scriptValues; + }; + + struct BO4_scrVmPub + { + void* unk0; + void* unk8; + void* executionQueueHeap; // HunkUser + void* timeByValueQueue; // VmExecutionQueueData_t + void* timeByThreadQueue[1024]; // VmExecutionQueue_t + void* frameByValueQueue; // VmExecutionQueueData_t + void* frameByThreadQueue[1024]; // VmExecutionQueue_t + void* timeoutByValueList; // VmExecutionQueueData_t + void* timeoutByThreadList[1024]; // VmExecutionQueue_t + void* notifyByObjectQueue[1024]; // VmExecutionNotifyQueue_t + void* notifyByThreadQueue[1024]; // VmExecutionNotifyQueue_t + void* endonByObjectList[1024]; // VmExecutionNotifyQueue_t + void* endonByThreadList[1024]; // VmExecutionNotifyQueue_t + ScrVarIndex_t* localVars; + ScrVarValue_t* maxstack; + function_frame_t* function_frame; + ScrVarValue_t* top; + function_frame_t function_frame_start[64]; + ScrVarValue_t stack[2048]; + uint32_t time; + uint32_t frame; + int function_count; + int callNesting; + unsigned int inparamcount; + bool showError; + bool systemInitialized; + bool vmInitialized; + bool isShutdown; + }; + + struct objFileInfo_t + { + GSC_OBJ* activeVersion; + int slot; + int refCount; + uint32_t groupId; + }; +} \ No newline at end of file diff --git a/source/proxy-dll/definitions/variables.cpp b/source/proxy-dll/definitions/variables.cpp index 599f1b7..44ae31c 100644 --- a/source/proxy-dll/definitions/variables.cpp +++ b/source/proxy-dll/definitions/variables.cpp @@ -1,5 +1,7 @@ #include #include "variables.hpp" +#include "game.hpp" +#include "xassets.hpp" #include "component/hashes.hpp" namespace fnv1a @@ -67,7 +69,7 @@ namespace fnv1a namespace variables { - std::vector dvars_record = + std::vector dvars_table = { { "aim_slowdown_enabled", @@ -6521,17 +6523,12 @@ namespace variables } }; - std::vector commands_record = + std::vector commands_table = { { "quit", "Shutdown the Game [Com_Quit_f]", 0x1DEE6107B26F8BB6 - }, - { - "reload_mods", - "Reload the shield mods", - 0x6cb53357b4ef835c } }; @@ -6540,7 +6537,7 @@ namespace variables static std::vector dvars; if (!dvars.empty()) return dvars; - for (const auto& dvar : dvars_record) + for (const auto& dvar : dvars_table) { dvars.push_back(dvar.name.data()); } @@ -6553,11 +6550,186 @@ namespace variables static std::vector commands; if (!commands.empty()) return commands; - for (const auto& cmd : commands_record) + for (const auto& cmd : commands_table) { commands.push_back(cmd.name.data()); } return commands; } -} \ No newline at end of file +} + +namespace runtime_errors +{ + std::unordered_map errors = + { + { 1045192683, "Scr_RandomFloatRange's second parameter must be greater than the first." }, + { 1047729873, "exitlevel already called" }, + { 104978404, "cannot cast type to canon" }, + { 1072585573, "Raw file is not a file of the right type" }, + { 1088278929, "Raw file is not a file of the right type" }, + { 1099145600, "Can't find asset" }, + { 1132507782, "bad opcode" }, + { 1137123674, "GScr_LUINotifyEvent: Expected Istrings, hash or integers only" }, + { 1252503459, "caller is not an entity" }, + { 1273214009, "CScr_PlayFX: invalid effect" }, + { 1333649786, "IsMature can only be called on a player." }, + { 1364331101, "Object must be an array" }, + { 1377489376, "Gesture key can't have the higher bit set" }, + { 1385570291, "assert fail (with message)" }, + { 1402557361, "bad opcode" }, + { 1403832952, "Attempt to register ClientField failed. Client Field set either already contains a field, or a hash collision has occurred." }, + { 1412130119, "parameter can't be cast to a hash" }, + { 1427704235, "expected struct type to add value pair" }, + { 1480037573, "Invalid canonical name hash" }, + { 1480821566, "Error registering client field. Attempted field size is not acceptable bit number range 1->32" }, + { 1517473035, "Value out of range. Allowed values: 0 to 2" }, + { 1609894461, "bad entity" }, + { 1670707254, "linking error" }, + { 1850691545, "Debug Break" }, + { 1895566756, "dvar is not a 3d vector, but GetDvarVector3D has been called on it" }, + { 1909233687, "Optional argument must be a vector type" }, + { 1915758537, "RegisterClientField can only accept bit ranges between 1 and 32." }, + { 1957162421, "Can't find bgCache entry" }, + { 1999906612, "type is not a integer or float" }, + { 2078816051, "not a valid name for a clientfield set." }, + { 209668787, "RandomInt parm must be positive integer." }, + { 2116335949, "function called with too many parameters" }, + { 219569925, "hasperk() can only be called on local players" }, + { 219686544, "object is not an array index" }, + { 2253722136, "CamAnimScripted can only be called on a player." }, + { 2269096660, "vector scale expecting vector" }, + { 2279633554, "SV_SetConfigstring: bad index" }, + { 2331090760, "stack does not have the pool" }, + { 2344222932, "assert fail" }, + { 2355618801, "Gesture table key can't have the higher bit set" }, + { 2408700928, "not a valid name for a clientfield set." }, + { 2448966512, "string too long" }, + { 245612264, "foreach should be used with an array" }, + { 247375020, "Attempting to register client field in client field set using bits, but system is out of space." }, + { 2479879368, "RegisterClientField can only accept bit ranges between 1 and 32." }, + { 249068885, "Failed to allocate from state pool" }, + { 2517242050, "parameter does not exist" }, + { 2532286589, "error message" }, + { 2538360978, "not a function pointer" }, + { 2572009355, "vector scale expecting vector" }, + { 2606724305, "parameter does not exist" }, + { 2626909173, "exceeded maximum number of script strings" }, + { 2681972741, "bad clientfield for name" }, + { 2687742442, "Forced script exception." }, + { 269518924, "Ammo count must not be negative" }, + { 2706458388, "Trying to get a local client index for a client that is not a local client." }, + { 2734491973, "Error need at least one argument for LUINotifyEvent." }, + { 2737681163, "assert fail (with message)" }, + { 2751867714, "self isn't a field object" }, + { 2792722947, "RegisterClientField can only accept 5 parameters" }, + { 280703902, "parameter does not exist" }, + { 2838301872, "Gesture table key can't have the higher bit set" }, + { 2855209542, "Cannot call IncrementClientField on a non-'counter' type clientfield." }, + { 2940210599, "Invalid Version Handling. Grab Bat !!!" }, + { 3015158315, "getperks() can only be called on local players" }, + { 3016026156, "Can't find asset" }, + { 3030895505, "Whitelist failure for title" }, + { 3059411687, "Argument and parameter count mismatch for LUINotifyEvent" }, + { 3086288875, "playFx called with (0 0 0) forward direction" }, + { 3122940489, "caller is not an entity" }, + { 312545010, "not a vector" }, + { 3143575744, "parameter does not exist" }, + { 317100267, "unmatching types" }, + { 3189465155, "Invalid bgCache type" }, + { 3221522156, "Failed to alloc client field" }, + { 3222417139, "size cannot be applied to type" }, + { 3251676101, "Could not load raw file" }, + { 3255107847, "LUINotifyEvent: entity must be a player entity" }, + { 3288551912, "expected array type to add value pair" }, + { 3385008561, "cannot set field on type" }, + { 3459949409, "Failed to alloc client field - MAX_CLIENTFIELD_FIELDS_IN_SET=512 exceeded." }, + { 3523382186, "ScrEvent map is full, unable to register new event" }, + { 3524483616, "Ammo count must not be negative" }, + { 3592841213, "cannot directly set the origin on AI. Use the teleport command instead." }, + { 359760836, "G_Spawn: no free entities" }, + { 3654063291, "ScrEvent map is full, unable to register new event" }, + { 3679846953, "LUINotifyEvent: entity must be a player entity" }, + { 3699844858, "parameter does not exist" }, + { 3761634992, "not a pointer" }, + { 3894031202, "Can't find gamedata/playeranim/playeranimtypes.txt" }, + { 3967909977, "Trying to get version of a demo when the demo system is idle." }, + { 3990130335, "player getperks(): localClientNum out of range" }, + { 4039057166, "LUINotifyEvent: entity must be a player entity" }, + { 4047738848, "Invalid opcode (Recovery)" }, + { 409067247, "No clientfield named found in set." }, + { 4100218247, "Error sending LUI notify event: LUI event name is not precached." }, + { 4103906837, "Entity is not an item." }, + { 4104994143, "can't allocate more script variables" }, + { 4106063796, "key value provided for array is not valid" }, + { 4163774148, "Optional argument must be a float or integer type" }, + { 4178589916, "Model was not cached by the linker." }, + { 4196473479, "parameter does not exist" }, + { 4213634562, "precacheLeaderboards must be called before any wait statements in the gametype or level script" }, + { 4220857104, "Cannot call IncrementClientField on a 'counter' type clientfield on the frame it is spawned, since newEnts on the clientside will not process 'counter' type clientfields." }, + { 467754466, "Error registering client field. bCallbacksFor0WhenNew (CF_CALLBACK_ZERO_ON_NEW_ENT) is disallowed for CF_SCRIPTMOVERFIELDS." }, + { 512306404, "not a function pointer" }, + { 57350207, "Unknown perk" }, + { 580674660, "Unknown ent type in GScr_GetFieldSetForEntityType." }, + { 619241173, "Failed to allocate from element pool" }, + { 647662103, "parameter can't be cast to a string" }, + { 657813230, "Error registering client field. bCallbacksFor0WhenNew (CF_CALLBACK_ZERO_ON_NEW_ENT) is disallowed for counter type clientfields. Due to it's treatment of the old and new val as a ring buffer, the counter type is not valid on a new snapshot, new ent, or demojump" }, + { 665902298, "Parameter must be an array" }, + { 71894325, "CamAnimScripted or ExtraCamAnimScripted can only be called on a player." }, + { 732489269, "Non-player entity passed to UploadStats()" }, + { 744499668, "too many vehicles" }, + { 750896894, "Invalid bgCache type" }, + { 753495682, "RandomIntRange's second parameter must be greater than the first." }, + { 754846421, "invalid vehicle spawn origin" }, + { 829015102, "var isn't a field object" }, + { 876169112, "key value provided for struct is not valid" }, + { 887228744, "origin being set to NAN." }, + { 904544970, "Attempt to register Client Field post finalization of Client Field registration period failed." }, + { 941828720, "exitlevel already called" }, + { 946363963, "Invalid opcode" }, + { 949934674, "Invalid Version Handling. Grab Bat !!!" }, + { 952690413, "parameter can't be cast to a boolean" }, + { 962032109, "Entity does not exist." }, + { 968521323, "player hasperk(, ): localClientNum out of range" }, + { 4088624643, "Can't find asset" }, + { custom_error_id, "Shield Error" } + }; + + const char* get_error_message(uint64_t code) + { + auto it = errors.find(code); + // known error + if (it != errors.end()) + { + return it->second; + } + + // read from the csv + static game::BO4_AssetRef_t custom_errors_file = game::AssetRef(fnv1a::generate_hash("gamedata/shield/custom_errors.csv")); + + xassets::stringtable_header* table = xassets::DB_FindXAssetHeader(xassets::ASSET_TYPE_STRINGTABLE, &custom_errors_file, false, -1).stringtable; + + if (!table || !table->columns_count || table->columns_count < 2) + { + return nullptr; + } + + for (size_t i = 0; i < table->rows_count; i++) + { + auto* rows = &table->values[i * table->columns_count]; + + if (rows[0].type != xassets::STC_TYPE_INT || rows[1].type != xassets::STC_TYPE_STRING) + { + continue; // bad types + } + + if (rows[0].value.hash_value == code) + { + return rows[1].value.string_value; + } + } + + // unknown + return nullptr; + } +} diff --git a/source/proxy-dll/definitions/variables.hpp b/source/proxy-dll/definitions/variables.hpp index 0bc5928..88ae30f 100644 --- a/source/proxy-dll/definitions/variables.hpp +++ b/source/proxy-dll/definitions/variables.hpp @@ -21,9 +21,15 @@ namespace variables uintptr_t pointer = 0; }; - extern std::vector dvars_record; - extern std::vector commands_record; + extern std::vector dvars_table; + extern std::vector commands_table; std::vector get_dvars_list(); std::vector get_commands_list(); +} + +namespace runtime_errors +{ + constexpr uint64_t custom_error_id = 0x42693201; + const char* get_error_message(uint64_t code); } \ No newline at end of file diff --git a/source/proxy-dll/main.cpp b/source/proxy-dll/main.cpp index eccc02d..188dcb9 100644 --- a/source/proxy-dll/main.cpp +++ b/source/proxy-dll/main.cpp @@ -1,6 +1,7 @@ #include - +#include "definitions/game.hpp" #include "loader/component_loader.hpp" + #include #include #include @@ -36,11 +37,15 @@ namespace INT WINAPI get_system_metrics(int nIndex) { -#ifdef DEBUG - logger::write(logger::LOG_TYPE_DEBUG, "get_system_metrics(%i)", nIndex); -#endif // DEBUG + static bool initialized = false; - component_loader::post_unpack(); + if (!initialized) { + game::verify_game_version(); + + component_loader::post_unpack(); + + initialized = true; + } return GetSystemMetrics(nIndex); }