feat context_menu_service (#293)

- add box around selected entity
- add option to select entity types 
- show reticle in middle of screen
This commit is contained in:
Quentin E. / iDeath 2022-06-29 23:27:44 +02:00 committed by GitHub
parent 3f46bad9c1
commit 4d19585b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 264 additions and 25 deletions

View File

@ -13,6 +13,16 @@ namespace big
VEHICLE_GUN 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 enum class eEntityType
{ {
UNK_0, UNK_0,

View File

@ -3,6 +3,7 @@
#include "enums.hpp" #include "enums.hpp"
#include "file_manager.hpp" #include "file_manager.hpp"
#include "imgui.h" #include "imgui.h"
#include <bitset>
namespace big namespace big
{ {
@ -266,6 +267,17 @@ namespace big
struct context_menu struct context_menu
{ {
bool enabled = true; bool enabled = true;
uint8_t allowed_entity_types =
static_cast<uint8_t>(ContextEntityType::PED) |
static_cast<uint8_t>(ContextEntityType::PLAYER) |
static_cast<uint8_t>(ContextEntityType::VEHICLE) |
static_cast<uint8_t>(ContextEntityType::OBJECT);
ImU32 selected_option_color = 4278255360;
bool bounding_box_enabled = true;
ImU32 bounding_box_color = 4278255360;
}; };
struct esp struct esp
@ -529,6 +541,10 @@ namespace big
this->window.users = j["window"]["users"]; this->window.users = j["window"]["users"];
this->context_menu.enabled = j["context_menu"]["enabled"]; 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.enabled = j["esp"]["enabled"];
this->esp.hide_self = j["esp"]["hide_self"]; this->esp.hide_self = j["esp"]["hide_self"];
@ -785,7 +801,11 @@ namespace big
}, },
{ {
"context_menu", { "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 },
} }
}, },
{ {

View File

@ -2,6 +2,8 @@
#include "natives.hpp" #include "natives.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "gta/replay.hpp" #include "gta/replay.hpp"
#include "gui.hpp"
#include "util/misc.hpp"
namespace big namespace big
{ {
@ -16,6 +18,94 @@ namespace big
g_context_menu_service = nullptr; 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<float>(*g_pointers->m_resolution_x) * screen_result.x;
screen_result.y = static_cast<float>(*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 context_menu_service::distance_to_middle_of_screen(const rage::vector2& screen_pos)
{ {
double cumulative_distance{}; double cumulative_distance{};
@ -39,8 +129,12 @@ namespace big
{ {
switch (m_pointer->m_model_info->m_model_type) 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<uint8_t>(ContextEntityType::OBJECT)))
{
break;
}
return &options.at(ContextEntityType::OBJECT); return &options.at(ContextEntityType::OBJECT);
} }
case eModelType::Ped: case eModelType::Ped:
@ -50,16 +144,39 @@ namespace big
if (ped->m_ped_task_flag & static_cast<uint8_t>(ePedTask::TASK_DRIVING) && if (ped->m_ped_task_flag & static_cast<uint8_t>(ePedTask::TASK_DRIVING) &&
ped->m_vehicle) ped->m_vehicle)
{ {
if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast<uint8_t>(ContextEntityType::VEHICLE)))
{
break;
}
m_pointer = ped->m_vehicle; m_pointer = ped->m_vehicle;
return &options.at(ContextEntityType::VEHICLE); return &options.at(ContextEntityType::VEHICLE);
} }
if (ped->m_player_info) if (ped->m_player_info)
{
if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast<uint8_t>(ContextEntityType::PLAYER)))
{
break;
}
return &options.at(ContextEntityType::PLAYER); return &options.at(ContextEntityType::PLAYER);
} }
}
if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast<uint8_t>(ContextEntityType::PED)))
{
break;
}
return &options.at(ContextEntityType::PED); return &options.at(ContextEntityType::PED);
} }
case eModelType::Vehicle: case eModelType::Vehicle:
{ {
if (!misc::has_bits_set(&g->context_menu.allowed_entity_types, static_cast<uint8_t>(ContextEntityType::VEHICLE)))
{
break;
}
return &options.at(ContextEntityType::VEHICLE); return &options.at(ContextEntityType::VEHICLE);
} }
default: default:
@ -86,7 +203,7 @@ namespace big
const auto ptr = all_entities.get(); const auto ptr = all_entities.get();
std::uint32_t offset = 0; 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; 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); 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; offset += obj_interface_size;
double distance = 1; double distance = 1;
bool got_an_entity = false;
rage::vector2 screen_pos{}; rage::vector2 screen_pos{};
for (std::uint32_t i = 0; i < offset; i++) for (std::uint32_t i = 0; i < offset; i++)
{ {
@ -110,12 +228,20 @@ namespace big
const auto pos = temp_pointer->m_navigation->m_position; 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); 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 && 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_handle = temp_handle;
m_pointer = temp_pointer; m_pointer = temp_pointer;
distance = distance_to_middle_of_screen(screen_pos); 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) while (g_running)
{ {
if (!g->context_menu.enabled) { if (!g->context_menu.enabled)
{
g_context_menu_service->enabled = false; g_context_menu_service->enabled = false;
script::get_current()->yield(); script::get_current()->yield();
continue; continue;
} }
if (g_gui.m_opened)
{
script::get_current()->yield();
continue;
}
if (PAD::IS_DISABLED_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_VEH_DUCK)) if (PAD::IS_DISABLED_CONTROL_JUST_RELEASED(0, (int)ControllerInputs::INPUT_VEH_DUCK))
{ {
g_context_menu_service->enabled = !g_context_menu_service->enabled; g_context_menu_service->enabled = !g_context_menu_service->enabled;
@ -180,21 +313,36 @@ namespace big
if (g_context_menu_service->enabled) if (g_context_menu_service->enabled)
{ {
HUD::SHOW_HUD_COMPONENT_THIS_FRAME(14 /*RETICLE*/);
g_context_menu_service->get_entity_closest_to_screen_center(); g_context_menu_service->get_entity_closest_to_screen_center();
const auto cm = g_context_menu_service->get_context_menu(); const auto cm = g_context_menu_service->get_context_menu();
if (cm == nullptr) if (cm == nullptr)
{ {
g_context_menu_service->enabled = !g_context_menu_service->enabled; script::get_current()->yield();
continue;
} }
else
{
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<int>(cm->options.size()) - 1 : cm->current_option - 1;
if (g_context_menu_service->enabled) 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) if (!g_context_menu_service->m_pointer)
{
continue; continue;
}
cm->options.at(cm->current_option).command(); cm->options.at(cm->current_option).command();
} }
} }
}
script::get_current()->yield(); script::get_current()->yield();
} }
} }

