From 5086d79f5d4338827dc0f4b3a8c8e6c96271575f Mon Sep 17 00:00:00 2001 From: "Quentin E. / iDeath" Date: Wed, 29 Jun 2022 23:27:44 +0200 Subject: [PATCH] feat context_menu_service (#293) - add box around selected entity - add option to select entity types - show reticle in middle of screen --- BigBaseV2/src/core/enums.hpp | 12 +- BigBaseV2/src/core/globals.hpp | 22 ++- .../src/services/context_menu_service.cpp | 168 ++++++++++++++++-- .../src/services/context_menu_service.hpp | 17 +- BigBaseV2/src/util/misc.hpp | 10 +- .../settings/view_context_menu_settings.cpp | 32 ++++ BigBaseV2/src/views/view_context_menu.cpp | 28 ++- 7 files changed, 264 insertions(+), 25 deletions(-) diff --git a/BigBaseV2/src/core/enums.hpp b/BigBaseV2/src/core/enums.hpp index f5df4c70..5dc99a08 100644 --- a/BigBaseV2/src/core/enums.hpp +++ b/BigBaseV2/src/core/enums.hpp @@ -13,6 +13,16 @@ namespace big VEHICLE_GUN }; + enum class ContextEntityType : uint8_t + { + NONE = 0, + PED = 1 << 0, + PLAYER = 1 << 1, + VEHICLE = 1 << 2, + OBJECT = 1 << 3, + SHARED = 1 << 4 + }; + enum class eEntityType { UNK_0, @@ -170,4 +180,4 @@ namespace big KMH, MPH }; -} \ No newline at end of file +} diff --git a/BigBaseV2/src/core/globals.hpp b/BigBaseV2/src/core/globals.hpp index 393f54ad..57da88a3 100644 --- a/BigBaseV2/src/core/globals.hpp +++ b/BigBaseV2/src/core/globals.hpp @@ -3,6 +3,7 @@ #include "enums.hpp" #include "file_manager.hpp" #include "imgui.h" +#include namespace big { @@ -266,6 +267,17 @@ namespace big struct context_menu { bool enabled = true; + + uint8_t allowed_entity_types = + static_cast(ContextEntityType::PED) | + static_cast(ContextEntityType::PLAYER) | + static_cast(ContextEntityType::VEHICLE) | + static_cast(ContextEntityType::OBJECT); + + ImU32 selected_option_color = 4278255360; + + bool bounding_box_enabled = true; + ImU32 bounding_box_color = 4278255360; }; struct esp @@ -529,6 +541,10 @@ namespace big this->window.users = j["window"]["users"]; this->context_menu.enabled = j["context_menu"]["enabled"]; + this->context_menu.allowed_entity_types = j["context_menu"]["allowed_entity_types"]; + this->context_menu.selected_option_color = j["context_menu"]["selected_option_color"]; + this->context_menu.bounding_box_enabled = j["context_menu"]["bounding_box_enabled"]; + this->context_menu.bounding_box_color = j["context_menu"]["bounding_box_color"]; this->esp.enabled = j["esp"]["enabled"]; this->esp.hide_self = j["esp"]["hide_self"]; @@ -785,7 +801,11 @@ namespace big }, { "context_menu", { - {"enabled", this->context_menu.enabled} + {"enabled", this->context_menu.enabled}, + { "allowed_entity_types", this->context_menu.allowed_entity_types }, + { "selected_option_color", this->context_menu.selected_option_color }, + { "bounding_box_enabled", this->context_menu.bounding_box_enabled }, + { "bounding_box_color", this->context_menu.bounding_box_color }, } }, { diff --git a/BigBaseV2/src/services/context_menu_service.cpp b/BigBaseV2/src/services/context_menu_service.cpp index 6acdc276..47ea68b2 100644 --- a/BigBaseV2/src/services/context_menu_service.cpp +++ b/BigBaseV2/src/services/context_menu_service.cpp @@ -2,6 +2,8 @@ #include "natives.hpp" #include "pointers.hpp" #include "gta/replay.hpp" +#include "gui.hpp" +#include "util/misc.hpp" namespace big { @@ -16,6 +18,94 @@ namespace big g_context_menu_service = nullptr; } + void context_menu_service::fill_model_bounding_box_screen_space() + { + Vector3 forward, right, up, pos; + ENTITY::GET_ENTITY_MATRIX(m_handle, &forward, &right, &up, &pos); + + const auto hash = ENTITY::GET_ENTITY_MODEL(m_handle); + Vector3 min, max; + MISC::GET_MODEL_DIMENSIONS(hash, &min, &max); + const auto dimensions = (max - min) * 0.5f; + + const auto& position = m_pointer->m_position; + + rage::fvector3 front_upper_right, back_lower_left; + front_upper_right.x = position.x + dimensions.y * forward.x + dimensions.x * right.x + dimensions.z * up.x; + front_upper_right.y = position.y + dimensions.y * forward.y + dimensions.x * right.y + dimensions.z * up.y; + front_upper_right.z = position.z + dimensions.y * forward.z + dimensions.x * right.z + dimensions.z * up.z; + + back_lower_left.x = position.x - dimensions.y * forward.x - dimensions.x * right.x - dimensions.z * up.x; + back_lower_left.y = position.y - dimensions.y * forward.y - dimensions.x * right.y - dimensions.z * up.y; + back_lower_left.z = position.z - dimensions.y * forward.z - dimensions.x * right.z - dimensions.z * up.z; + + rage::fvector3 edge1 = back_lower_left; + rage::fvector3 edge2, edge3, edge4; + + rage::fvector3 edge5 = front_upper_right; + rage::fvector3 edge6, edge7, edge8; + + edge2.x = edge1.x + 2 * dimensions.y * forward.x; + edge2.y = edge1.y + 2 * dimensions.y * forward.y; + edge2.z = edge1.z + 2 * dimensions.y * forward.z; + + edge3.x = edge2.x + 2 * dimensions.z * up.x; + edge3.y = edge2.y + 2 * dimensions.z * up.y; + edge3.z = edge2.z + 2 * dimensions.z * up.z; + + edge4.x = edge1.x + 2 * dimensions.z * up.x; + edge4.y = edge1.y + 2 * dimensions.z * up.y; + edge4.z = edge1.z + 2 * dimensions.z * up.z; + + edge6.x = edge5.x - 2 * dimensions.y * forward.x; + edge6.y = edge5.y - 2 * dimensions.y * forward.y; + edge6.z = edge5.z - 2 * dimensions.y * forward.z; + + edge7.x = edge6.x - 2 * dimensions.z * up.x; + edge7.y = edge6.y - 2 * dimensions.z * up.y; + edge7.z = edge6.z - 2 * dimensions.z * up.z; + + edge8.x = edge5.x - 2 * dimensions.z * up.x; + edge8.y = edge5.y - 2 * dimensions.z * up.y; + edge8.z = edge5.z - 2 * dimensions.z * up.z; + + auto any_fail = false; + static auto imgui_world_to_screen = [&any_fail](rage::fvector3& world_input, ImVec2& screen_result) + { + if (any_fail) + { + return; + } + + const auto success = GRAPHICS::GET_SCREEN_COORD_FROM_WORLD_COORD(world_input.x, world_input.y, world_input.z, &screen_result.x, &screen_result.y); + if (success) + { + screen_result.x = static_cast(*g_pointers->m_resolution_x) * screen_result.x; + screen_result.y = static_cast(*g_pointers->m_resolution_y) * screen_result.y; + } + else + { + any_fail = true; + } + }; + + auto& box = m_model_bounding_box_screen_space; + imgui_world_to_screen(edge1, box.edge1); + imgui_world_to_screen(edge2, box.edge2); + imgui_world_to_screen(edge3, box.edge3); + imgui_world_to_screen(edge4, box.edge4); + + imgui_world_to_screen(edge5, box.edge5); + imgui_world_to_screen(edge6, box.edge6); + imgui_world_to_screen(edge7, box.edge7); + imgui_world_to_screen(edge8, box.edge8); + + if (any_fail) + { + box = {}; + } + } + double context_menu_service::distance_to_middle_of_screen(const rage::vector2& screen_pos) { double cumulative_distance{}; @@ -39,8 +129,12 @@ namespace big { switch (m_pointer->m_model_info->m_model_type) { - case eModelType::Object: // Object + case eModelType::Object: { + if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast(ContextEntityType::OBJECT))) + { + break; + } return &options.at(ContextEntityType::OBJECT); } case eModelType::Ped: @@ -50,16 +144,39 @@ namespace big if (ped->m_ped_task_flag & static_cast(ePedTask::TASK_DRIVING) && ped->m_vehicle) { + if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast(ContextEntityType::VEHICLE))) + { + break; + } + m_pointer = ped->m_vehicle; return &options.at(ContextEntityType::VEHICLE); } if (ped->m_player_info) + { + if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast(ContextEntityType::PLAYER))) + { + break; + } + return &options.at(ContextEntityType::PLAYER); + } } + + if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast(ContextEntityType::PED))) + { + break; + } + return &options.at(ContextEntityType::PED); } case eModelType::Vehicle: { + if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast(ContextEntityType::VEHICLE))) + { + break; + } + return &options.at(ContextEntityType::VEHICLE); } default: @@ -86,7 +203,7 @@ namespace big const auto ptr = all_entities.get(); std::uint32_t offset = 0; - std::copy(ped_interface->m_ped_list->m_peds, ped_interface->m_ped_list->m_peds + ped_interface_size,ptr); + std::copy(ped_interface->m_ped_list->m_peds, ped_interface->m_ped_list->m_peds + ped_interface_size, ptr); offset += ped_interface_size; std::copy(veh_interface->m_vehicle_list->m_vehicles, veh_interface->m_vehicle_list->m_vehicles + veh_interface_size, ptr + offset); @@ -96,6 +213,7 @@ namespace big offset += obj_interface_size; double distance = 1; + bool got_an_entity = false; rage::vector2 screen_pos{}; for (std::uint32_t i = 0; i < offset; i++) { @@ -110,12 +228,20 @@ namespace big const auto pos = temp_pointer->m_navigation->m_position; HUD::GET_HUD_SCREEN_POSITION_FROM_WORLD_POSITION(pos.x, pos.y, pos.z, &screen_pos.x, &screen_pos.y); if (distance_to_middle_of_screen(screen_pos) < distance && - temp_handle != PLAYER::PLAYER_PED_ID()) { + ENTITY::HAS_ENTITY_CLEAR_LOS_TO_ENTITY(PLAYER::PLAYER_PED_ID(), temp_handle, 17) && + temp_handle != PLAYER::PLAYER_PED_ID()) + { m_handle = temp_handle; m_pointer = temp_pointer; distance = distance_to_middle_of_screen(screen_pos); + got_an_entity = true; } } + + if (got_an_entity) + { + fill_model_bounding_box_screen_space(); + } } } } @@ -166,13 +292,20 @@ namespace big { while (g_running) { - if (!g->context_menu.enabled) { + if (!g->context_menu.enabled) + { g_context_menu_service->enabled = false; script::get_current()->yield(); continue; } + if (g_gui.m_opened) + { + script::get_current()->yield(); + continue; + } + if (PAD::IS_DISABLED_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_VEH_DUCK)) { g_context_menu_service->enabled = !g_context_menu_service->enabled; @@ -180,21 +313,36 @@ namespace big if (g_context_menu_service->enabled) { + HUD::SHOW_HUD_COMPONENT_THIS_FRAME(14 /*RETICLE*/); + g_context_menu_service->get_entity_closest_to_screen_center(); const auto cm = g_context_menu_service->get_context_menu(); if (cm == nullptr) { - g_context_menu_service->enabled = !g_context_menu_service->enabled; + script::get_current()->yield(); + continue; } - - if (g_context_menu_service->enabled) + else { - if (!g_context_menu_service->m_pointer) - continue; - cm->options.at(cm->current_option).command(); + if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_WEAPON_WHEEL_NEXT)) + cm->current_option = cm->options.size() <= cm->current_option + 1 ? 0 : cm->current_option + 1; + if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_WEAPON_WHEEL_PREV)) + cm->current_option = 0 > cm->current_option - 1 ? static_cast(cm->options.size()) - 1 : cm->current_option - 1; + + if (PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_ATTACK) || + PAD::IS_DISABLED_CONTROL_JUST_PRESSED(0, (int)ControllerInputs::INPUT_SPECIAL_ABILITY)) + { + if (!g_context_menu_service->m_pointer) + { + continue; + } + + cm->options.at(cm->current_option).command(); + } } } + script::get_current()->yield(); } } diff --git a/BigBaseV2/src/services/context_menu_service.hpp b/BigBaseV2/src/services/context_menu_service.hpp index bce24083..3f63ae58 100644 --- a/BigBaseV2/src/services/context_menu_service.hpp +++ b/BigBaseV2/src/services/context_menu_service.hpp @@ -6,15 +6,6 @@ namespace big { - enum class ContextEntityType - { - PED, - PLAYER, - VEHICLE, - OBJECT, - SHARED - }; - struct context_option { std::string name; @@ -29,9 +20,16 @@ namespace big std::vector options; }; + struct model_bounding_box_screen_space + { + ImVec2 edge1, edge2, edge3, edge4; + ImVec2 edge5, edge6, edge7, edge8; + }; + class context_menu_service final { private: + void fill_model_bounding_box_screen_space(); static double distance_to_middle_of_screen(const rage::vector2& screen_pos); public: @@ -53,6 +51,7 @@ namespace big Entity m_handle; rage::fwEntity* m_pointer; + model_bounding_box_screen_space m_model_bounding_box_screen_space; s_context_menu vehicle_menu{ ContextEntityType::VEHICLE, diff --git a/BigBaseV2/src/util/misc.hpp b/BigBaseV2/src/util/misc.hpp index 871421f6..72c8408d 100644 --- a/BigBaseV2/src/util/misc.hpp +++ b/BigBaseV2/src/util/misc.hpp @@ -16,7 +16,13 @@ namespace big::misc { return *address & 1 << pos; } - + + template + inline bool has_bits_set(T* address, T bits) + { + return (*address & bits) == bits; + } + inline bool has_bits_set(int* address, int bits) { return (*address & bits) == bits; @@ -31,4 +37,4 @@ namespace big::misc { *address |= bits; } -} \ No newline at end of file +} diff --git a/BigBaseV2/src/views/settings/view_context_menu_settings.cpp b/BigBaseV2/src/views/settings/view_context_menu_settings.cpp index 48d87fdf..7bf84666 100644 --- a/BigBaseV2/src/views/settings/view_context_menu_settings.cpp +++ b/BigBaseV2/src/views/settings/view_context_menu_settings.cpp @@ -1,9 +1,41 @@ #include "views/view.hpp" +#include "services/context_menu_service.hpp" namespace big { void view::context_menu_settings() { ImGui::Checkbox("Context Menu Enabled", &g->context_menu.enabled); + + if (g->context_menu.enabled) + { + ImGui::Text("Allowed Entity Types:"); + ImGui::CheckboxFlags("Object", reinterpret_cast(&g->context_menu.allowed_entity_types), static_cast(ContextEntityType::OBJECT)); + ImGui::SameLine(); + ImGui::CheckboxFlags("Ped", reinterpret_cast(&g->context_menu.allowed_entity_types), static_cast(ContextEntityType::PED)); + ImGui::SameLine(); + ImGui::CheckboxFlags("Player", reinterpret_cast(&g->context_menu.allowed_entity_types), static_cast(ContextEntityType::PLAYER)); + ImGui::SameLine(); + ImGui::CheckboxFlags("Vehicle", reinterpret_cast(&g->context_menu.allowed_entity_types), static_cast(ContextEntityType::VEHICLE)); + + static ImVec4 selected_option_color = ImGui::ColorConvertU32ToFloat4(g->context_menu.selected_option_color); + ImGui::Text("Selected Option Color:"); + if (ImGui::ColorEdit4("###BSelected Option Color##cm_picker", (float*)&selected_option_color, ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_NoSidePreview)) + { + g->context_menu.selected_option_color = ImGui::ColorConvertFloat4ToU32(selected_option_color); + } + + ImGui::Checkbox("Bounding Box Enabled", &g->context_menu.bounding_box_enabled); + + if (g->context_menu.bounding_box_enabled) + { + static ImVec4 bounding_box_color = ImGui::ColorConvertU32ToFloat4(g->context_menu.bounding_box_color); + ImGui::Text("Bounding Box Color:"); + if (ImGui::ColorEdit4("###Bounding Box Color##cm_picker", (float*)&bounding_box_color, ImGuiColorEditFlags_InputRGB | ImGuiColorEditFlags_NoSidePreview)) + { + g->context_menu.bounding_box_color = ImGui::ColorConvertFloat4ToU32(bounding_box_color); + } + } + } } } diff --git a/BigBaseV2/src/views/view_context_menu.cpp b/BigBaseV2/src/views/view_context_menu.cpp index bb70ca8e..3bcb623e 100644 --- a/BigBaseV2/src/views/view_context_menu.cpp +++ b/BigBaseV2/src/views/view_context_menu.cpp @@ -3,6 +3,27 @@ namespace big { + static void draw_model_bounding_box(ImDrawList* draw_list, const model_bounding_box_screen_space& m_model_bounding_box_screen_space) + { + const auto& box = g_context_menu_service->m_model_bounding_box_screen_space; + const auto& color = g->context_menu.bounding_box_color; + + draw_list->AddLine(box.edge1, box.edge2, color); + draw_list->AddLine(box.edge1, box.edge4, color); + draw_list->AddLine(box.edge2, box.edge3, color); + draw_list->AddLine(box.edge3, box.edge4, color); + + draw_list->AddLine(box.edge5, box.edge6, color); + draw_list->AddLine(box.edge5, box.edge8, color); + draw_list->AddLine(box.edge6, box.edge7, color); + draw_list->AddLine(box.edge7, box.edge8, color); + + draw_list->AddLine(box.edge1, box.edge7, color); + draw_list->AddLine(box.edge2, box.edge8, color); + draw_list->AddLine(box.edge3, box.edge5, color); + draw_list->AddLine(box.edge4, box.edge6, color); + } + void view::context_menu() { if (const auto draw_list = ImGui::GetBackgroundDrawList(); draw_list) @@ -35,10 +56,13 @@ namespace big for (std::uint32_t i = 0; i < cm->options.size(); i++) { const auto co = cm->options.at(i); - draw_list->AddText({ cm_start_x + 7.f, cm_start_y + (20.f * static_cast(i)) + 5.f }, cm->current_option == i ? ImGui::ColorConvertFloat4ToU32({ 0.f, 1.f, 0.f, 1.f }) : ImGui::ColorConvertFloat4ToU32({ 1.f, 1.f, 1.f, 1.f }), co.name.c_str()); + draw_list->AddText({ cm_start_x + 7.f, cm_start_y + (20.f * static_cast(i)) + 5.f }, cm->current_option == i ? g->context_menu.selected_option_color : ImGui::ColorConvertFloat4ToU32({ 1.f, 1.f, 1.f, 1.f }), co.name.c_str()); } + + if (g->context_menu.bounding_box_enabled) + draw_model_bounding_box(draw_list, g_context_menu_service->m_model_bounding_box_screen_space); } } } } -} \ No newline at end of file +}