From 58dc53850bfa7b1b8e2e08738e6e900b01640d0b Mon Sep 17 00:00:00 2001 From: quaK <38787176+Joelrau@users.noreply.github.com> Date: Sat, 17 Sep 2022 20:19:30 +0300 Subject: [PATCH] new stuff and other stuff --- src/client/component/binding.cpp | 150 ++++++++++++++++++++++ src/client/component/branding.cpp | 7 +- src/client/component/command.cpp | 114 ++++++++++++++-- src/client/component/dvars.cpp | 41 +++--- src/client/component/exception.cpp | 2 +- src/client/component/fastfiles.cpp | 2 +- src/client/component/game_console.cpp | 25 +++- src/client/component/renderer.cpp | 74 +++++++++++ src/client/component/system_check.cpp | 1 - src/client/game/dvars.cpp | 28 ++-- src/client/game/dvars.hpp | 8 +- src/client/game/game.cpp | 19 +-- src/client/game/game.hpp | 2 - src/client/game/structs.hpp | 86 +++++++++---- src/client/game/symbols.hpp | 16 ++- src/client/loader/component_interface.hpp | 5 + src/client/loader/component_loader.cpp | 31 ++++- src/client/loader/component_loader.hpp | 25 +++- src/client/main.cpp | 12 +- src/client/std_include.hpp | 2 + src/client/steam/steam.cpp | 6 +- 21 files changed, 543 insertions(+), 113 deletions(-) create mode 100644 src/client/component/binding.cpp create mode 100644 src/client/component/renderer.cpp diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp new file mode 100644 index 0000000..7446d95 --- /dev/null +++ b/src/client/component/binding.cpp @@ -0,0 +1,150 @@ +#include +#include "loader/component_loader.hpp" +#include "game/game.hpp" + +#include +#include + +namespace binding +{ + namespace + { + std::vector custom_binds = {}; + + utils::hook::detour cl_execute_key_hook; + + int get_num_keys() + { + return 118; + } + + int key_write_bindings_to_buffer_stub(int, char* buffer, const int buffer_size) + { + auto bytes_used = 0; + const auto buffer_size_align = static_cast(buffer_size) - 4; + + for (auto key_index = 0; key_index < 256; ++key_index) + { + const auto* const key_button = game::Key_KeynumToString(key_index, 0, 1); + auto value = game::playerKeys->keys[key_index].binding; + + if (value && value < get_num_keys()) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, game::command_whitelist[value]); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + else if (value >= get_num_keys()) + { + value -= get_num_keys(); + if (static_cast(value) < custom_binds.size() && !custom_binds[value].empty()) + { + const auto len = sprintf_s(&buffer[bytes_used], (buffer_size_align - bytes_used), + "bind %s \"%s\"\n", key_button, custom_binds[value].data()); + + if (len < 0) + { + return bytes_used; + } + + bytes_used += len; + } + } + } + + buffer[bytes_used] = 0; + return bytes_used; + } + + int get_binding_for_custom_command(const char* command) + { + auto index = 0; + for (auto& bind : custom_binds) + { + if (bind == command) + { + return index; + } + index++; + } + + custom_binds.emplace_back(command); + index = static_cast(custom_binds.size()) - 1; + + return index; + } + + int key_get_binding_for_cmd_stub(const char* command) + { + // original binds + for (auto i = 0; i < get_num_keys(); i++) + { + if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) + { + return i; + } + } + + // custom binds + return get_num_keys() + get_binding_for_custom_command(command); + } + + + std::optional get_custom_binding_for_key(int key) + { + key -= get_num_keys(); + + if (static_cast(key) < custom_binds.size() && !custom_binds[key].empty()) + { + return { custom_binds[key] }; + } + + return {}; + } + + void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time) + { + if (key >= get_num_keys()) + { + const auto bind = get_custom_binding_for_key(key); + if (!bind.has_value()) + { + return; + } + + return game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", bind.value().data())); + } + + cl_execute_key_hook.invoke(local_client_num, key, down, time); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + // write all bindings to config file + utils::hook::jump(0x9A9F70_b, key_write_bindings_to_buffer_stub); + + // links a custom command to an index + utils::hook::jump(0x9A8EA0_b, key_get_binding_for_cmd_stub); + + // execute custom binds + cl_execute_key_hook.create(0x32A3B0_b, &cl_execute_key_stub); + } + }; +} + +REGISTER_COMPONENT(binding::component) \ No newline at end of file diff --git a/src/client/component/branding.cpp b/src/client/component/branding.cpp index 75073f2..918a0a0 100644 --- a/src/client/component/branding.cpp +++ b/src/client/component/branding.cpp @@ -6,6 +6,7 @@ #include "version.hpp" #include "game/game.hpp" +#include "game/dvars.hpp" // Fonts used in game: // fonts/blender_pro_bold.ttf, fonts/blender_pro_book.ttf, fonts/blender_pro_heavy.ttf, fonts/blender_pro_medium.ttf @@ -16,8 +17,6 @@ namespace branding namespace { float color[4] = { 0.666f, 0.666f, 0.666f, 0.666f }; - - game::dvar_t* branding; } class component final : public component_interface @@ -38,12 +37,12 @@ namespace branding scheduler::once([]() { - branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top left corner"); + dvars::branding = game::Dvar_RegisterBool("branding", true, game::DvarFlags::DVAR_FLAG_SAVED, "Show branding in the top left corner"); }, scheduler::pipeline::renderer); scheduler::loop([]() { - if (branding && branding->current.enabled) + if (dvars::branding && dvars::branding->current.enabled) { const auto font = game::R_RegisterFont("fonts/fira_mono_bold.ttf", 20); if (font) diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp index e3eb069..e13c79b 100644 --- a/src/client/component/command.cpp +++ b/src/client/component/command.cpp @@ -18,7 +18,8 @@ namespace command { namespace { - utils::hook::detour client_command_hook; + utils::hook::detour client_command_mp_hook; + utils::hook::detour client_command_sp_hook; utils::hook::detour parse_commandline_hook; std::unordered_map> handlers; @@ -35,7 +36,7 @@ namespace command } } - void client_command(const int client_num) + void client_command_mp(const int client_num) { params_sv params = {}; @@ -45,7 +46,22 @@ namespace command handlers_sv[command](client_num, params); } - client_command_hook.invoke(client_num); + client_command_mp_hook.invoke(client_num); + } + + void client_command_sp(const int client_num, const char* s) + { + game::SV_Cmd_TokenizeString(s); + params_sv params = {}; + + const auto command = utils::string::to_lower(s); + if (handlers_sv.find(command) != handlers_sv.end()) + { + handlers_sv[command](client_num, params); + } + game::SV_Cmd_EndTokenizedString(); + + client_command_sp_hook.invoke(client_num, s); } // Shamelessly stolen from Quake3 @@ -109,8 +125,8 @@ namespace command const auto current = game::Dvar_ValueToString(dvar, dvar->current); const auto reset = game::Dvar_ValueToString(dvar, dvar->reset); - console::info("\"%s\" is: \"%s\" default: \"%s\" hash: 0x%08lX type: %i\n", - args[0], current, reset, dvar->hash, dvar->type); + console::info("\"%s\" is: \"%s\" default: \"%s\" checksum: 0x%08lX type: %i\n", + args[0], current, reset, dvar->checksum, dvar->type); const auto dvar_info = dvars::dvar_get_description(dvar); @@ -134,16 +150,23 @@ namespace command void client_println(int client_num, const std::string& text) { - game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, - utils::string::va("f \"%s\"", text.data())); + if (game::Com_GameMode_GetActiveGameMode() == game::GAME_TYPE_SP) + { + game::CG_Utils_GameMessage(client_num, text.data(), 0); // why is nothing printed? + } + else + { + game::SV_GameSendServerCommand(client_num, game::SV_CMD_RELIABLE, + utils::string::va("f \"%s\"", text.data())); + } } - bool check_cheats(int client_num) + bool cheats_ok(int client_num) { const auto sv_cheats = game::Dvar_FindVar("sv_cheats"); if (!sv_cheats || !sv_cheats->current.enabled) { - client_println(client_num, "Cheats are not enabled on this server"); + client_println(client_num, "GAME_CHEATSNOTENABLED"); return false; } @@ -289,7 +312,8 @@ namespace command void post_unpack() override { utils::hook::jump(0xBB1DC0_b, dvar_command_stub, true); - client_command_hook.create(0xB105D0_b, &client_command); + //client_command_mp_hook.create(0xB105D0_b, &client_command_mp); + //client_command_sp_hook.create(0x483130_b, &client_command_sp); add_commands(); } @@ -302,6 +326,76 @@ namespace command { *reinterpret_cast(1) = 0; }); + + add("god", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::g_entities[0].flags ^= 1; + client_println(0, + game::g_entities[0].flags & 1 + ? "GAME_GODMODE_ON" + : "GAME_GODMODE_OFF"); + }); + + add("demigod", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::g_entities[0].flags ^= 2; + client_println(0, + game::g_entities[0].flags & 2 + ? "GAME_DEMI_GODMODE_ON" + : "GAME_DEMI_GODMODE_OFF"); + }); + + add("notarget", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::g_entities[0].flags ^= 4; + client_println(0, + game::g_entities[0].flags & 4 + ? "GAME_NOTARGETON" + : "GAME_NOTARGETOFF"); + }); + + add("noclip", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::g_entities[0].client->flags ^= 1; + client_println(0, + game::g_entities[0].client->flags & 1 + ? "GAME_NOCLIPON" + : "GAME_NOCLIPOFF"); + }); + + add("ufo", []() + { + if (!game::SV_Loaded()) + { + return; + } + + game::g_entities[0].client->flags ^= 1; + client_println(0, + game::g_entities[0].client->flags & 1 + ? "GAME_UFOON" + : "GAME_UFOOFF"); + }); } }; } diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp index 4597e26..4f40cd3 100644 --- a/src/client/component/dvars.cpp +++ b/src/client/component/dvars.cpp @@ -36,7 +36,6 @@ namespace dvars struct dvar_vector3 : dvar_base { - float x{}; float y{}; float z{}; @@ -93,22 +92,10 @@ namespace dvars } utils::hook::detour dvar_register_new_hook; - game::dvar_t* dvar_register_new_internal(const char* name, int hash, game::dvar_type type, unsigned int flags, - game::dvar_value* value, game::dvar_limits* domain, bool level, const char* description) + 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) { - auto* dvar = dvar_register_new_hook.invoke(name, hash, type, flags, value, domain, level, description); - - if (dvar) - { - if (name) - { - dvars::dvar_set_name(dvar, name); - } - if (description) - { - dvars::dvar_set_description(dvar, description); - } - } + auto* dvar = dvar_register_new_hook.invoke(name, checksum, type, flags, value, domain, level, description); if (dvar && name && dvar_on_register_function_map.find(name) != dvar_on_register_function_map.end()) { @@ -119,11 +106,13 @@ namespace dvars return dvar; } - utils::hook::detour dvar_reregister_hook; - void dvar_reregister(game::dvar_t* dvar, const char* name, game::dvar_type type, unsigned int flags, - game::dvar_value* value, game::dvar_limits* domain, bool level, const char* description) + std::recursive_mutex register_var_lock; + utils::hook::detour dvar_register_variant_hook; + 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) { - dvar_reregister_hook.invoke(dvar, name, type, flags, value, domain, level, description); + std::lock_guard $(register_var_lock); + auto* dvar = dvar_register_variant_hook.invoke(name, checksum, type, flags, value, domain, description); if (dvar) { @@ -136,6 +125,8 @@ namespace dvars dvars::dvar_set_description(dvar, description); } } + + return dvar; } class component final : public component_interface @@ -143,9 +134,13 @@ namespace dvars public: void post_unpack() override { - // the post_unpack happens too late for some dvars... - dvar_register_new_hook.create(0xCEBA60_b, dvar_register_new_internal); - dvar_reregister_hook.create(0xCEC210_b, dvar_reregister); + dvar_register_new_hook.create(0xCEBA60_b, dvar_register_new); + dvar_register_variant_hook.create(0xCEBDD0_b, dvar_register_variant); + } + + int priority() override + { + return COMPONENT_MAX_PRIORITY - 1; } }; } diff --git a/src/client/component/exception.cpp b/src/client/component/exception.cpp index e1d1827..483aca3 100644 --- a/src/client/component/exception.cpp +++ b/src/client/component/exception.cpp @@ -159,4 +159,4 @@ namespace exception }; } -//REGISTER_COMPONENT(exception::component) \ No newline at end of file +REGISTER_COMPONENT(exception::component) \ No newline at end of file diff --git a/src/client/component/fastfiles.cpp b/src/client/component/fastfiles.cpp index 387be5b..c5d049d 100644 --- a/src/client/component/fastfiles.cpp +++ b/src/client/component/fastfiles.cpp @@ -75,7 +75,7 @@ namespace fastfiles void post_unpack() override { db_try_load_x_file_internal_hook.create(0x3BBC40_b, db_try_load_x_file_internal_stub); -#if defined(DEBUG) and defined (XFILE_DEBUG) +#if defined(DEBUG) and defined(XFILE_DEBUG) db_init_load_x_file_hook.create(0x9E8D10_b, db_init_load_x_file_stub); #else db_load_x_zone_hook.create(0x3BA920_b, db_load_x_zone_stub); diff --git a/src/client/component/game_console.cpp b/src/client/component/game_console.cpp index ea33165..24e2848 100644 --- a/src/client/component/game_console.cpp +++ b/src/client/component/game_console.cpp @@ -278,8 +278,17 @@ namespace game_console if (matches.size() > 24) { draw_hint_box(1, dvars::con_inputHintBoxColor->current.vector); - draw_hint_text(0, utils::string::va("%i matches (too many to show here)", matches.size()), + draw_hint_text(0, utils::string::va("%i matches (too many to show here). Press SHIFT + TAB to show more", matches.size()), dvars::con_inputDvarMatchColor->current.vector); + + if (game::playerKeys[0].keys[game::keyNum_t::K_SHIFT].down && game::playerKeys[0].keys[game::keyNum_t::K_TAB].down) + { + console::info("]%s\n", con.buffer); + for (size_t i = 0; i < matches.size(); i++) + { + console::info("\t%s\n", matches[i].data()); + } + } } else if (matches.size() == 1) { @@ -304,7 +313,7 @@ namespace game_console color_white, 0); const auto offset_y = height + 3.f; - const auto line_count_ = dvar->type == game::dvar_type::enumeration + const auto line_count_ = dvar->type == game::DvarType::enumeration ? dvar->domain.enumeration.stringCount + 1 : 1; @@ -334,11 +343,15 @@ namespace game_console if (dvar) { - draw_hint_text(static_cast(i), game::Dvar_ValueToString(dvar, dvar->current), + const auto value = game::Dvar_ValueToString(dvar, dvar->current); + draw_hint_text(static_cast(i), value, dvars::con_inputDvarValueColor->current.vector, offset_value); - draw_hint_text(static_cast(i), dvars::dvar_get_description(dvar).data(), - dvars::con_inputDvarValueColor->current.vector, offset_description); + if (strlen(value) < 0x18) + { + draw_hint_text(static_cast(i), dvars::dvar_get_description(dvar).data(), + dvars::con_inputDvarValueColor->current.vector, offset_description); + } } } @@ -554,7 +567,7 @@ namespace game_console return false; } - if (key < 32) + if (key < ' ') { return false; } diff --git a/src/client/component/renderer.cpp b/src/client/component/renderer.cpp new file mode 100644 index 0000000..57364a6 --- /dev/null +++ b/src/client/component/renderer.cpp @@ -0,0 +1,74 @@ +#include +#include "loader/component_loader.hpp" + +#include "dvars.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include + +namespace renderer +{ + namespace + { + utils::hook::detour r_init_draw_method_hook; + utils::hook::detour r_update_front_end_dvar_options_hook; + + int get_fullbright_technique() + { + switch (dvars::r_fullbright->current.integer) + { + case 2: + return game::TECHNIQUE_LIT; + default: + return game::TECHNIQUE_UNLIT; + } + } + + void gfxdrawmethod() + { + game::gfxDrawMethod->drawScene = game::GFX_DRAW_SCENE_STANDARD; + game::gfxDrawMethod->baseTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT; + game::gfxDrawMethod->emissiveTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_EMISSIVE; + game::gfxDrawMethod->forceTechType = dvars::r_fullbright->current.integer ? get_fullbright_technique() : game::TECHNIQUE_LIT; + } + + void r_init_draw_method_stub() + { + gfxdrawmethod(); + } + + bool r_update_front_end_dvar_options_stub() + { + if (dvars::r_fullbright->modified) + { + game::Dvar_ClearModified(dvars::r_fullbright); + game::R_SyncRenderThread(); + + gfxdrawmethod(); + } + + return r_update_front_end_dvar_options_hook.invoke(); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + if (game::environment::is_dedi()) + { + return; + } + + dvars::r_fullbright = game::Dvar_RegisterInt("r_fullbright", 0, 0, 2, game::DVAR_FLAG_SAVED, "Toggles rendering without lighting"); + + r_init_draw_method_hook.create(0xDE9260_b, &r_init_draw_method_stub); + r_update_front_end_dvar_options_hook.create(0xE28B60_b, &r_update_front_end_dvar_options_stub); + } + }; +} + +REGISTER_COMPONENT(renderer::component) \ No newline at end of file diff --git a/src/client/component/system_check.cpp b/src/client/component/system_check.cpp index c15308b..2c20c49 100644 --- a/src/client/component/system_check.cpp +++ b/src/client/component/system_check.cpp @@ -56,7 +56,6 @@ namespace system_check static std::unordered_map sp_zone_hashes = { - // Steam doesn't necessarily deliver this file :( {"patch_common.ff", "A427FDFBFCF16B0BA662459383C48AE15C884B9B44C61C12B98E062FBC4C6DB3"}, }; diff --git a/src/client/game/dvars.cpp b/src/client/game/dvars.cpp index 103d925..b8cb3e4 100644 --- a/src/client/game/dvars.cpp +++ b/src/client/game/dvars.cpp @@ -19,7 +19,11 @@ namespace dvars game::dvar_t* con_inputDvarInactiveValueColor = nullptr; game::dvar_t* con_inputCmdMatchColor = nullptr; - std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain) + game::dvar_t* branding = nullptr; + + game::dvar_t* r_fullbright = nullptr; + + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain) { if (domain.vector.min == -FLT_MAX) { @@ -45,16 +49,16 @@ namespace dvars } } - std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain) + std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain) { std::string str; switch (type) { - case game::dvar_type::boolean: + case game::DvarType::boolean: return "Domain is 0 or 1"s; - case game::dvar_type::value: + case game::DvarType::value: if (domain.value.min == -FLT_MAX) { if (domain.value.max == FLT_MAX) @@ -75,17 +79,17 @@ namespace dvars return utils::string::va("Domain is any number from %g to %g", domain.value.min, domain.value.max); } - case game::dvar_type::vec2: + case game::DvarType::vec2: return dvar_get_vector_domain(2, domain); - case game::dvar_type::rgb: - case game::dvar_type::vec3: + case game::DvarType::rgb: + case game::DvarType::vec3: return dvar_get_vector_domain(3, domain); - case game::dvar_type::vec4: + case game::DvarType::vec4: return dvar_get_vector_domain(4, domain); - case game::dvar_type::integer: + case game::DvarType::integer: if (domain.enumeration.stringCount == INT_MIN) { if (domain.integer.max == INT_MAX) @@ -106,10 +110,10 @@ namespace dvars return utils::string::va("Domain is any integer from %i to %i", domain.integer.min, domain.integer.max); } - case game::dvar_type::color: + case game::DvarType::color: return "Domain is any 4-component color, in RGBA format"s; - case game::dvar_type::enumeration: + case game::DvarType::enumeration: str = "Domain is one of the following:"s; for (auto string_index = 0; string_index < domain.enumeration.stringCount; ++string_index) @@ -119,7 +123,7 @@ namespace dvars return str; - case game::dvar_type::string: + case game::DvarType::string: return "Domain is any text"s; default: diff --git a/src/client/game/dvars.hpp b/src/client/game/dvars.hpp index bac4305..412646b 100644 --- a/src/client/game/dvars.hpp +++ b/src/client/game/dvars.hpp @@ -15,8 +15,12 @@ namespace dvars extern game::dvar_t* con_inputDvarInactiveValueColor; extern game::dvar_t* con_inputCmdMatchColor; - std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain); - std::string dvar_get_domain(const game::dvar_type type, const game::dvar_limits& domain); + extern game::dvar_t* branding; + + extern game::dvar_t* r_fullbright; + + std::string dvar_get_vector_domain(const int components, const game::DvarLimits& domain); + std::string dvar_get_domain(const game::DvarType type, const game::DvarLimits& domain); std::string dvar_get_name(const game::dvar_t* dvar); std::string dvar_get_description(const game::dvar_t* dvar); void dvar_set_name(const game::dvar_t* dvar, const std::string& name); diff --git a/src/client/game/game.cpp b/src/client/game/game.cpp index c0245dd..715b57f 100644 --- a/src/client/game/game.cpp +++ b/src/client/game/game.cpp @@ -33,11 +33,6 @@ namespace game return sv_cmd_args->argv[sv_cmd_args->nesting][index]; } - bool VirtualLobby_Loaded() - { - return 0; //return *mp::virtualLobby_loaded == 1; - } - const char* g_assetNames[ASSET_TYPE_COUNT] = { "physicslibrary", @@ -81,13 +76,13 @@ namespace game "attachment", "weapon", "vfx", - "impactfx", // not confirmed - "surfacefx", // not confirmed - "aitype", // not confirmed - "mptype", // not confirmed - "character", // not confirmed - "xmodelalias", // not confirmed - "ASSET_TYPE_UNKNOWN", // not confirmed + "impactfx", + "surfacefx", + "aitype", + "mptype", + "character", + "xmodelalias", + "ASSET_TYPE_UNKNOWN", "rawfile", "scriptfile", "stringtable", diff --git a/src/client/game/game.hpp b/src/client/game/game.hpp index 332b460..0083aba 100644 --- a/src/client/game/game.hpp +++ b/src/client/game/game.hpp @@ -48,8 +48,6 @@ namespace game int SV_Cmd_Argc(); const char* SV_Cmd_Argv(int index); - bool VirtualLobby_Loaded(); - extern const char* g_assetNames[ASSET_TYPE_COUNT]; const char* DB_GetXAssetName(const XAsset* asset); void DB_EnumXAssets(const std::int32_t type, const std::function& callback); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 82ffe09..061500d 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -14,6 +14,14 @@ namespace game { }; + enum GameModeType : std::uint32_t + { + GAME_TYPE_NONE = 0x0, + GAME_TYPE_SP = 0x1, + GAME_TYPE_MP = 0x2, + GAME_TYPE_CP = 0x3, + }; + struct CmdArgs { int nesting; @@ -51,8 +59,20 @@ namespace game DVAR_FLAG_READ = 0x2000, }; - enum dvar_type : std::int8_t + enum DvarType : std::uint8_t { + DVAR_TYPE_BOOL = 0x0, + DVAR_TYPE_FLOAT = 0x1, + DVAR_TYPE_FLOAT_2 = 0x2, + DVAR_TYPE_FLOAT_3 = 0x3, + DVAR_TYPE_FLOAT_4 = 0x4, + DVAR_TYPE_INT = 0x5, + DVAR_TYPE_ENUM = 0x6, + DVAR_TYPE_STRING = 0x7, + DVAR_TYPE_COLOR = 0x8, + DVAR_TYPE_FLOAT_3_COLOR = 0x9, + DVAR_TYPE_COUNT = 0xA, + boolean = 0, value = 1, vec2 = 2, @@ -62,10 +82,10 @@ namespace game enumeration = 6, string = 7, color = 8, - rgb = 9 // Color without alpha + rgb = 9, // Color without alpha }; - union dvar_value + union DvarValue { bool enabled; int integer; @@ -94,7 +114,7 @@ namespace game float max; }; - union dvar_limits + union DvarLimits { $A37BA207B3DDD6345C554D4661813EDD enumeration; $9CA192F9DB66A3CB7E01DE78A0DEA53D integer; @@ -104,17 +124,17 @@ namespace game struct dvar_t { - int hash; // 0 - unsigned int flags; // 4 - bool unk; // 8 tls value? - dvar_type type; // 9 - bool modified; // 10 - dvar_value current; // 16 - dvar_value latched; // 32 - dvar_value reset; // 48 - dvar_limits domain; // 64 - char unk2; // 80 always 0? - void* unk3; // 88 some pointer related to hash? + unsigned int checksum; + unsigned int flags; + char level; + DvarType type; + bool modified; + DvarValue current; + DvarValue latched; + DvarValue reset; + DvarLimits domain; + bool(__fastcall* domainFunc)(dvar_t*, DvarValue); + dvar_t* hashNext; }; static_assert(sizeof(dvar_t) == 96); enum svscmd_type @@ -271,7 +291,7 @@ namespace game int down; int unk; int repeats; - int unk2; + int binding; }; struct field_t @@ -438,13 +458,13 @@ namespace game ASSET_TYPE_ATTACHMENT = 38, ASSET_TYPE_WEAPON = 39, ASSET_TYPE_VFX = 40, - ASSET_TYPE_IMPACT_FX = 41, // not confirmed - ASSET_TYPE_SURFACE_FX = 42, // not confirmed - ASSET_TYPE_AITYPE = 43, // not confirmed + unused - ASSET_TYPE_MPTYPE = 44, // not confirmed + unused - ASSET_TYPE_CHARACTER = 45, // not confirmed + unused - ASSET_TYPE_XMODELALIAS = 46, // not confirmed + unused - ASSET_TYPE_UNKNOWN = 47, // not confirmed + unused + ASSET_TYPE_IMPACT_FX = 41, + ASSET_TYPE_SURFACE_FX = 42, + ASSET_TYPE_AITYPE = 43, // unused + ASSET_TYPE_MPTYPE = 44, // unused + ASSET_TYPE_CHARACTER = 45, // unused + ASSET_TYPE_XMODELALIAS = 46, // unused + ASSET_TYPE_UNKNOWN = 47, // unused ASSET_TYPE_RAWFILE = 48, ASSET_TYPE_SCRIPTFILE = 49, ASSET_TYPE_STRINGTABLE = 50, @@ -1468,6 +1488,26 @@ namespace game TTFDef* ttfDef; }; + enum MaterialTechniqueType + { + TECHNIQUE_UNLIT = 8, + TECHNIQUE_EMISSIVE = 10, + TECHNIQUE_LIT = 13, + }; + + enum GfxDrawSceneMethod + { + GFX_DRAW_SCENE_STANDARD = 0x1, + }; + + struct GfxDrawMethod + { + int drawScene; + int baseTechType; + int emissiveTechType; + int forceTechType; + }; + namespace demonware { enum DWOnlineStatus diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index effb427..0417675 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -10,9 +10,15 @@ namespace game WEAK symbol Com_Quit_f{ 0xBADC90 }; + WEAK symbol Com_FrontEndScene_IsActive{ 0x5AEBA0 }; + + WEAK symbol Com_GameMode_GetActiveGameMode{ 0x5AFD50 }; + WEAK symbol Cbuf_AddText{ 0xB7C290 }; WEAK symbol Cbuf_AddCall{ 0xB7C220 }; + WEAK symbol CG_Utils_GameMessage{ 0x1D7FC0 }; + WEAK symbol Cmd_ExecuteSingleCommand{ 0xB7D040 }; WEAK symbol Cmd_AddCommandInternal{ 0xB7C8F0 }; WEAK symbol Cmd_RemoveCommand{ 0xB7D630 }; @@ -41,12 +47,17 @@ namespace game WEAK symbol Dvar_SetCommand{ 0xCECB30 }; WEAK symbol Dvar_FindVar{ 0xCEA460 }; + WEAK symbol Dvar_ClearModified{ 0xCE9E90 }; WEAK symbol Dvar_GetCombinedString{ 0xBB1F30 }; - WEAK symbol Dvar_ValueToString{ 0xCEED00 }; + WEAK symbol Dvar_ValueToString{ 0xCEED00 }; WEAK symbol Dvar_GenerateChecksum{ 0xCEA520 }; #define Dvar_GenerateHash(name) \ Dvar_GenerateChecksum(name); + WEAK symbol Key_KeynumToString{ 0x9A95E0 }; + + WEAK symbol LUI_CoD_InFrontEnd{ 0x615080 }; + WEAK symbol Live_SyncOnlineDataFlags{ 0xDC5CE0 }; WEAK symbol Material_RegisterHandle{ 0xE11CE0 }; @@ -82,6 +93,9 @@ namespace game WEAK symbol sv_cmd_args{ 0x5D65C20 }; WEAK symbol cmd_args{ 0x5D65B70 }; WEAK symbol cmd_functions{ 0x5D65CC8 }; + WEAK symbol command_whitelist{ 0x14D1B70 }; + + WEAK symbol gfxDrawMethod{ 0x83E86A8 }; WEAK symbol keyCatchers{ 0x2246C34 }; WEAK symbol playerKeys{ 0x523BA0C }; diff --git a/src/client/loader/component_interface.hpp b/src/client/loader/component_interface.hpp index e1ee433..edec6f5 100644 --- a/src/client/loader/component_interface.hpp +++ b/src/client/loader/component_interface.hpp @@ -32,4 +32,9 @@ public: { return true; } + + virtual int priority() + { + return 0; + } }; diff --git a/src/client/loader/component_loader.cpp b/src/client/loader/component_loader.cpp index 342a1a9..707351c 100644 --- a/src/client/loader/component_loader.cpp +++ b/src/client/loader/component_loader.cpp @@ -1,8 +1,12 @@ #include #include "component_loader.hpp" -void component_loader::register_component(std::unique_ptr&& component_) +void component_loader::register_component(std::unique_ptr&& component_, [[maybe_unused]] const std::string& name) { +#ifdef DEBUG + printf("registering component: %s\n", name.data()); +#endif + get_components().push_back(std::move(component_)); } @@ -33,8 +37,6 @@ bool component_loader::post_load() if (handled) return true; handled = true; - clean(); - try { for (const auto& component_ : get_components()) @@ -65,7 +67,7 @@ void component_loader::post_unpack() catch (std::exception& e) { MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); - quick_exit(-1); + quick_exit(EXIT_FAILURE); } } } @@ -78,7 +80,15 @@ void component_loader::pre_destroy() for (const auto& component_ : get_components()) { - component_->pre_destroy(); + try + { + component_->pre_destroy(); + } + catch (std::exception& e) + { + MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); + quick_exit(EXIT_FAILURE); + } } } @@ -99,6 +109,17 @@ void component_loader::clean() } } +void component_loader::sort() +{ + auto& components = get_components(); + + std::ranges::stable_sort(components, [](const std::unique_ptr& a, + const std::unique_ptr& b) + { + return a->priority() > b->priority(); + }); +} + void* component_loader::load_import(const std::string& library, const std::string& function) { void* function_ptr = nullptr; diff --git a/src/client/loader/component_loader.hpp b/src/client/loader/component_loader.hpp index 4ff8f3c..290f39e 100644 --- a/src/client/loader/component_loader.hpp +++ b/src/client/loader/component_loader.hpp @@ -1,6 +1,8 @@ #pragma once #include "component_interface.hpp" +#define COMPONENT_MAX_PRIORITY 999 + class component_loader final { public: @@ -22,6 +24,17 @@ public: { register_component(std::make_unique()); } + + installer(const std::string& component_name) + { + register_component( + std::make_unique(), + std::string( + component_name.begin(), + component_name.begin() + component_name.find("::") + ) + ); + } }; template @@ -38,13 +51,14 @@ public: return nullptr; } - static void register_component(std::unique_ptr&& component); + static void register_component(std::unique_ptr&& component, const std::string& name = "(unnamed)"); static bool post_start(); static bool post_load(); static void post_unpack(); static void pre_destroy(); static void clean(); + static void sort(); static void* load_import(const std::string& library, const std::string& function); @@ -54,8 +68,9 @@ private: static std::vector>& get_components(); }; -#define REGISTER_COMPONENT(name) \ -namespace \ -{ \ - static component_loader::installer __component; \ +#define REGISTER_COMPONENT(name) \ +namespace \ +{ \ + static component_loader::installer __component = component_loader::installer(#name); \ } + diff --git a/src/client/main.cpp b/src/client/main.cpp index 5b9f564..6360de0 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -36,7 +36,8 @@ FARPROC load_binary(uint64_t* base_address) } else if (function == "SystemParametersInfoA") { - return system_parameters_info_a; + // post_unpack called from SteamAPI_Init + //return system_parameters_info_a; } return component_loader::load_import(library, function); @@ -118,6 +119,9 @@ int main() remove_crash_file(); { + component_loader::sort(); + component_loader::clean(); + auto premature_shutdown = true; const auto _ = gsl::finally([&premature_shutdown]() { @@ -129,7 +133,7 @@ int main() try { - if (!component_loader::post_start()) return 0; + if (!component_loader::post_start()) return EXIT_FAILURE; uint64_t base_address{}; entry_point = load_binary(&base_address); @@ -146,14 +150,14 @@ int main() } game::base_address = base_address; - if (!component_loader::post_load()) return 0; + if (!component_loader::post_load()) return EXIT_FAILURE; premature_shutdown = false; } catch (std::exception& e) { MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR); - return 1; + return EXIT_FAILURE; } } diff --git a/src/client/std_include.hpp b/src/client/std_include.hpp index bd326f9..863a376 100644 --- a/src/client/std_include.hpp +++ b/src/client/std_include.hpp @@ -101,3 +101,5 @@ #include "resource.hpp" using namespace std::literals; + +#define __FILENAME__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) diff --git a/src/client/steam/steam.cpp b/src/client/steam/steam.cpp index 18ecd7d..ee78a9c 100644 --- a/src/client/steam/steam.cpp +++ b/src/client/steam/steam.cpp @@ -3,6 +3,8 @@ #include +#include "loader/component_loader.hpp" + namespace steam { uint64_t callbacks::call_id_ = 0; @@ -111,12 +113,14 @@ namespace steam bool SteamAPI_Init() { const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath(); - if (steam_path.empty()) return true; + if (steam_path.empty()) return false; ::utils::nt::library::load(steam_path / "tier0_s64.dll"); ::utils::nt::library::load(steam_path / "vstdlib_s64.dll"); ::utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll"); ::utils::nt::library::load(steam_path / "steamclient64.dll"); + + component_loader::post_unpack(); return true; }