View File

@ -6,15 +6,6 @@
namespace big namespace big
{ {
enum class ContextEntityType
{
PED,
PLAYER,
VEHICLE,
OBJECT,
SHARED
};
struct context_option struct context_option
{ {
std::string name; std::string name;
@ -29,9 +20,16 @@ namespace big
std::vector<context_option> options; std::vector<context_option> options;
}; };
struct model_bounding_box_screen_space
{
ImVec2 edge1, edge2, edge3, edge4;
ImVec2 edge5, edge6, edge7, edge8;
};
class context_menu_service final class context_menu_service final
{ {
private: private:
void fill_model_bounding_box_screen_space();
static double distance_to_middle_of_screen(const rage::vector2& screen_pos); static double distance_to_middle_of_screen(const rage::vector2& screen_pos);
public: public:
@ -53,6 +51,7 @@ namespace big
Entity m_handle; Entity m_handle;
rage::fwEntity* m_pointer; rage::fwEntity* m_pointer;
model_bounding_box_screen_space m_model_bounding_box_screen_space;
s_context_menu vehicle_menu{ s_context_menu vehicle_menu{
ContextEntityType::VEHICLE, ContextEntityType::VEHICLE,

View File

@ -17,6 +17,12 @@ namespace big::misc
return *address & 1 << pos; return *address & 1 << pos;
} }
template<typename T>
inline bool has_bits_set(T* address, T bits)
{
return (*address & bits) == bits;
}
inline bool has_bits_set(int* address, int bits) inline bool has_bits_set(int* address, int bits)
{ {
return (*address & bits) == bits; return (*address & bits) == bits;

View File

@ -1,9 +1,41 @@
#include "views/view.hpp" #include "views/view.hpp"
#include "services/context_menu_service.hpp"
namespace big namespace big
{ {
void view::context_menu_settings() void view::context_menu_settings()
{ {
ImGui::Checkbox("Context Menu Enabled", &g->context_menu.enabled); ImGui::Checkbox("Context Menu Enabled", &g->context_menu.enabled);
if (g->context_menu.enabled)
{
ImGui::Text("Allowed Entity Types:");
ImGui::CheckboxFlags("Object", reinterpret_cast<int*>(&g->context_menu.allowed_entity_types), static_cast<int>(ContextEntityType::OBJECT));
ImGui::SameLine();
ImGui::CheckboxFlags("Ped", reinterpret_cast<int*>(&g->context_menu.allowed_entity_types), static_cast<int>(ContextEntityType::PED));
ImGui::SameLine();
ImGui::CheckboxFlags("Player", reinterpret_cast<int*>(&g->context_menu.allowed_entity_types), static_cast<int>(ContextEntityType::PLAYER));
ImGui::SameLine();
ImGui::CheckboxFlags("Vehicle", reinterpret_cast<int*>(&g->context_menu.allowed_entity_types), static_cast<int>(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);
}
}
}
} }
} }

View File

@ -3,6 +3,27 @@
namespace big 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() void view::context_menu()
{ {
if (const auto draw_list = ImGui::GetBackgroundDrawList(); draw_list) if (const auto draw_list = ImGui::GetBackgroundDrawList(); draw_list)
@ -35,8 +56,11 @@ namespace big
for (std::uint32_t i = 0; i < cm->options.size(); i++) for (std::uint32_t i = 0; i < cm->options.size(); i++)
{ {
const auto co = cm->options.at(i); const auto co = cm->options.at(i);
draw_list->AddText({ cm_start_x + 7.f, cm_start_y + (20.f * static_cast<float>(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<float>(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);
} }
} }
} }