From 84facee97e91182b3cdfe718e43a49f684ad3713 Mon Sep 17 00:00:00 2001 From: project-bo4 <127137346+project-bo4@users.noreply.github.com> Date: Sun, 28 Jul 2024 12:26:23 +0330 Subject: [PATCH] Functionality Improvements + Added 'keycatchers' as an standalone component + Improvement to logger with output division + Improvements to game console --- source/proxy-dll/component/command.cpp | 2 +- source/proxy-dll/component/game_console.cpp | 40 ++---------- source/proxy-dll/component/keycatchers.cpp | 71 +++++++++++++++++++++ source/proxy-dll/component/keycatchers.hpp | 10 +++ source/proxy-dll/component/logger.cpp | 13 ++-- source/proxy-dll/component/logger.hpp | 3 +- source/proxy-dll/component/mods.cpp | 7 +- source/shared-code/utilities/string.cpp | 71 +++++++++++++++++++-- source/shared-code/utilities/string.hpp | 21 +++++- 9 files changed, 183 insertions(+), 55 deletions(-) create mode 100644 source/proxy-dll/component/keycatchers.cpp create mode 100644 source/proxy-dll/component/keycatchers.hpp diff --git a/source/proxy-dll/component/command.cpp b/source/proxy-dll/component/command.cpp index ae72060..6f58bca 100644 --- a/source/proxy-dll/component/command.cpp +++ b/source/proxy-dll/component/command.cpp @@ -159,7 +159,7 @@ namespace command add(command, [f = std::move(function)](const params&) { f(); - }); + }, desc); } void add(const std::string& command, command_param_function function, const char* desc) diff --git a/source/proxy-dll/component/game_console.cpp b/source/proxy-dll/component/game_console.cpp index 3c65166..a7f590f 100644 --- a/source/proxy-dll/component/game_console.cpp +++ b/source/proxy-dll/component/game_console.cpp @@ -6,6 +6,7 @@ #include "component/dvars.hpp" #include "component/scheduler.hpp" +#include "component/keycatchers.hpp" #include #include @@ -437,8 +438,7 @@ namespace game_console } } - - bool console_char_event(const int local_client_num, const int key) + bool console_char_event(const int local_client_num, const int key, const bool is_repeated) { if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE || @@ -490,7 +490,7 @@ namespace game_console for (size_t i = 0; i < clipboard.length(); i++) { - console_char_event(local_client_num, clipboard[i]); + console_char_event(local_client_num, clipboard[i], false); } return false; @@ -546,7 +546,7 @@ namespace game_console return true; } - bool console_key_event(const int local_client_num, const int key, const int down) + bool console_key_event(const int local_client_num, const int key, const bool down, const unsigned int time) { if (key == game::keyNum_t::K_GRAVE || key == game::keyNum_t::K_TILDE) { @@ -650,10 +650,8 @@ namespace game_console }); } - if (key == game::keyNum_t::K_ENTER) + if (key == game::keyNum_t::K_ENTER && !utilities::string::is_truely_empty(con.buffer)) { - //game::Cbuf_AddText(0, utilities::string::va("%s \n", fixed_input.data())); - if (history_index != -1) { const auto itr = history.begin() + history_index; @@ -684,29 +682,6 @@ namespace game_console return true; } - utilities::hook::detour cl_key_event_hook; - void cl_key_event_stub(int localClientNum, int key, bool down, unsigned int time) - { - if (!game_console::console_key_event(localClientNum, key, down)) - { - return; - } - - cl_key_event_hook.invoke(localClientNum, key, down, time); - } - - utilities::hook::detour cl_char_event_hook; - void cl_char_event_stub(const int localClientNum, const int key, bool isRepeated) - { - if (!game_console::console_char_event(localClientNum, key)) - { - return; - } - - cl_char_event_hook.invoke(localClientNum, key, isRepeated); - } - - class component final : public component_interface { public: @@ -714,9 +689,8 @@ namespace game_console { scheduler::loop(draw_console, scheduler::renderer); - cl_key_event_hook.create(0x142839250_g, cl_key_event_stub); - cl_char_event_hook.create(0x142836F80_g, cl_char_event_stub); - + keycatchers::add_key_event(console_key_event); + keycatchers::add_char_event(console_char_event); // initialize our structs con.cursor = 0; diff --git a/source/proxy-dll/component/keycatchers.cpp b/source/proxy-dll/component/keycatchers.cpp new file mode 100644 index 0000000..09003ec --- /dev/null +++ b/source/proxy-dll/component/keycatchers.cpp @@ -0,0 +1,71 @@ +#include +#include "keycatchers.hpp" +#include "loader/component_loader.hpp" + +#include +#include + +namespace keycatchers +{ + namespace + { + utilities::concurrency::container, std::recursive_mutex> key_event_callbacks; + utilities::concurrency::container, std::recursive_mutex> char_event_callbacks; + + utilities::hook::detour cl_key_event_hook; + void cl_key_event_stub(const int localClientNum, const int key, bool down, const unsigned int time) + { + key_event_callbacks.access([&](std::vector& callbacks) + { + for (auto& func : callbacks) { + if (!func(localClientNum, key, down, time)) + return; + } + }); + + cl_key_event_hook.invoke(localClientNum, key, down, time); + } + + utilities::hook::detour cl_char_event_hook; + void cl_char_event_stub(const int localClientNum, const int key, bool isRepeated) + { + char_event_callbacks.access([&](std::vector& callbacks) + { + for (auto& func : callbacks) { + if (!func(localClientNum, key, isRepeated)) + return; + } + }); + + cl_char_event_hook.invoke(localClientNum, key, isRepeated); + } + } + + void add_key_event(ke_typedef&& func) + { + key_event_callbacks.access([&func](std::vector& callbacks) + { + callbacks.push_back(std::move(func)); + }); + } + + void add_char_event(ch_typedef&& func) + { + char_event_callbacks.access([&func](std::vector& callbacks) + { + callbacks.push_back(std::move(func)); + }); + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + cl_key_event_hook.create(0x142839250_g, cl_key_event_stub); + cl_char_event_hook.create(0x142836F80_g, cl_char_event_stub); + } + }; +} + +REGISTER_COMPONENT(keycatchers::component) \ No newline at end of file diff --git a/source/proxy-dll/component/keycatchers.hpp b/source/proxy-dll/component/keycatchers.hpp new file mode 100644 index 0000000..c274219 --- /dev/null +++ b/source/proxy-dll/component/keycatchers.hpp @@ -0,0 +1,10 @@ +#pragma once + +namespace keycatchers +{ + using ke_typedef = std::function; + using ch_typedef = std::function; + + void add_key_event(ke_typedef&& func); + void add_char_event(ch_typedef&& func); +} \ No newline at end of file diff --git a/source/proxy-dll/component/logger.cpp b/source/proxy-dll/component/logger.cpp index ff7bf53..140975e 100644 --- a/source/proxy-dll/component/logger.cpp +++ b/source/proxy-dll/component/logger.cpp @@ -5,9 +5,6 @@ #include -#define OUTPUT_DEBUG_API -#define OUTPUT_GAME_CONSOLE - namespace logger { const char* LogTypeNames[] = @@ -15,7 +12,8 @@ namespace logger "DEBUG", "INFO", "WARN", - "ERROR" + "ERROR", + "" }; void write(const int type, std::string str) @@ -24,15 +22,14 @@ namespace logger if (type == LOG_TYPE_DEBUG) return; #endif // _DEBUG + game_console::print(str); + if (type == type::LOG_TYPE_CONSOLE) return; + std::stringstream ss; ss << "[ " << LogTypeNames[type] << " ] " << str << std::endl; std::string text = ss.str(); -#ifdef OUTPUT_GAME_CONSOLE - game_console::print(text); -#endif // OUTPUT_GAME_CONSOLE - #ifdef OUTPUT_DEBUG_API OutputDebugStringA(text.c_str()); #endif // OUTPUT_DEBUG_API diff --git a/source/proxy-dll/component/logger.hpp b/source/proxy-dll/component/logger.hpp index 38812eb..a670a89 100644 --- a/source/proxy-dll/component/logger.hpp +++ b/source/proxy-dll/component/logger.hpp @@ -7,7 +7,8 @@ namespace logger LOG_TYPE_DEBUG = 0, LOG_TYPE_INFO = 1, LOG_TYPE_WARN = 2, - LOG_TYPE_ERROR = 3 + LOG_TYPE_ERROR = 3, + LOG_TYPE_CONSOLE = 4 }; void write(const int type, std::string str); diff --git a/source/proxy-dll/component/mods.cpp b/source/proxy-dll/component/mods.cpp index ea2c18e..10d69ec 100644 --- a/source/proxy-dll/component/mods.cpp +++ b/source/proxy-dll/component/mods.cpp @@ -4,7 +4,6 @@ #include "dvars.hpp" #include "hashes.hpp" #include "command.hpp" -#include "game_console.hpp" #include "loader/component_loader.hpp" #include "definitions/xassets.hpp" @@ -1099,17 +1098,17 @@ namespace mods { if (!game::Com_IsRunningUILevel()) { // avoid gsc issues, but if a script is loaded in the frontend, it will still crash - game_console::print("can't load mods while in-game!"); + logger::write(logger::LOG_TYPE_CONSOLE, "can't load mods while in-game!"); return; } if (!storage.load_mods()) { - game_console::print("mods reloaded."); + logger::write(logger::LOG_TYPE_CONSOLE, "mods reloaded."); } else { - game_console::print("mods reloaded with errors, see logs."); + logger::write(logger::LOG_TYPE_CONSOLE, "mods reloaded with errors, see logs."); } } } diff --git a/source/shared-code/utilities/string.cpp b/source/shared-code/utilities/string.cpp index 96c2af8..8ba1cfe 100644 --- a/source/shared-code/utilities/string.cpp +++ b/source/shared-code/utilities/string.cpp @@ -181,6 +181,30 @@ namespace utilities::string } #pragma warning(pop) + void copy(char* dest, const size_t max_size, const char* src) + { + if (!max_size) + { + return; + } + + for (size_t i = 0;; ++i) + { + if (i + 1 == max_size) + { + dest[i] = 0; + break; + } + + dest[i] = src[i]; + + if (!src[i]) + { + break; + } + } + } + std::string replace(std::string str, const std::string& from, const std::string& to) { if (from.empty()) @@ -198,6 +222,46 @@ namespace utilities::string return str; } + std::string& ltrim(std::string& str) + { + str.erase(str.begin(), std::find_if(str.begin(), str.end(), [](const unsigned char input) + { + return !std::isspace(input); + })); + + return str; + } + + std::string& rtrim(std::string& str) + { + str.erase(std::find_if(str.rbegin(), str.rend(), [](const unsigned char input) + { + return !std::isspace(input); + }).base(), str.end()); + + return str; + } + + std::string& trim(std::string& str) + { + return ltrim(rtrim(str)); + } + + bool is_truely_empty(std::string str) + { + return trim(str).size() == 0; + } + + StringMatch compare(const std::string& s1, const std::string& s2) + { + if (s1 == s2) + return StringMatch::Identical; + else if (to_lower(s1) == to_lower(s2)) + return StringMatch::CaseVariant; + else + return StringMatch::Mismatch; + } + double match(const std::string& input, const std::string& text) { if (text == input) return 1.00; // identical @@ -211,13 +275,6 @@ namespace utilities::string return ((double)match_percent / 100); } - bool compare(const std::string& s1, const std::string& s2, bool sensetive) - { - if (sensetive && (s1 == s2)) return true; - if (!sensetive && (to_lower(s1) == to_lower(s2))) return true; - return false; - } - bool contains(std::string text, std::string substr, bool sensetive) { if (!sensetive) { diff --git a/source/shared-code/utilities/string.hpp b/source/shared-code/utilities/string.hpp index 6694875..711131e 100644 --- a/source/shared-code/utilities/string.hpp +++ b/source/shared-code/utilities/string.hpp @@ -100,9 +100,28 @@ namespace utilities::string std::string convert(const std::wstring& wstr); std::wstring convert(const std::string& str); + void copy(char* dest, size_t max_size, const char* src); + + template + void copy(char(&dest)[Size], const char* src) + { + copy(dest, Size, src); + } + std::string replace(std::string str, const std::string& from, const std::string& to); + std::string& trim(std::string& str); + + bool is_truely_empty(std::string str); + + enum StringMatch + { + Mismatch = 0, + Identical = 1, + CaseVariant = 2 + }; + + StringMatch compare(const std::string& s1, const std::string& s2); double match(const std::string& input, const std::string& text); - bool compare(const std::string& s1, const std::string& s2, bool sensetive = false); bool contains(std::string text, std::string substr, bool sensetive = false); }