From d2494336c1e3c6cdfbccf23a6d870e1284ba4625 Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Fri, 7 Jan 2022 19:19:04 +0100 Subject: [PATCH 1/5] Draw triggers --- src/client/component/gui_debug.cpp | 665 +++++++++++++++++++++++++++++ src/client/game/structs.hpp | 60 ++- 2 files changed, 717 insertions(+), 8 deletions(-) create mode 100644 src/client/component/gui_debug.cpp diff --git a/src/client/component/gui_debug.cpp b/src/client/component/gui_debug.cpp new file mode 100644 index 00000000..4f8fdc06 --- /dev/null +++ b/src/client/component/gui_debug.cpp @@ -0,0 +1,665 @@ +#include <std_include.hpp> +#include "loader/component_loader.hpp" + +#include "game/game.hpp" +#include "game/dvars.hpp" + +#include "scheduler.hpp" +#include "gui.hpp" + +#include <utils/string.hpp> + +namespace gui_debug +{ + namespace + { + game::dvar_t* cl_paused = nullptr; + + enum object_type + { + square, + circle, + circle_fill, + cube, + cube_mesh + }; + + float camera[3] = {}; + float axis[3][3] = {}; + + struct draw_settings + { + bool enabled; + bool camera_locked; + float camera[3] = {}; + float range = 500.f; + float color[4] = {1.f, 0.f, 0.f, 1.f}; + float mesh_thickness = 1.f; + float size = 10.f; + object_type type; + }; + + struct : draw_settings + { + float link_thickness = 1.f; + bool draw_linked_nodes; + } path_node_settings{}; + + struct point + { + ImVec2 point; + bool valid; + }; + + draw_settings trigger_settings{}; + + float vector_dot(float* a, float* b) + { + return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); + } + + bool world_pos_to_screen_pos(float* origin, float* out) + { + float local[3] = + { + origin[0] - camera[0], + origin[1] - camera[1], + origin[2] - camera[2] + }; + + float transform[3] = + { + vector_dot(local, axis[1]), + vector_dot(local, axis[2]), + vector_dot(local, axis[0]) + }; + + if (transform[2] < 0.1f) + { + return false; + } + + const auto width = game::ScrPlace_GetViewPlacement()->realViewportSize[0]; + const auto height = game::ScrPlace_GetViewPlacement()->realViewportSize[1]; + + out[0] = (width / 2) * (1 - transform[0] / game::refdef->fovX / transform[2]); + out[1] = (height / 2) * (1 - transform[1] / game::refdef->fovY / transform[2]); + + return true; + } + + void draw_line(float* start, float* end, float* color, float thickness) + { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + float start_screen[2] = {}; + float end_screen[2] = {}; + + auto result = 1; + result *= world_pos_to_screen_pos(start, start_screen); + result *= world_pos_to_screen_pos(end, end_screen); + + if (!result) + { + return; + } + + const auto start_ = ImVec2(start_screen[0], start_screen[1]); + const auto end_ = ImVec2(end_screen[0], end_screen[1]); + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + + window->DrawList->AddLine(start_, end_, color_, thickness); + } + + void draw_square(float* origin, float width, float* color) + { + const auto half = width / 2.f; + float p1[3] = {origin[0] - half, origin[1] + half, origin[2]}; + float p2[3] = {origin[0] + half, origin[1] + half, origin[2]}; + float p3[3] = {origin[0] + half, origin[1] - half, origin[2]}; + float p4[3] = {origin[0] - half, origin[1] - half, origin[2]}; + + float p1_screen[2] = {}; + float p2_screen[2] = {}; + float p3_screen[2] = {}; + float p4_screen[2] = {}; + + auto result = 1; + result *= world_pos_to_screen_pos(p1, p1_screen); + result *= world_pos_to_screen_pos(p2, p2_screen); + result *= world_pos_to_screen_pos(p3, p3_screen); + result *= world_pos_to_screen_pos(p4, p4_screen); + + if (!result) + { + return; + } + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + ImVec2 points[4] = + { + ImVec2(p1_screen[0], p1_screen[1]), + ImVec2(p2_screen[0], p2_screen[1]), + ImVec2(p3_screen[0], p3_screen[1]), + ImVec2(p4_screen[0], p4_screen[1]) + }; + + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + window->DrawList->AddConvexPolyFilled(points, 4, color_); + } + + void draw_square_from_points(float* p1, float* p2, float* p3, float* p4, float* color) + { + float p1_screen[2] = {}; + float p2_screen[2] = {}; + float p3_screen[2] = {}; + float p4_screen[2] = {}; + + auto result = 1; + result *= world_pos_to_screen_pos(p1, p1_screen); + result *= world_pos_to_screen_pos(p2, p2_screen); + result *= world_pos_to_screen_pos(p3, p3_screen); + result *= world_pos_to_screen_pos(p4, p4_screen); + + if (!result) + { + return; + } + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + ImVec2 points[4] = + { + ImVec2(p1_screen[0], p1_screen[1]), + ImVec2(p2_screen[0], p2_screen[1]), + ImVec2(p3_screen[0], p3_screen[1]), + ImVec2(p4_screen[0], p4_screen[1]) + }; + + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + window->DrawList->AddConvexPolyFilled(points, 4, color_); + } + + void draw_cube(float* origin, float width, float* color) + { + const auto half = width / 2.f; + + float p1[3] = {origin[0] - half, origin[1] + half, origin[2]}; + float p2[3] = {origin[0] + half, origin[1] + half, origin[2]}; + float p3[3] = {origin[0] + half, origin[1] - half, origin[2]}; + float p4[3] = {origin[0] - half, origin[1] - half, origin[2]}; + + float p1_top[3] = {p1[0], p1[1], origin[2] + width}; + float p2_top[3] = {p2[0], p2[1], origin[2] + width}; + float p3_top[3] = {p3[0], p3[1], origin[2] + width}; + float p4_top[3] = {p4[0], p4[1], origin[2] + width}; + + draw_square_from_points(p1, p2, p3, p4, color); + draw_square_from_points(p1_top, p2_top, p3_top, p4_top, color); + + draw_square_from_points(p3, p2, p2_top, p3_top, color); + draw_square_from_points(p4, p1, p1_top, p4_top, color); + + draw_square_from_points(p1, p2, p2_top, p1_top, color); + draw_square_from_points(p4, p3, p3_top, p4_top, color); + } + + void draw_cube_mesh(float* origin, float width, float* color, float thickness) + { + const auto half = width / 2.f; + + float p1[3] = {origin[0] - half, origin[1] + half, origin[2]}; + float p2[3] = {origin[0] + half, origin[1] + half, origin[2]}; + float p3[3] = {origin[0] + half, origin[1] - half, origin[2]}; + float p4[3] = {origin[0] - half, origin[1] - half, origin[2]}; + + float p1_top[3] = {p1[0], p1[1], origin[2] + width}; + float p2_top[3] = {p2[0], p2[1], origin[2] + width}; + float p3_top[3] = {p3[0], p3[1], origin[2] + width}; + float p4_top[3] = {p4[0], p4[1], origin[2] + width}; + + draw_line(p1, p2, color, thickness); + draw_line(p2, p3, color, thickness); + draw_line(p3, p4, color, thickness); + draw_line(p4, p1, color, thickness); + + draw_line(p1_top, p2_top, color, thickness); + draw_line(p2_top, p3_top, color, thickness); + draw_line(p3_top, p4_top, color, thickness); + draw_line(p4_top, p1_top, color, thickness); + + draw_line(p1, p1_top, color, thickness); + draw_line(p2, p2_top, color, thickness); + draw_line(p3, p3_top, color, thickness); + draw_line(p4, p4_top, color, thickness); + } + + float get_pi() + { + static const auto pi = static_cast<float>(atan(1)) * 4.f; + return pi; + } + + void draw_circle(float* center, float radius, float* color, float thickness) + { + const auto pi = get_pi(); + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + window->DrawList->PathClear(); + + for (auto angle = 0.f; angle < 360; angle += 1.f) + { + const auto x = center[0] + radius * cos(angle * pi / 180.f); + const auto y = center[1] + radius * sin(angle * pi / 180.f); + + float point[3] = {x, y, center[2]}; + float point_screen[2] = {}; + + if (!world_pos_to_screen_pos(point, point_screen)) + { + return; + } + + const auto point_ = ImVec2(point_screen[0], point_screen[1]); + window->DrawList->PathLineTo(point_); + } + + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + window->DrawList->PathStroke(color_, 0, thickness); + } + + void draw_circle_filled(float* center, float radius, float* color) + { + const auto pi = get_pi(); + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + window->DrawList->PathClear(); + + for (auto angle = 0; angle < 360; angle += 12) + { + const auto x = center[0] + radius * cos(static_cast<float>(angle) * pi / 180.f); + const auto y = center[1] + radius * sin(static_cast<float>(angle) * pi / 180.f); + + float point[3] = {x, y, center[2]}; + float point_screen[2] = {}; + + if (!world_pos_to_screen_pos(point, point_screen)) + { + continue; + } + + const auto point_ = ImVec2(point_screen[0], point_screen[1]); + window->DrawList->PathLineTo(point_); + } + + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + window->DrawList->PathFillConvex(color_); + } + + void draw_cylinder(float* center, float radius, float height, float* color, float thickness) + { + const auto pi = get_pi(); + + ImGuiWindow* window = ImGui::GetCurrentWindow(); + + float top[3] = {center[0], center[1], center[2] + height}; + + const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); + + const auto max_points = 30; + const auto step = 360 / max_points; + + point points_top[max_points]; + point points_bottom[max_points]; + + auto point_index = 0; + for (auto angle = 0; angle < 360; angle += step) + { + const auto x = center[0] + radius * cos(static_cast<float>(angle) * pi / 180.f); + const auto y = center[1] + radius * sin(static_cast<float>(angle) * pi / 180.f); + + float point[3] = {x, y, center[2]}; + float point_top[3] = {x, y, center[2] + height}; + + float point_screen[2] = {}; + float point_top_screen[2] = {}; + + const auto index = point_index++; + + auto result = 1; + result *= world_pos_to_screen_pos(point, point_screen); + result *= world_pos_to_screen_pos(point_top, point_top_screen); + + if (!result) + { + points_bottom[index] = {{}, false}; + points_top[index] = {{}, false}; + continue; + } + + points_bottom[index] = {ImVec2(point_screen[0], point_screen[1]), true}; + points_top[index] = {ImVec2(point_top_screen[0], point_top_screen[1]), true}; + } + + window->DrawList->PathClear(); + for (auto i = 0; i < max_points; i++) + { + if (!points_bottom[i].valid) + { + continue; + } + + window->DrawList->PathLineTo(points_bottom[i].point); + } + window->DrawList->PathFillConvex(color_); + + window->DrawList->PathClear(); + for (auto i = 0; i < max_points; i++) + { + if (!points_top[i].valid) + { + continue; + } + + window->DrawList->PathLineTo(points_top[i].point); + } + window->DrawList->PathFillConvex(color_); + + for (auto i = 0; i < max_points - 1; i++) + { + window->DrawList->PathClear(); + + if (!points_bottom[i].valid) + { + continue; + } + + window->DrawList->PathLineTo(points_bottom[i].point); + + if (i == max_points - 1) + { + window->DrawList->PathLineTo(points_bottom[0].point); + window->DrawList->PathLineTo(points_top[0].point); + } + else + { + window->DrawList->PathLineTo(points_bottom[i + 1].point); + window->DrawList->PathLineTo(points_top[i + 1].point); + } + + window->DrawList->PathLineTo(points_top[i].point); + + window->DrawList->PathFillConvex(color_); + } + } + + void draw_object(float* origin, object_type type) + { + switch (type) + { + case object_type::square: + draw_square(origin, path_node_settings.size, path_node_settings.color); + break; + case object_type::circle: + break; + case object_type::cube: + draw_cube(origin, path_node_settings.size, path_node_settings.color); + break; + case object_type::cube_mesh: + draw_cube_mesh(origin, path_node_settings.size, path_node_settings.color, + path_node_settings.mesh_thickness); + break; + } + } + + void draw_window() + { + if (!gui::enabled_menus["debug"]) + { + return; + } + + ImGui::Begin("Debug", &gui::enabled_menus["debug"]); + + if (ImGui::TreeNode("Path nodes")) + { + ImGui::Checkbox("Draw", &path_node_settings.enabled); + ImGui::Checkbox("Lock camera", &path_node_settings.camera_locked); + + ImGui::Checkbox("Draw linked nodes", &path_node_settings.draw_linked_nodes); + + if (ImGui::TreeNode("Object type")) + { + ImGui::RadioButton("square", reinterpret_cast<int*>(&path_node_settings.type), object_type::square); + ImGui::RadioButton("cube", reinterpret_cast<int*>(&path_node_settings.type), object_type::cube); + ImGui::RadioButton("cube mesh", reinterpret_cast<int*>(&path_node_settings.type), object_type::cube_mesh); + + ImGui::TreePop(); + } + + ImGui::SliderFloat("range", &path_node_settings.range, 0.f, 10000.f); + ImGui::SliderFloat("size", &path_node_settings.size, 5.f, 100.f); + + if (path_node_settings.draw_linked_nodes) + { + ImGui::SliderFloat("link thickness", &path_node_settings.link_thickness, 1.f, 20.f); + } + + if (path_node_settings.type == object_type::cube_mesh) + { + ImGui::SliderFloat("mesh thickness", &path_node_settings.mesh_thickness, 1.f, 20.f); + } + + if (ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", path_node_settings.color); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + if (ImGui::TreeNode("Triggers")) + { + ImGui::Checkbox("Draw", &trigger_settings.enabled); + ImGui::Checkbox("Lock camera", &trigger_settings.camera_locked); + + ImGui::SliderFloat("range", &trigger_settings.range, 0.f, 10000.f); + ImGui::SliderFloat("mesh thickness", &trigger_settings.mesh_thickness, 1.f, 20.f); + + if (ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", trigger_settings.color); + ImGui::TreePop(); + } + + ImGui::TreePop(); + } + + ImGui::End(); + } + + float distance_2d(float* a, float* b) + { + return sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1])); + } + + void get_pathnode_origin(game::pathnode_t* node, float* out) + { + out[0] = node->vLocalOrigin[0]; + out[1] = node->vLocalOrigin[1]; + out[2] = node->vLocalOrigin[2]; + + game::PathNode_WorldifyPosFromParent(node, out); + } + + void draw_linked_nodes(game::pathnode_t* node, float* origin) + { + for (unsigned int i = 0; i < node->totalLinkCount; i++) + { + float linked_origin[3] = {}; + const auto num = node->Links[i].nodeNum; + const auto linked = &game::pathData->nodes[num]; + + get_pathnode_origin(linked, linked_origin); + if (distance_2d(path_node_settings.camera, linked_origin) < path_node_settings.range) + { + draw_line(origin, linked_origin, path_node_settings.color, + path_node_settings.link_thickness); + } + } + } + + void begin_render_window() + { + const auto& io = ImGui::GetIO(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f}); + ImGui::PushStyleColor(ImGuiCol_WindowBg, {0.0f, 0.0f, 0.0f, 0.0f}); + ImGui::Begin("debug window", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs); + + ImGui::SetWindowPos(ImVec2(0, 0), ImGuiCond_Always); + ImGui::SetWindowSize(ImVec2(io.DisplaySize.x, io.DisplaySize.y), ImGuiCond_Always); + } + + void end_render_window() + { + ImGuiWindow* window = ImGui::GetCurrentWindow(); + window->DrawList->PushClipRectFullScreen(); + + ImGui::End(); + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + } + + void draw_nodes() + { + if (!path_node_settings.enabled) + { + return; + } + + for (unsigned int i = 0; i < game::pathData->nodeCount; i++) + { + float origin[3] = {}; + const auto node = &game::pathData->nodes[i]; + + get_pathnode_origin(node, origin); + if (distance_2d(path_node_settings.camera, origin) >= path_node_settings.range) + { + continue; + } + + draw_object(origin, path_node_settings.type); + if (path_node_settings.draw_linked_nodes) + { + draw_linked_nodes(node, origin); + } + } + } + + void draw_triggers() + { + if (!trigger_settings.enabled) + { + return; + } + + const auto trigger_radius = game::SL_GetString("trigger_radius", 0); + + for (auto i = 0; i < 0xF9E; i++) + { + const auto entity = &game::g_entities[i]; + const auto origin = entity->origin; + const auto radius = entity->halfSize[0]; + const auto height = entity->halfSize[2] * 2.f; + + const auto distance = distance_2d(trigger_settings.camera, origin); + + if (distance - radius > trigger_settings.range || entity->script_classname != trigger_radius) + { + continue; + } + + float top[3] = {origin[0], origin[1], origin[2] + entity->halfSize[2] * 2.f}; + draw_cylinder(top, radius, height, trigger_settings.color, trigger_settings.mesh_thickness); + } + } + + void update_camera() + { + camera[0] = game::refdef->org[0]; + camera[1] = game::refdef->org[1]; + camera[2] = game::refdef->org[2]; + + axis[0][0] = game::refdef->axis[0][0]; + axis[0][1] = game::refdef->axis[0][1]; + axis[0][2] = game::refdef->axis[0][2]; + + axis[1][0] = game::refdef->axis[1][0]; + axis[1][1] = game::refdef->axis[1][1]; + axis[1][2] = game::refdef->axis[1][2]; + + axis[2][0] = game::refdef->axis[2][0]; + axis[2][1] = game::refdef->axis[2][1]; + axis[2][2] = game::refdef->axis[2][2]; + + if (!path_node_settings.camera_locked) + { + path_node_settings.camera[0] = camera[0]; + path_node_settings.camera[1] = camera[1]; + path_node_settings.camera[2] = camera[2]; + } + + if (!trigger_settings.camera_locked) + { + trigger_settings.camera[0] = camera[0]; + trigger_settings.camera[1] = camera[1]; + trigger_settings.camera[2] = camera[2]; + } + } + } + + class component final : public component_interface + { + public: + void post_unpack() override + { + gui::on_frame(draw_window); + gui::on_frame(draw_nodes, true); + gui::on_frame([]() + { + if (!game::SV_Loaded() || cl_paused->current.integer) + { + return; + } + + begin_render_window(); + draw_nodes(); + draw_triggers(); + end_render_window(); + }, true); + + scheduler::on_game_initialized([]() + { + cl_paused = game::Dvar_FindVar("cl_paused"); + }); + + scheduler::loop([]() + { + if (!game::SV_Loaded() || cl_paused->current.integer) + { + return; + } + + update_camera(); + }, scheduler::pipeline::renderer); + } + }; +} + +REGISTER_COMPONENT(gui_debug::component) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 3eaf0d67..f131e3ab 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -56,18 +56,67 @@ namespace game char entityNum; }; + enum scr_string_t + { + scr_string_t_dummy = 0x0, + }; + struct gentity_s { EntityState s; char __pad0[0x1B]; vec3_t origin; - char __pad1[0xF0]; + char __pad1[152]; + float midPoint[3]; // entityShared.box + float halfSize[3]; // entityShared.box + char __pad2[64]; gclient_s* client; - char __pad2[0x4C]; + char __pad3[48]; + scr_string_t script_classname; + char __pad4[0x14]; // 416 char flags; - char __pad3[392]; + char __pad5[392]; }; // size = 760 + static_assert(sizeof(gentity_s) == 760); + + struct pathlink_s + { + char __pad0[4]; + unsigned __int16 nodeNum; + char __pad[6]; + }; + + static_assert(sizeof(pathlink_s) == 12); + + struct pathnode_t + { + unsigned __int16 type; + unsigned int spawnflags; + unsigned int targetname; + unsigned int script_linkName; + unsigned int script_noteworthy; + unsigned int target; + unsigned int animscript; + int animscriptfunc; + float vLocalOrigin[3]; + char __pad0[28]; + unsigned __int16 totalLinkCount; + char __pad1[2]; + pathlink_s* Links; + char __pad2[104]; + }; // size = 192 + + static_assert(sizeof(pathnode_t) == 192); + + struct PathData + { + const char* name; + unsigned int nodeCount; + pathnode_t* nodes; + // ... + }; + struct Material { const char* name; @@ -653,11 +702,6 @@ namespace game int freeFlags; }; - enum scr_string_t - { - scr_string_t_dummy = 0x0, - }; - struct scr_entref_t { unsigned short entnum; From 72a02c2deb2e9f58fb026aef75dd52b49b4bfecd Mon Sep 17 00:00:00 2001 From: Federico Cecchetto <fedecek3@gmail.com> Date: Sat, 8 Jan 2022 01:28:46 +0100 Subject: [PATCH 2/5] Entity list & asset list & debug windows fixes --- src/client/component/gui_asset_list.cpp | 6 ++++-- src/client/component/gui_debug.cpp | 25 ++++++++++++++++-------- src/client/component/gui_entity_list.cpp | 9 ++++++--- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/client/component/gui_asset_list.cpp b/src/client/component/gui_asset_list.cpp index 4950026f..b8a02ef3 100644 --- a/src/client/component/gui_asset_list.cpp +++ b/src/client/component/gui_asset_list.cpp @@ -64,12 +64,14 @@ namespace asset_list ImGui::InputText("asset name", &assets_name_filter[type]); ImGui::BeginChild("assets list"); - fastfiles::enum_assets(type, [type](const game::XAssetHeader header) + const auto lowercase_filter = utils::string::to_lower(assets_name_filter[type]); + + fastfiles::enum_assets(type, [&lowercase_filter, type](const game::XAssetHeader header) { const auto asset = game::XAsset{type, header}; const auto* const asset_name = game::DB_GetXAssetName(&asset); - if (utils::string::find_lower(asset_name, assets_name_filter[type]) && ImGui::Button(asset_name)) + if (strstr(asset_name, lowercase_filter.data()) && ImGui::Button(asset_name)) { gui::copy_to_clipboard(asset_name); } diff --git a/src/client/component/gui_debug.cpp b/src/client/component/gui_debug.cpp index 5c2b131c..a172100f 100644 --- a/src/client/component/gui_debug.cpp +++ b/src/client/component/gui_debug.cpp @@ -81,7 +81,7 @@ namespace gui_debug vector_dot(local, axis[0]) }; - if (transform[2] < 0.1f) + if (transform[2] < 0.01f) { return false; } @@ -375,11 +375,12 @@ namespace gui_debug } window->DrawList->PathFillConvex(color_); - for (auto i = 0; i < max_points - 1; i++) + for (auto i = 0; i < max_points; i++) { window->DrawList->PathClear(); - if (!points_bottom[i].valid) + if (!points_bottom[i].valid || + !points_top[i].valid) { continue; } @@ -388,11 +389,21 @@ namespace gui_debug if (i == max_points - 1) { + if (!points_bottom[0].valid || !points_top[0].valid) + { + continue; + } + window->DrawList->PathLineTo(points_bottom[0].point); window->DrawList->PathLineTo(points_top[0].point); } else { + if (!points_bottom[i + 1].valid || !points_top[i + 1].valid) + { + continue; + } + window->DrawList->PathLineTo(points_bottom[i + 1].point); window->DrawList->PathLineTo(points_top[i + 1].point); } @@ -592,8 +603,7 @@ namespace gui_debug continue; } - float top[3] = {origin[0], origin[1], origin[2] + entity->halfSize[2] * 2.f}; - draw_cylinder(top, radius, height, trigger_settings.color, trigger_settings.mesh_thickness); + draw_cylinder(origin, radius, height, trigger_settings.color, trigger_settings.mesh_thickness); } } @@ -637,7 +647,6 @@ namespace gui_debug void post_unpack() override { gui::on_frame(draw_window); - gui::on_frame(draw_nodes, true); gui::on_frame([]() { if (!game::SV_Loaded() || cl_paused->current.integer) @@ -651,10 +660,10 @@ namespace gui_debug end_render_window(); }, true); - scheduler::on_game_initialized([]() + scheduler::once([]() { cl_paused = game::Dvar_FindVar("cl_paused"); - }); + }, scheduler::pipeline::main); scheduler::loop([]() { diff --git a/src/client/component/gui_entity_list.cpp b/src/client/component/gui_entity_list.cpp index a0151f19..40eddb62 100644 --- a/src/client/component/gui_entity_list.cpp +++ b/src/client/component/gui_entity_list.cpp @@ -666,7 +666,7 @@ namespace entity_list ImGui::Text("Fields"); auto index = 0; - for (auto i = data.filters.fields.begin(); i != data.filters.fields.end(); ++i) + for (auto i = data.filters.fields.begin(); i != data.filters.fields.end();) { if (ImGui::TreeNode(utils::string::va("Filter #%i", index++))) { @@ -675,12 +675,15 @@ namespace entity_list if (ImGui::Button("Erase")) { - data.filters.fields.erase(i); - --i; + i = data.filters.fields.erase(i); + ImGui::TreePop(); + continue; } ImGui::TreePop(); } + + ++i; } if (ImGui::Button("Add field filter")) From ece5da170bd78079a6b76992a19e1889cfbe69eb Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Sat, 8 Jan 2022 10:39:08 +0100 Subject: [PATCH 3/5] Fix entity struct --- src/client/game/structs.hpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 30aae8ff..490266f5 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -12,7 +12,7 @@ namespace game { char __pad0[0x8C]; vec3_t velocity; - char __pad1[59504]; + char __pad1[0xE870]; char flags; }; @@ -66,25 +66,27 @@ namespace game EntityState s; char __pad0[0x1B]; vec3_t origin; - char __pad1[152]; - float midPoint[3]; // entityShared.box - float halfSize[3]; // entityShared.box - char __pad2[64]; + char __pad1[0x98]; + float midPoint[0x3]; // entityShared.box + float halfSize[0x3]; // entityShared.box + char __pad2[0x40]; gclient_s* client; - char __pad3[48]; + char __pad3[0x30]; scr_string_t script_classname; - char __pad4[0x14]; // 416 + char __pad4[0x18]; char flags; - char __pad5[392]; + char __pad5[0x188]; }; // size = 760 + //auto a = sizeof(gentity_s); + static_assert(sizeof(gentity_s) == 760); struct pathlink_s { - char __pad0[4]; + char __pad0[0x4]; unsigned __int16 nodeNum; - char __pad[6]; + char __pad[0x6]; }; static_assert(sizeof(pathlink_s) == 12); @@ -99,12 +101,12 @@ namespace game unsigned int target; unsigned int animscript; int animscriptfunc; - float vLocalOrigin[3]; - char __pad0[28]; + float vLocalOrigin[0x3]; + char __pad0[0x1C]; unsigned __int16 totalLinkCount; - char __pad1[2]; + char __pad1[0x2]; pathlink_s* Links; - char __pad2[104]; + char __pad2[0x68]; }; // size = 192 static_assert(sizeof(pathnode_t) == 192); From 526a477a59c32bb0d7185dd788e308b2f2454672 Mon Sep 17 00:00:00 2001 From: fed <58637860+fedddddd@users.noreply.github.com> Date: Sat, 8 Jan 2022 20:22:59 +0100 Subject: [PATCH 4/5] More trigger stuff --- src/client/component/gui_debug.cpp | 154 +++++++++-------------------- 1 file changed, 46 insertions(+), 108 deletions(-) diff --git a/src/client/component/gui_debug.cpp b/src/client/component/gui_debug.cpp index a172100f..def9943a 100644 --- a/src/client/component/gui_debug.cpp +++ b/src/client/component/gui_debug.cpp @@ -38,28 +38,32 @@ namespace gui_debug { bool enabled; bool camera_locked; - float camera[3] = {}; - float range = 500.f; - float color[4] = {1.f, 0.f, 0.f, 1.f}; - float mesh_thickness = 1.f; - float size = 10.f; object_type type; + float range = 500.f; + float camera[3] = {}; }; struct : draw_settings { + bool draw_node_links; + float size = 10.f; + float mesh_thickness = 1.f; float link_thickness = 1.f; - bool draw_linked_nodes; + float color[4] = {1.f, 0.f, 0.f, 1.f}; } path_node_settings{}; + struct : draw_settings + { + int point_count = 30; + float color[4] = {0.f, 1.f, 0.f, 0.5f}; + } trigger_settings{}; + struct point { ImVec2 point; bool valid; }; - draw_settings trigger_settings{}; - float vector_dot(float* a, float* b) { return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); @@ -248,82 +252,21 @@ namespace gui_debug return pi; } - void draw_circle(float* center, float radius, float* color, float thickness) + void draw_cylinder(float* center, float radius, float height, int point_count, float* color) { const auto pi = get_pi(); ImGuiWindow* window = ImGui::GetCurrentWindow(); - - window->DrawList->PathClear(); - - for (auto angle = 0.f; angle < 360; angle += 1.f) - { - const auto x = center[0] + radius * cos(angle * pi / 180.f); - const auto y = center[1] + radius * sin(angle * pi / 180.f); - - float point[3] = {x, y, center[2]}; - float point_screen[2] = {}; - - if (!world_pos_to_screen_pos(point, point_screen)) - { - return; - } - - const auto point_ = ImVec2(point_screen[0], point_screen[1]); - window->DrawList->PathLineTo(point_); - } - - const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); - window->DrawList->PathStroke(color_, 0, thickness); - } - - void draw_circle_filled(float* center, float radius, float* color) - { - const auto pi = get_pi(); - - ImGuiWindow* window = ImGui::GetCurrentWindow(); - - window->DrawList->PathClear(); - - for (auto angle = 0; angle < 360; angle += 12) - { - const auto x = center[0] + radius * cos(static_cast<float>(angle) * pi / 180.f); - const auto y = center[1] + radius * sin(static_cast<float>(angle) * pi / 180.f); - - float point[3] = {x, y, center[2]}; - float point_screen[2] = {}; - - if (!world_pos_to_screen_pos(point, point_screen)) - { - continue; - } - - const auto point_ = ImVec2(point_screen[0], point_screen[1]); - window->DrawList->PathLineTo(point_); - } - - const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); - window->DrawList->PathFillConvex(color_); - } - - void draw_cylinder(float* center, float radius, float height, float* color, float thickness) - { - const auto pi = get_pi(); - - ImGuiWindow* window = ImGui::GetCurrentWindow(); - - float top[3] = {center[0], center[1], center[2] + height}; - const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); - const auto max_points = 30; - const auto step = 360 / max_points; + point_count = std::max(0, std::min(point_count, 360)); + const auto step = 360.f / point_count; - point points_top[max_points]; - point points_bottom[max_points]; + point points_top[360]; + point points_bottom[360]; auto point_index = 0; - for (auto angle = 0; angle < 360; angle += step) + for (auto angle = 0.f; angle < 360.f; angle += step) { const auto x = center[0] + radius * cos(static_cast<float>(angle) * pi / 180.f); const auto y = center[1] + radius * sin(static_cast<float>(angle) * pi / 180.f); @@ -352,7 +295,7 @@ namespace gui_debug } window->DrawList->PathClear(); - for (auto i = 0; i < max_points; i++) + for (auto i = 0; i < point_count; i++) { if (!points_bottom[i].valid) { @@ -364,7 +307,7 @@ namespace gui_debug window->DrawList->PathFillConvex(color_); window->DrawList->PathClear(); - for (auto i = 0; i < max_points; i++) + for (auto i = 0; i < point_count; i++) { if (!points_top[i].valid) { @@ -375,7 +318,7 @@ namespace gui_debug } window->DrawList->PathFillConvex(color_); - for (auto i = 0; i < max_points; i++) + for (auto i = 0; i < point_count; i++) { window->DrawList->PathClear(); @@ -387,7 +330,7 @@ namespace gui_debug window->DrawList->PathLineTo(points_bottom[i].point); - if (i == max_points - 1) + if (i == point_count - 1) { if (!points_bottom[0].valid || !points_top[0].valid) { @@ -409,30 +352,10 @@ namespace gui_debug } window->DrawList->PathLineTo(points_top[i].point); - window->DrawList->PathFillConvex(color_); } } - void draw_object(float* origin, object_type type) - { - switch (type) - { - case object_type::square: - draw_square(origin, path_node_settings.size, path_node_settings.color); - break; - case object_type::circle: - break; - case object_type::cube: - draw_cube(origin, path_node_settings.size, path_node_settings.color); - break; - case object_type::cube_mesh: - draw_cube_mesh(origin, path_node_settings.size, path_node_settings.color, - path_node_settings.mesh_thickness); - break; - } - } - void draw_window() { if (!gui::enabled_menus["debug"]) @@ -447,7 +370,7 @@ namespace gui_debug ImGui::Checkbox("Draw", &path_node_settings.enabled); ImGui::Checkbox("Lock camera", &path_node_settings.camera_locked); - ImGui::Checkbox("Draw linked nodes", &path_node_settings.draw_linked_nodes); + ImGui::Checkbox("Draw node links", &path_node_settings.draw_node_links); if (ImGui::TreeNode("Object type")) { @@ -461,7 +384,7 @@ namespace gui_debug ImGui::SliderFloat("range", &path_node_settings.range, 0.f, 10000.f); ImGui::SliderFloat("size", &path_node_settings.size, 5.f, 100.f); - if (path_node_settings.draw_linked_nodes) + if (path_node_settings.draw_node_links) { ImGui::SliderFloat("link thickness", &path_node_settings.link_thickness, 1.f, 20.f); } @@ -486,7 +409,7 @@ namespace gui_debug ImGui::Checkbox("Lock camera", &trigger_settings.camera_locked); ImGui::SliderFloat("range", &trigger_settings.range, 0.f, 10000.f); - ImGui::SliderFloat("mesh thickness", &trigger_settings.mesh_thickness, 1.f, 20.f); + ImGui::SliderInt("circle max points", &trigger_settings.point_count, 3, 360); if (ImGui::TreeNode("Color picker")) { @@ -514,7 +437,7 @@ namespace gui_debug game::PathNode_WorldifyPosFromParent(node, out); } - void draw_linked_nodes(game::pathnode_t* node, float* origin) + void draw_node_links(game::pathnode_t* node, float* origin) { for (unsigned int i = 0; i < node->totalLinkCount; i++) { @@ -572,10 +495,23 @@ namespace gui_debug continue; } - draw_object(origin, path_node_settings.type); - if (path_node_settings.draw_linked_nodes) + switch (path_node_settings.type) { - draw_linked_nodes(node, origin); + case object_type::square: + draw_square(origin, path_node_settings.size, path_node_settings.color); + break; + case object_type::cube: + draw_cube(origin, path_node_settings.size, path_node_settings.color); + break; + case object_type::cube_mesh: + draw_cube_mesh(origin, path_node_settings.size, path_node_settings.color, + path_node_settings.mesh_thickness); + break; + } + + if (path_node_settings.draw_node_links) + { + draw_node_links(node, origin); } } } @@ -598,12 +534,14 @@ namespace gui_debug const auto distance = distance_2d(trigger_settings.camera, origin); - if (distance - radius > trigger_settings.range || entity->script_classname != trigger_radius) + if (distance - radius * 2 > trigger_settings.range || + entity->script_classname != trigger_radius) { continue; } - draw_cylinder(origin, radius, height, trigger_settings.color, trigger_settings.mesh_thickness); + draw_cylinder(origin, radius, height, trigger_settings.point_count, + trigger_settings.color); } } From f1f84b705db71f61ce54f4b254c706931420667e Mon Sep 17 00:00:00 2001 From: Federico Cecchetto <fedecek3@gmail.com> Date: Sun, 9 Jan 2022 02:59:53 +0100 Subject: [PATCH 5/5] More trigger stuff --- src/client/component/gui_debug.cpp | 265 +++++++++++++++++++++-------- src/client/game/structs.hpp | 25 +-- src/client/game/symbols.hpp | 1 + 3 files changed, 204 insertions(+), 87 deletions(-) diff --git a/src/client/component/gui_debug.cpp b/src/client/component/gui_debug.cpp index def9943a..cce50253 100644 --- a/src/client/component/gui_debug.cpp +++ b/src/client/component/gui_debug.cpp @@ -31,6 +31,15 @@ namespace gui_debug cube_mesh }; + enum entity_type + { + other, + trigger_radius, + generic_trigger, + actor, + count + }; + float camera[3] = {}; float axis[3][3] = {}; @@ -39,6 +48,7 @@ namespace gui_debug bool enabled; bool camera_locked; object_type type; + float mesh_thickness = 1.f; float range = 500.f; float camera[3] = {}; }; @@ -47,16 +57,23 @@ namespace gui_debug { bool draw_node_links; float size = 10.f; - float mesh_thickness = 1.f; float link_thickness = 1.f; float color[4] = {1.f, 0.f, 0.f, 1.f}; } path_node_settings{}; struct : draw_settings { + bool enabled_types[entity_type::count]; + float type_colors[entity_type::count][4] = + { + {0.f, 0.5f, 1.f, 0.3f}, + {0.f, 1.f, 0.f, 0.3f}, + {1.0f, 1.f, 0.f, 0.3f}, + {1.f, 0.5f, 1.f, 0.3f}, + }; + bool mesh_only = false; int point_count = 30; - float color[4] = {0.f, 1.f, 0.f, 0.5f}; - } trigger_settings{}; + } entity_bound_settings{}; struct point { @@ -160,7 +177,8 @@ namespace gui_debug window->DrawList->AddConvexPolyFilled(points, 4, color_); } - void draw_square_from_points(float* p1, float* p2, float* p3, float* p4, float* color) + void draw_square_from_points(float* p1, float* p2, float* p3, float* p4, float* color, + float thickness, bool mesh_only) { float p1_screen[2] = {}; float p2_screen[2] = {}; @@ -189,10 +207,25 @@ namespace gui_debug }; const auto color_ = ImGui::GetColorU32({color[0], color[1], color[2], color[3]}); - window->DrawList->AddConvexPolyFilled(points, 4, color_); + + window->DrawList->PathClear(); + window->DrawList->PathLineTo(ImVec2(p1_screen[0], p1_screen[1])); + window->DrawList->PathLineTo(ImVec2(p2_screen[0], p2_screen[1])); + window->DrawList->PathLineTo(ImVec2(p3_screen[0], p3_screen[1])); + window->DrawList->PathLineTo(ImVec2(p4_screen[0], p4_screen[1])); + window->DrawList->PathLineTo(ImVec2(p1_screen[0], p1_screen[1])); + + if (mesh_only) + { + window->DrawList->PathStroke(color_, 0, thickness); + } + else + { + window->DrawList->PathFillConvex(color_); + } } - void draw_cube(float* origin, float width, float* color) + void draw_cube(float* origin, float width, float* color, float thickness, bool mesh_only) { const auto half = width / 2.f; @@ -206,44 +239,14 @@ namespace gui_debug float p3_top[3] = {p3[0], p3[1], origin[2] + width}; float p4_top[3] = {p4[0], p4[1], origin[2] + width}; - draw_square_from_points(p1, p2, p3, p4, color); - draw_square_from_points(p1_top, p2_top, p3_top, p4_top, color); + draw_square_from_points(p1, p2, p3, p4, color, thickness, mesh_only); + draw_square_from_points(p1_top, p2_top, p3_top, p4_top, color, thickness, mesh_only); - draw_square_from_points(p3, p2, p2_top, p3_top, color); - draw_square_from_points(p4, p1, p1_top, p4_top, color); + draw_square_from_points(p3, p2, p2_top, p3_top, color, thickness, mesh_only); + draw_square_from_points(p4, p1, p1_top, p4_top, color, thickness, mesh_only); - draw_square_from_points(p1, p2, p2_top, p1_top, color); - draw_square_from_points(p4, p3, p3_top, p4_top, color); - } - - void draw_cube_mesh(float* origin, float width, float* color, float thickness) - { - const auto half = width / 2.f; - - float p1[3] = {origin[0] - half, origin[1] + half, origin[2]}; - float p2[3] = {origin[0] + half, origin[1] + half, origin[2]}; - float p3[3] = {origin[0] + half, origin[1] - half, origin[2]}; - float p4[3] = {origin[0] - half, origin[1] - half, origin[2]}; - - float p1_top[3] = {p1[0], p1[1], origin[2] + width}; - float p2_top[3] = {p2[0], p2[1], origin[2] + width}; - float p3_top[3] = {p3[0], p3[1], origin[2] + width}; - float p4_top[3] = {p4[0], p4[1], origin[2] + width}; - - draw_line(p1, p2, color, thickness); - draw_line(p2, p3, color, thickness); - draw_line(p3, p4, color, thickness); - draw_line(p4, p1, color, thickness); - - draw_line(p1_top, p2_top, color, thickness); - draw_line(p2_top, p3_top, color, thickness); - draw_line(p3_top, p4_top, color, thickness); - draw_line(p4_top, p1_top, color, thickness); - - draw_line(p1, p1_top, color, thickness); - draw_line(p2, p2_top, color, thickness); - draw_line(p3, p3_top, color, thickness); - draw_line(p4, p4_top, color, thickness); + draw_square_from_points(p1, p2, p2_top, p1_top, color, thickness, mesh_only); + draw_square_from_points(p4, p3, p3_top, p4_top, color, thickness, mesh_only); } float get_pi() @@ -252,7 +255,8 @@ namespace gui_debug return pi; } - void draw_cylinder(float* center, float radius, float height, int point_count, float* color) + void draw_cylinder(float* center, float radius, float height, int point_count, float* color, + float thickness, bool mesh_only) { const auto pi = get_pi(); @@ -304,7 +308,15 @@ namespace gui_debug window->DrawList->PathLineTo(points_bottom[i].point); } - window->DrawList->PathFillConvex(color_); + + if (mesh_only) + { + window->DrawList->PathStroke(color_, 0, thickness); + } + else + { + window->DrawList->PathFillConvex(color_); + } window->DrawList->PathClear(); for (auto i = 0; i < point_count; i++) @@ -316,7 +328,15 @@ namespace gui_debug window->DrawList->PathLineTo(points_top[i].point); } - window->DrawList->PathFillConvex(color_); + + if (mesh_only) + { + window->DrawList->PathStroke(color_, 0, thickness); + } + else + { + window->DrawList->PathFillConvex(color_); + } for (auto i = 0; i < point_count; i++) { @@ -352,10 +372,43 @@ namespace gui_debug } window->DrawList->PathLineTo(points_top[i].point); - window->DrawList->PathFillConvex(color_); + + if (mesh_only) + { + window->DrawList->PathStroke(color_, 0, thickness); + } + else + { + window->DrawList->PathFillConvex(color_); + } } } + void draw_rectangular_prism(float* center, game::Bounds bounds, float* color, float thickness, bool mesh_only) + { + float vertices[8][3] = + { + {center[0] - bounds.halfSize[0], center[1] - bounds.halfSize[1], center[2] - bounds.halfSize[2]}, + {center[0] - bounds.halfSize[0], center[1] + bounds.halfSize[1], center[2] - bounds.halfSize[2]}, + {center[0] + bounds.halfSize[0], center[1] + bounds.halfSize[1], center[2] - bounds.halfSize[2]}, + {center[0] + bounds.halfSize[0], center[1] - bounds.halfSize[1], center[2] - bounds.halfSize[2]}, + + {center[0] - bounds.halfSize[0], center[1] - bounds.halfSize[1], center[2] + bounds.halfSize[2]}, + {center[0] - bounds.halfSize[0], center[1] + bounds.halfSize[1], center[2] + bounds.halfSize[2]}, + {center[0] + bounds.halfSize[0], center[1] + bounds.halfSize[1], center[2] + bounds.halfSize[2]}, + {center[0] + bounds.halfSize[0], center[1] - bounds.halfSize[1], center[2] + bounds.halfSize[2]}, + }; + + draw_square_from_points(vertices[0], vertices[1], vertices[2], vertices[3], color, thickness, mesh_only); + draw_square_from_points(vertices[4], vertices[5], vertices[6], vertices[7], color, thickness, mesh_only); + + draw_square_from_points(vertices[0], vertices[4], vertices[5], vertices[1], color, thickness, mesh_only); + draw_square_from_points(vertices[7], vertices[6], vertices[2], vertices[3], color, thickness, mesh_only); + + draw_square_from_points(vertices[6], vertices[5], vertices[1], vertices[2], color, thickness, mesh_only); + draw_square_from_points(vertices[7], vertices[4], vertices[0], vertices[3], color, thickness, mesh_only); + } + void draw_window() { if (!gui::enabled_menus["debug"]) @@ -403,20 +456,48 @@ namespace gui_debug ImGui::TreePop(); } - if (ImGui::TreeNode("Triggers")) + if (ImGui::TreeNode("Entity bounds")) { - ImGui::Checkbox("Draw", &trigger_settings.enabled); - ImGui::Checkbox("Lock camera", &trigger_settings.camera_locked); + ImGui::Checkbox("Draw", &entity_bound_settings.enabled); + ImGui::Checkbox("Lock camera", &entity_bound_settings.camera_locked); - ImGui::SliderFloat("range", &trigger_settings.range, 0.f, 10000.f); - ImGui::SliderInt("circle max points", &trigger_settings.point_count, 3, 360); - - if (ImGui::TreeNode("Color picker")) + if (ImGui::TreeNode("Types")) { - ImGui::ColorPicker4("color", trigger_settings.color); - ImGui::TreePop(); + ImGui::Checkbox("trigger_radius", &entity_bound_settings.enabled_types[entity_type::trigger_radius]); + if (entity_bound_settings.enabled_types[entity_type::trigger_radius] && ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", entity_bound_settings.type_colors[entity_type::trigger_radius]); + ImGui::TreePop(); + } + + ImGui::Checkbox("generic trigger", &entity_bound_settings.enabled_types[entity_type::generic_trigger]); + if (entity_bound_settings.enabled_types[entity_type::generic_trigger] && ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", entity_bound_settings.type_colors[entity_type::generic_trigger]); + ImGui::TreePop(); + } + + ImGui::Checkbox("actor", &entity_bound_settings.enabled_types[entity_type::actor]); + if (entity_bound_settings.enabled_types[entity_type::actor] && ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", entity_bound_settings.type_colors[entity_type::actor]); + ImGui::TreePop(); + } + + ImGui::Checkbox("other entities", &entity_bound_settings.enabled_types[entity_type::other]); + if (entity_bound_settings.enabled_types[entity_type::other] && ImGui::TreeNode("Color picker")) + { + ImGui::ColorPicker4("color", entity_bound_settings.type_colors[entity_type::other]); + ImGui::TreePop(); + } + } + ImGui::SliderFloat("range", &entity_bound_settings.range, 0.f, 10000.f); + ImGui::SliderFloat("mesh thickness", &entity_bound_settings.mesh_thickness, 1.f, 20.f); + ImGui::Checkbox("mesh only", &entity_bound_settings.mesh_only); + ImGui::SliderInt("circle max points", &entity_bound_settings.point_count, 3, 360); + ImGui::TreePop(); } @@ -500,12 +581,10 @@ namespace gui_debug case object_type::square: draw_square(origin, path_node_settings.size, path_node_settings.color); break; - case object_type::cube: - draw_cube(origin, path_node_settings.size, path_node_settings.color); - break; case object_type::cube_mesh: - draw_cube_mesh(origin, path_node_settings.size, path_node_settings.color, - path_node_settings.mesh_thickness); + case object_type::cube: + draw_cube(origin, path_node_settings.size, path_node_settings.color, + path_node_settings.mesh_thickness, path_node_settings.type == object_type::cube_mesh); break; } @@ -516,32 +595,68 @@ namespace gui_debug } } + entity_type get_entity_type(const char* classname) + { + if (strstr(classname, "trigger_radius")) + { + return entity_type::trigger_radius; + } + else if (strstr(classname, "trigger")) + { + return entity_type::generic_trigger; + } + else if (strstr(classname, "actor")) + { + return entity_type::actor; + } + + return entity_type::other; + } + void draw_triggers() { - if (!trigger_settings.enabled) + if (!entity_bound_settings.enabled) { return; } - const auto trigger_radius = game::SL_GetString("trigger_radius", 0); - - for (auto i = 0; i < 0xF9E; i++) + for (auto i = 0; i < *game::num_entities; i++) { const auto entity = &game::g_entities[i]; const auto origin = entity->origin; - const auto radius = entity->halfSize[0]; - const auto height = entity->halfSize[2] * 2.f; - const auto distance = distance_2d(trigger_settings.camera, origin); + const auto distance = distance_2d(entity_bound_settings.camera, origin); + const auto* classname = game::SL_ConvertToString(entity->script_classname); - if (distance - radius * 2 > trigger_settings.range || - entity->script_classname != trigger_radius) + if (distance > entity_bound_settings.range || !classname) { continue; } - draw_cylinder(origin, radius, height, trigger_settings.point_count, - trigger_settings.color); + const auto type = get_entity_type(classname); + if (!entity_bound_settings.enabled_types[type]) + { + continue; + } + + switch (type) + { + case entity_type::trigger_radius: + { + const auto radius = entity->box.halfSize[0]; + const auto height = entity->box.halfSize[2] * 2.f; + + draw_cylinder(origin, radius, height, entity_bound_settings.point_count, + entity_bound_settings.type_colors[type], entity_bound_settings.mesh_thickness, entity_bound_settings.mesh_only); + break; + } + default: + { + draw_rectangular_prism(origin, entity->box, entity_bound_settings.type_colors[type], + entity_bound_settings.mesh_thickness, entity_bound_settings.mesh_only); + break; + } + } } } @@ -570,11 +685,11 @@ namespace gui_debug path_node_settings.camera[2] = camera[2]; } - if (!trigger_settings.camera_locked) + if (!entity_bound_settings.camera_locked) { - trigger_settings.camera[0] = camera[0]; - trigger_settings.camera[1] = camera[1]; - trigger_settings.camera[2] = camera[2]; + entity_bound_settings.camera[0] = camera[0]; + entity_bound_settings.camera[1] = camera[1]; + entity_bound_settings.camera[2] = camera[2]; } } } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index 490266f5..291203a8 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -61,21 +61,28 @@ namespace game scr_string_t_dummy = 0x0, }; + struct Bounds + { + vec3_t midPoint; + vec3_t halfSize; + }; + struct gentity_s { EntityState s; char __pad0[0x1B]; vec3_t origin; char __pad1[0x98]; - float midPoint[0x3]; // entityShared.box - float halfSize[0x3]; // entityShared.box - char __pad2[0x40]; + Bounds box; + char __pad2[0x4]; + Bounds absBox; + char __pad3[0x24]; gclient_s* client; - char __pad3[0x30]; + char __pad4[0x30]; scr_string_t script_classname; - char __pad4[0x18]; + char __pad5[0x18]; char flags; - char __pad5[0x188]; + char __pad6[0x188]; }; // size = 760 //auto a = sizeof(gentity_s); @@ -973,12 +980,6 @@ namespace game const char* name; }; - struct Bounds - { - vec3_t midPoint; - vec3_t halfSize; - }; - struct pmove_t { }; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index e6b6e697..c7152fc0 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -153,6 +153,7 @@ namespace game WEAK symbol<int> g_poolSize{0xBF2E40}; WEAK symbol<gentity_s> g_entities{0x52DDDA0}; + WEAK symbol<int> num_entities{0x55CC738}; WEAK symbol<PathData> pathData{0x52CCDA0}; WEAK symbol<DWORD> threadIds{0xB11DC80};