From de2ef7eaef1a53f4b0b45ded264be7f130fad6c6 Mon Sep 17 00:00:00 2001 From: Federico Cecchetto Date: Wed, 5 Jan 2022 17:11:40 +0100 Subject: [PATCH] Add bindings module --- src/client/component/binding.cpp | 130 +++++++++++++++++++++++++++++++ src/client/game/symbols.hpp | 14 +++- 2 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/client/component/binding.cpp diff --git a/src/client/component/binding.cpp b/src/client/component/binding.cpp new file mode 100644 index 00000000..36f9e06c --- /dev/null +++ b/src/client/component/binding.cpp @@ -0,0 +1,130 @@ +#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; + utils::hook::detour key_write_bindings_to_buffer_hook; + + int key_write_bindings_to_buffer_stub(int /*localClientNum*/, 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 < 100) + { + 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 >= 100) + { + value -= 100; + 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 <= 100; i++) + { + if (game::command_whitelist[i] && !strcmp(command, game::command_whitelist[i])) + { + return i; + } + } + + // custom binds + return 100 + get_binding_for_custom_command(command); + } + + void cl_execute_key_stub(const int local_client_num, int key, const int down, const unsigned int time) + { + if (key >= 100) + { + key -= 100; + + if (static_cast(key) < custom_binds.size() && !custom_binds[key].empty()) + { + game::Cbuf_AddText(local_client_num, utils::string::va("%s\n", custom_binds[key].data())); + } + + return; + } + + cl_execute_key_hook.invoke(local_client_num, key, down, time); + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + // write all bindings to config file + key_write_bindings_to_buffer_hook.create(0x3D3840_b, key_write_bindings_to_buffer_stub); + + // links a custom command to an index + utils::hook::jump(0x59AE30_b, key_get_binding_for_cmd_stub, true); + + // execute custom binds + cl_execute_key_hook.create(0x3CF1E0_b, &cl_execute_key_stub); + } + }; +} + +REGISTER_COMPONENT(binding::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 48c6eac3..f02a47b1 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -72,17 +72,25 @@ namespace game G_GivePlayerWeapon{0x51B660}; WEAK symbol G_InitializeAmmo{0x4C4110}; WEAK symbol G_SelectWeapon{0x51C0D0}; + WEAK symbol WorldPosToScreenPos{0x36F310}; + + WEAK symbol G_SightTrace{0x4CBCA0}; WEAK symbol I_CleanStr{0x620660}; WEAK symbol Image_Setup{0x74B2A0}; + WEAK symbol Key_KeynumToString{0x3D32D0}; + WEAK symbol LUI_OpenMenu{0x5F0EE0}; WEAK symbol Menu_IsMenuOpenAndVisible{0x5EE1A0}; WEAK symbol Material_RegisterHandle{0x759BA0}; + WEAK symbol PathNode_WorldifyPosFromParent{0x525830}; + WEAK symbol Scr_AllocVector{0x5C3220}; WEAK symbol Scr_ClearOutParams{0x5C6E50}; WEAK symbol Scr_GetEntityIdRef{0x5C56C0}; @@ -112,7 +120,8 @@ namespace game WEAK symbol R_AddDObjToScene{0x775C40}; - WEAK symbol ScrPlace_GetViewPlacement{0x3E16A0}; + WEAK symbol ScrPlace_GetViewPlacement{0x3E16A0}; + WEAK symbol ScrPlace_GetView{0x3E1660}; WEAK symbol SL_ConvertToString{0x5BFBB0}; WEAK symbol SL_GetString{0x5C0170}; @@ -138,6 +147,7 @@ namespace game WEAK symbol cmd_functions{0xAD17BB8}; WEAK symbol cmd_args{0xAD17A60}; + WEAK symbol command_whitelist{0xBF84E0}; WEAK symbol hWnd{0xCCF81C0}; @@ -145,10 +155,12 @@ namespace game WEAK symbol g_poolSize{0xBF2E40}; WEAK symbol g_entities{0x52DDDA0}; + WEAK symbol pathData{0x52CCDA0}; WEAK symbol threadIds{0xB11DC80}; WEAK symbol gfxDrawMethod{0xEDF9E00}; + WEAK symbol refdef{0x1BC2500}; WEAK symbol keyCatchers{0x203F3C0};