From a7f60aeae281c45b56c0ec5f79275ef3ee3adadc Mon Sep 17 00:00:00 2001 From: Maurice Heumann Date: Fri, 30 Dec 2022 19:17:36 +0100 Subject: [PATCH] Add custom command support --- src/client/component/command.cpp | 124 +++++++++++++++++++++++++++++++ src/client/component/command.hpp | 28 +++++++ src/client/game/structs.hpp | 1 + src/client/game/symbols.hpp | 22 +++--- src/common/utils/hook.hpp | 3 +- src/common/utils/memory.hpp | 8 +- 6 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 src/client/component/command.cpp create mode 100644 src/client/component/command.hpp diff --git a/src/client/component/command.cpp b/src/client/component/command.cpp new file mode 100644 index 00000000..52aae8ed --- /dev/null +++ b/src/client/component/command.cpp @@ -0,0 +1,124 @@ +#include +#include "loader/component_loader.hpp" + +#include "command.hpp" +#include "scheduler.hpp" +#include +#include + +#include + +namespace command +{ + namespace + { + std::unordered_map& get_command_map() + { + static std::unordered_map command_map{}; + return command_map; + } + + void execute_custom_command() + { + const params params{}; + + auto& map = get_command_map(); + const auto entry = map.find(params[0]); + if (entry != map.end()) + { + entry->second(params); + } + } + + game::CmdArgs* get_cmd_args() + { + return game::Sys_GetTLS()->cmdArgs; + } + + void update_whitelist_stub() + { + game::cmd_function_s* current_function = game::cmd_functions; + while (current_function) + { + current_function->autoComplete = 1; + current_function = current_function->next; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + command::add("bruuh", [](const params& p) + { + MessageBoxA(0, p.join(0).data(), 0, 0); + }); + + // Disable whitelist + utils::hook::jump(0x14133CF70_g, update_whitelist_stub); + } + }; + + params::params() + : nesting_(get_cmd_args()->nesting) + { + assert(this->nesting_ < game::CMD_MAX_NESTING); + } + + int params::size() const + { + return get_cmd_args()->argc[this->nesting_]; + } + + 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(std::string command, command_function function) + { + add(std::move(command), [f = std::move(function)](const params&) + { + f(); + }); + } + + void add(std::string command, command_param_function function) + { + auto& map = get_command_map(); + const auto reregister = map.contains(command); + + if (!reregister) + { + auto& allocator = *utils::memory::get_allocator(); + auto* cmd_function = allocator.allocate(); + const auto* cmd_string = allocator.duplicate_string(command); + + game::Cmd_AddCommandInternal(cmd_string, execute_custom_command, cmd_function); + cmd_function->autoComplete = 1; + } + + map[std::move(command)] = std::move(function); + } +} + +REGISTER_COMPONENT(command::component) diff --git a/src/client/component/command.hpp b/src/client/component/command.hpp new file mode 100644 index 00000000..3ab882ab --- /dev/null +++ b/src/client/component/command.hpp @@ -0,0 +1,28 @@ +#pragma once + +namespace command +{ + class params + { + public: + params(); + + int size() const; + const char* get(int index) const; + std::string join(int index) const; + + const char* operator[](const int index) const + { + return this->get(index); // + } + + private: + int nesting_; + }; + + using command_function = std::function; + using command_param_function = std::function; + + void add(std::string command, command_function function); + void add(std::string command, command_param_function function); +} diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index f0a00ee5..c787841d 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -439,6 +439,7 @@ namespace game const char* autoCompleteDir; const char* autoCompleteExt; xcommand_t function; + int autoComplete; }; struct CmdArgs diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 8f641499..e7d2b3a2 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -16,13 +16,18 @@ namespace game // Com WEAK symbol Com_Printf{0x1421499C0}; WEAK symbol Com_Error_{0x1420F8BD0}; - WEAK symbol Com_SessionMode_IsMode{ 0x1420F7DD0 }; - WEAK symbol Com_SwitchMode{0x14214AF30 }; + WEAK symbol Com_SessionMode_IsMode{0x1420F7DD0}; + WEAK symbol Com_SwitchMode{ + 0x14214AF30 + }; - WEAK symbol Cbuf_AddText{0x1420EC8B0}; + WEAK symbol Cbuf_AddText{0x1420EC8B0}; WEAK symbol Cmd_AddCommandInternal{ 0x1420ED530 }; + WEAK symbol Cmd_ExecuteSingleCommand{ + 0x1420EDC20 + }; WEAK symbol Con_GetTextCopy{0x14133A7D0}; // DB @@ -57,7 +62,8 @@ namespace game }; // Rendering - WEAK symbol R_AddCmdDrawText{ + WEAK symbol + R_AddCmdDrawText{ 0x141CD98D0 }; @@ -85,14 +91,6 @@ namespace game // Global game definitions constexpr auto CMD_MAX_NESTING = 8; - struct cmd_args_t - { - CmdArgs* operator->() const - { - return Sys_GetTLS()->cmdArgs; - } - }; - // Re-implementations eModes Com_SessionMode_GetMode(); } diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp index 62df41c3..b924e17b 100644 --- a/src/common/utils/hook.hpp +++ b/src/common/utils/hook.hpp @@ -149,7 +149,8 @@ namespace utils::hook void un_move(); }; - std::optional> iat(const nt::library& library, const std::string& target_library, const std::string& process, void* stub); + std::optional> iat(const nt::library& library, const std::string& target_library, + const std::string& process, void* stub); void nop(void* place, size_t length); void nop(size_t place, size_t length); diff --git a/src/common/utils/memory.hpp b/src/common/utils/memory.hpp index 01f9554f..6c8455c6 100644 --- a/src/common/utils/memory.hpp +++ b/src/common/utils/memory.hpp @@ -22,13 +22,13 @@ namespace utils void* allocate(size_t length); template - inline T* allocate() + T* allocate() { return this->allocate_array(1); } template - inline T* allocate_array(const size_t count = 1) + T* allocate_array(const size_t count = 1) { return static_cast(this->allocate(count * sizeof(T))); } @@ -47,13 +47,13 @@ namespace utils static void* allocate(size_t length); template - static inline T* allocate() + static T* allocate() { return allocate_array(1); } template - static inline T* allocate_array(const size_t count = 1) + static T* allocate_array(const size_t count = 1) { return static_cast(allocate(count * sizeof(T))); }