diff --git a/src/core/globals.hpp b/src/core/globals.hpp index 6b3c0c2a..1d03f283 100644 --- a/src/core/globals.hpp +++ b/src/core/globals.hpp @@ -223,6 +223,7 @@ namespace big bool editing_menu_toggle = false; int menu_toggle = VK_INSERT; int teleport_waypoint = 0; + int teleport_objective = 0; }; bool dev_dlc = false; @@ -658,6 +659,8 @@ namespace big this->settings.dev_dlc = j["settings"]["dev_dlc"]; this->settings.hotkeys.menu_toggle = j["settings"]["hotkeys"]["menu_toggle"]; + this->settings.hotkeys.teleport_waypoint = j["settings"]["hotkeys"]["teleport_waypoint"]; + this->settings.hotkeys.teleport_objective = j["settings"]["hotkeys"]["teleport_objective"]; this->spawn_vehicle.preview_vehicle = j["spawn_vehicle"]["preview_vehicle"]; this->spawn_vehicle.spawn_inside = j["spawn_vehicle"]["spawn_inside"]; @@ -1001,7 +1004,9 @@ namespace big "settings", { { "dev_dlc", this->settings.dev_dlc }, { "hotkeys", { - { "menu_toggle", this->settings.hotkeys.menu_toggle } + { "menu_toggle", this->settings.hotkeys.menu_toggle }, + { "teleport_waypoint", this->settings.hotkeys.teleport_waypoint }, + { "teleport_objective", this->settings.hotkeys.teleport_objective } } } } diff --git a/src/hooks/gui/wndproc.cpp b/src/hooks/gui/wndproc.cpp index 5fe2ad0b..10eb09a7 100644 --- a/src/hooks/gui/wndproc.cpp +++ b/src/hooks/gui/wndproc.cpp @@ -1,6 +1,7 @@ #include "hooking.hpp" #include "renderer.hpp" #include "script.hpp" +#include "services/hotkey/hotkey_service.hpp" namespace big { @@ -11,6 +12,7 @@ namespace big if (g_running) { g_renderer->wndproc(hwnd, msg, wparam, lparam); + g_hotkey_service->wndproc(static_cast(msg), wparam); } return CallWindowProcW(g_hooking->m_og_wndproc, hwnd, msg, wparam, lparam); diff --git a/src/main.cpp b/src/main.cpp index b7113788..8a671e7d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "services/vehicle/handling_service.hpp" #include "services/script_patcher/script_patcher_service.hpp" #include "services/player_database/player_database_service.hpp" +#include "services/hotkey/hotkey_service.hpp" #include "services/matchmaking/matchmaking_service.hpp" BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) @@ -89,6 +90,7 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) auto gui_service_instance = std::make_unique(); auto script_patcher_service_instance = std::make_unique(); auto player_database_service_instance = std::make_unique(); + auto hotkey_service_instance = std::make_unique(); auto matchmaking_service_instance = std::make_unique(); LOG(INFO) << "Registered service instances..."; @@ -137,6 +139,8 @@ BOOL APIENTRY DllMain(HMODULE hmod, DWORD reason, PVOID) thread_pool_instance.reset(); LOG(INFO) << "Thread pool uninitialized."; + hotkey_service_instance.reset(); + LOG(INFO) << "Hotkey Service reset."; matchmaking_service_instance.reset(); LOG(INFO) << "Matchmaking Service reset."; player_database_service_instance.reset(); diff --git a/src/services/hotkey/hotkey.cpp b/src/services/hotkey/hotkey.cpp new file mode 100644 index 00000000..310fc5f8 --- /dev/null +++ b/src/services/hotkey/hotkey.cpp @@ -0,0 +1,37 @@ +#include "hotkey.hpp" + +namespace big +{ + hotkey::hotkey(rage::joaat_t name_hash, key_t key, hotkey_func func, std::optional cooldown) : + m_name_hash(name_hash), + m_key(key), + m_func(func), + m_cooldown(cooldown), + m_wakeup() + { + + } + + bool hotkey::can_exec() const + { + return !m_cooldown.has_value() || std::chrono::high_resolution_clock::now() >= m_wakeup; + } + + void hotkey::exec() + { + if (m_cooldown.has_value()) + m_wakeup = std::chrono::high_resolution_clock::now() + m_cooldown.value(); + + m_func(); + } + + rage::joaat_t hotkey::name_hash() const + { + return m_name_hash; + } + + void hotkey::set_key(key_t new_key) + { + m_key = new_key; + } +} \ No newline at end of file diff --git a/src/services/hotkey/hotkey.hpp b/src/services/hotkey/hotkey.hpp new file mode 100644 index 00000000..7cd6ac91 --- /dev/null +++ b/src/services/hotkey/hotkey.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "common.hpp" +#include "rage/joaat.hpp" + +namespace big +{ + using hotkey_func = std::function; + using key_t = unsigned int; + + class hotkey final + { + public: + hotkey(rage::joaat_t name_hash, key_t key, hotkey_func func, std::optional cooldown = std::nullopt); + virtual ~hotkey() = default; + + bool can_exec() const; + void exec(); + + rage::joaat_t name_hash() const; + void set_key(key_t new_key); + + private: + rage::joaat_t m_name_hash; + key_t m_key; + + hotkey_func m_func; + std::optional m_cooldown; + std::chrono::high_resolution_clock::time_point m_wakeup; + + }; +} \ No newline at end of file diff --git a/src/services/hotkey/hotkey_service.cpp b/src/services/hotkey/hotkey_service.cpp new file mode 100644 index 00000000..9a2ca773 --- /dev/null +++ b/src/services/hotkey/hotkey_service.cpp @@ -0,0 +1,67 @@ +#include "hotkey_service.hpp" +#include "fiber_pool.hpp" +#include "util/teleport.hpp" + +namespace big +{ + hotkey_service::hotkey_service() + { + register_hotkey("waypoint", g->settings.hotkeys.teleport_waypoint, teleport::to_waypoint); + register_hotkey("objective", g->settings.hotkeys.teleport_objective, teleport::to_objective); + + g_hotkey_service = this; + } + + hotkey_service::~hotkey_service() + { + g_hotkey_service = nullptr; + } + + void hotkey_service::register_hotkey(const std::string_view name, key_t key, hotkey_func func, eKeyState state, std::optional cooldown) + { + m_hotkeys[state == eKeyState::RELEASE].emplace(key, hotkey(rage::joaat(name), key, func, cooldown)); + } + + bool hotkey_service::update_hotkey(const std::string_view name, const key_t key) + { + static auto update_hotkey_map = [key](hotkey_map& hotkey_map, rage::joaat_t name_hash) -> bool + { + if (const auto &it = std::find_if(hotkey_map.begin(), hotkey_map.end(), [name_hash](std::pair pair) -> bool + { + return pair.second.name_hash() == name_hash; + }); it != hotkey_map.end()) + { + auto hotkey = it->second; + hotkey.set_key(key); + + hotkey_map.emplace(key, hotkey); + hotkey_map.erase(it); + + return true; + } + return false; + }; + + const auto name_hash = rage::joaat(name); + return update_hotkey_map(m_hotkeys[1], name_hash) // released + && update_hotkey_map(m_hotkeys[0], name_hash); // down + } + + void hotkey_service::wndproc(eKeyState state, key_t key) + { + if (state == eKeyState::RELEASE || state == eKeyState::DOWN) + { + auto &hotkey_map = m_hotkeys[state == eKeyState::RELEASE]; + if (const auto &it = hotkey_map.find(key); it != hotkey_map.end()) + { + if (auto &hotkey = it->second; hotkey.can_exec()) + { + g_fiber_pool->queue_job([&hotkey] + { + hotkey.exec(); + }); + } + } + } + } +} \ No newline at end of file diff --git a/src/services/hotkey/hotkey_service.hpp b/src/services/hotkey/hotkey_service.hpp new file mode 100644 index 00000000..af9c28a8 --- /dev/null +++ b/src/services/hotkey/hotkey_service.hpp @@ -0,0 +1,42 @@ +#pragma once +#include "common.hpp" +#include "hotkey.hpp" + +namespace big +{ + enum eKeyState : unsigned int + { + RELEASE = WM_KEYUP, + DOWN = WM_KEYDOWN + }; + + using hotkey_map = std::map; + + class hotkey_service final + { + public: + hotkey_service(); + virtual ~hotkey_service(); + hotkey_service(const hotkey_service&) = delete; + hotkey_service(hotkey_service&&) noexcept = delete; + hotkey_service& operator=(const hotkey_service&) = delete; + hotkey_service& operator=(hotkey_service&&) noexcept = delete; + + + void register_hotkey( + const std::string_view name, + const key_t initial_key, + const hotkey_func func, + const eKeyState state = eKeyState::RELEASE, + std::optional cooldown = std::nullopt); + bool update_hotkey(const std::string_view name, const key_t new_key); + void wndproc(eKeyState state, key_t key); + + private: + // yes curse me + std::array m_hotkeys; + + }; + + inline hotkey_service* g_hotkey_service{}; +} diff --git a/src/views/settings/view_settings.cpp b/src/views/settings/view_settings.cpp index d48ef567..27cc6466 100644 --- a/src/views/settings/view_settings.cpp +++ b/src/views/settings/view_settings.cpp @@ -1,6 +1,7 @@ #include "views/view.hpp" #include "widgets/imgui_hotkey.hpp" #include "script_mgr.hpp" +#include "services/hotkey/hotkey_service.hpp" namespace big { @@ -36,8 +37,11 @@ namespace big if (ImGui::Hotkey("Menu Toggle", &g->settings.hotkeys.menu_toggle)) g->settings.hotkeys.editing_menu_toggle = true; // make our menu reappear - ImGui::Text("(Below hotkey is not implemented)"); - ImGui::Hotkey("Teleport to waypoint", &g->settings.hotkeys.teleport_waypoint); + if (ImGui::Hotkey("Teleport to waypoint", &g->settings.hotkeys.teleport_waypoint)) + g_hotkey_service->update_hotkey("waypoint", g->settings.hotkeys.teleport_waypoint); + if (ImGui::Hotkey("Teleport to objective", &g->settings.hotkeys.teleport_objective)) + g_hotkey_service->update_hotkey("objective", g->settings.hotkeys.teleport_objective); + ImGui::PopItemWidth();