From ee61858489195f72a26774a61c25d5a75eda9f09 Mon Sep 17 00:00:00 2001 From: DayibBaba <79384354+DayibBaba@users.noreply.github.com> Date: Sun, 9 Jul 2023 23:03:05 +0200 Subject: [PATCH] Custom teleport sub tab (#1652) --- src/backend/backend.cpp | 8 +- .../custom_teleport_service.cpp | 114 +++++++++++++ .../custom_teleport_service.hpp | 29 ++++ src/services/gui/gui_service.hpp | 8 +- src/util/teleport.hpp | 91 ---------- src/views/self/view_custom_teleport.cpp | 156 ++++++++++++++++++ src/views/self/view_teleport.cpp | 86 ---------- src/views/view.hpp | 1 + 8 files changed, 310 insertions(+), 183 deletions(-) create mode 100644 src/services/custom_teleport/custom_teleport_service.cpp create mode 100644 src/services/custom_teleport/custom_teleport_service.hpp create mode 100644 src/views/self/view_custom_teleport.cpp diff --git a/src/backend/backend.cpp b/src/backend/backend.cpp index a62a10bf..700ee704 100644 --- a/src/backend/backend.cpp +++ b/src/backend/backend.cpp @@ -5,15 +5,14 @@ #include "script.hpp" #include "script_patches.hpp" #include "services/context_menu/context_menu_service.hpp" +#include "services/custom_teleport/custom_teleport_service.hpp" #include "services/orbital_drone/orbital_drone.hpp" #include "services/script_connection/script_connection_service.hpp" #include "services/squad_spawner/squad_spawner.hpp" #include "services/tunables/tunables_service.hpp" #include "services/vehicle/vehicle_control_service.hpp" -#include "thread_pool.hpp" -#include "util/teleport.hpp" -#include "services/squad_spawner/squad_spawner.hpp" #include "services/vehicle/xml_vehicles_service.hpp" +#include "thread_pool.hpp" namespace big @@ -24,9 +23,10 @@ namespace big command->refresh(); register_script_patches(); - teleport::fetch_saved_locations(); + g_squad_spawner_service.fetch_squads(); g_xml_vehicles_service->fetch_xml_files(); + g_custom_teleport_service.fetch_saved_locations(); while (g_running) { diff --git a/src/services/custom_teleport/custom_teleport_service.cpp b/src/services/custom_teleport/custom_teleport_service.cpp new file mode 100644 index 00000000..179468c3 --- /dev/null +++ b/src/services/custom_teleport/custom_teleport_service.cpp @@ -0,0 +1,114 @@ +#include "custom_teleport_service.hpp" + +#include "util/notify.hpp" + +namespace big +{ + std::filesystem::path custom_teleport_service::get_telelocations_file_path() + { + return g_file_manager.get_project_file("telelocations.json").get_path(); + } + + std::vector custom_teleport_service::saved_locations_filtered_list(std::string filter) + { + std::vector filterlist{}; + + static auto to_lower = [=](std::string text) -> std::string { + std::transform(text.begin(), text.end(), text.begin(), ::tolower); + return text; + }; + + for (auto& location : all_saved_locations | std::views::values | std::views::join) + if (to_lower(location.name).find(to_lower(filter)) != std::string::npos) + filterlist.push_back(location); + + return filterlist; + } + + bool custom_teleport_service::fetch_saved_locations() + { + all_saved_locations.clear(); + + auto path = get_telelocations_file_path(); + std::ifstream file(path, std::ios::binary); + + try + { + if (!file.is_open()) + return false; + + nlohmann::json j; + file >> j; + all_saved_locations = j.get>>(); + + return true; + } + catch (const std::exception& e) + { + LOG(WARNING) << "Failed fetching saved locations: " << e.what() << '\n'; + return false; + } + + return false; + } + + bool custom_teleport_service::save_new_location(const std::string& category, telelocation t) + { + const auto& pair = all_saved_locations.insert({category, {t}}); + if (!pair.second) + { + pair.first->second.push_back(t); + } + + auto path = get_telelocations_file_path(); + + std::ofstream file_out(path, std::ofstream::trunc | std::ofstream::binary); + if (!file_out.is_open()) + return false; + + nlohmann::json j = all_saved_locations; + file_out << j.dump(4); + file_out.close(); + + g_notification_service->push_success("Custom Teleport", std::format("Succesfully saved location {}", t.name)); + + return true; + } + + bool custom_teleport_service::delete_saved_location(const std::string& category, const std::string& location_name) + { + auto path = get_telelocations_file_path(); + + const auto& it = all_saved_locations.find(category); + if (it == all_saved_locations.end()) + return false; + + std::erase_if(it->second, [location_name](telelocation t) { + return t.name == location_name; + }); + + if (!it->second.size()) + { + all_saved_locations.erase(category); + } + + std::ofstream file_out(path, std::ofstream::trunc | std::ofstream::binary); + if (!file_out.is_open()) + return false; + + nlohmann::json j = all_saved_locations; + file_out << j.dump(4); + file_out.close(); + + return true; + } + + telelocation* custom_teleport_service::get_saved_location_by_name(std::string name) + { + for (auto& loc : g_custom_teleport_service.saved_locations_filtered_list()) + if (loc.name == name) + return &loc; + + return nullptr; + } +} diff --git a/src/services/custom_teleport/custom_teleport_service.hpp b/src/services/custom_teleport/custom_teleport_service.hpp new file mode 100644 index 00000000..9b3258cd --- /dev/null +++ b/src/services/custom_teleport/custom_teleport_service.hpp @@ -0,0 +1,29 @@ +#include "file_manager.hpp" +#include "util/teleport.hpp" + +namespace big +{ + struct telelocation + { + std::string name; + float x, y, z; + }; + + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(telelocation, name, x, y, z); + + class custom_teleport_service + { + public: + std::map> all_saved_locations; + bool fetch_saved_locations(); + bool save_new_location(const std::string& category, telelocation t); + bool delete_saved_location(const std::string& category, const std::string& location_name); + telelocation* get_saved_location_by_name(std::string); + std::vector saved_locations_filtered_list(std::string filter = ""); + + private: + std::filesystem::path get_telelocations_file_path(); + }; + + inline custom_teleport_service g_custom_teleport_service; +} \ No newline at end of file diff --git a/src/services/gui/gui_service.hpp b/src/services/gui/gui_service.hpp index 2b59ff82..7e203019 100644 --- a/src/services/gui/gui_service.hpp +++ b/src/services/gui/gui_service.hpp @@ -11,6 +11,7 @@ namespace big SELF, WEAPONS, TELEPORT, + CUSTOM_TELEPORT, MOBILE, OUTFIT_EDITOR, OUTFIT_SLOTS, @@ -86,7 +87,10 @@ namespace big { {TAB_DECL(WEAPONS), view::weapons}}, {TAB_DECL(MOBILE), view::mobile}}, - {TAB_DECL(TELEPORT), view::teleport}}, + {TAB_DECL(TELEPORT), view::teleport, + { + {TAB_DECL(CUSTOM_TELEPORT), view::custom_teleport}}, + }}}, {TAB_DECL(OUTFIT_EDITOR), view::outfit_editor}}, {TAB_DECL(OUTFIT_SLOTS), view::outfit_slots}}, }, @@ -178,4 +182,4 @@ namespace big }; inline gui_service* g_gui_service{}; -} +} \ No newline at end of file diff --git a/src/util/teleport.hpp b/src/util/teleport.hpp index 54d04ba9..e8dcebc3 100644 --- a/src/util/teleport.hpp +++ b/src/util/teleport.hpp @@ -8,97 +8,6 @@ namespace big::teleport { - struct telelocation - { - std::string name; - float x, y, z; - }; - - NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(telelocation, name, x, y, z); - - inline std::map> all_saved_locations; - - inline std::filesystem::path get_telelocations_file_path() - { - return g_file_manager.get_project_file("telelocations.json").get_path(); - } - - inline bool fetch_saved_locations() - { - all_saved_locations.clear(); - - auto path = get_telelocations_file_path(); - std::ifstream file(path, std::ios::binary); - - try - { - if (!file.is_open()) - return false; - - nlohmann::json j; - file >> j; - all_saved_locations = j.get>>(); - - return true; - } - catch (const std::exception& e) - { - LOG(WARNING) << "Failed fetching saved locations: " << e.what() << '\n'; - return false; - } - - return false; - } - - inline bool save_new_location(const std::string& category, telelocation t) - { - const auto& pair = all_saved_locations.insert({category, {t}}); - if (!pair.second) - { - pair.first->second.push_back(t); - } - - auto path = get_telelocations_file_path(); - - std::ofstream file_out(path, std::ofstream::trunc | std::ofstream::binary); - if (!file_out.is_open()) - return false; - - nlohmann::json j = all_saved_locations; - file_out << j.dump(4); - file_out.close(); - - return true; - } - - inline bool delete_saved_location(const std::string& category, const std::string& location_name) - { - auto path = get_telelocations_file_path(); - - const auto& it = all_saved_locations.find(category); - if (it == all_saved_locations.end()) - return false; - - std::erase_if(it->second, [location_name](telelocation t) { - return t.name == location_name; - }); - - if (!it->second.size()) - { - all_saved_locations.erase(category); - } - - std::ofstream file_out(path, std::ofstream::trunc | std::ofstream::binary); - if (!file_out.is_open()) - return false; - - nlohmann::json j = all_saved_locations; - file_out << j.dump(4); - file_out.close(); - - return true; - } - inline bool teleport_player_to_coords(player_ptr player, Vector3 coords) { Entity ent; diff --git a/src/views/self/view_custom_teleport.cpp b/src/views/self/view_custom_teleport.cpp new file mode 100644 index 00000000..a86e9d69 --- /dev/null +++ b/src/views/self/view_custom_teleport.cpp @@ -0,0 +1,156 @@ +#include "services/custom_teleport/custom_teleport_service.hpp" +#include "util/math.hpp" +#include "util/teleport.hpp" +#include "views/view.hpp" + +namespace big +{ + telelocation get_location_player_is_closest_to() + { + if (!g_local_player || !g_local_player->m_navigation || g_custom_teleport_service.all_saved_locations.empty()) + return {}; + + Vector3 transformed_vector = Vector3(g_local_player->m_navigation->get_position()->x, + g_local_player->m_navigation->get_position()->y, + g_local_player->m_navigation->get_position()->z); + + float distance = 500; + telelocation closest_location{}; + //saved_locations_filtered_list can be used to get a joint list of all categories when the filter is empty. + for (auto& loc : g_custom_teleport_service.saved_locations_filtered_list()) + { + float new_distance = math::distance_between_vectors(transformed_vector, {loc.x, loc.y, loc.z}); + + if (new_distance < distance) + closest_location = loc, distance = new_distance; + } + + return closest_location; + } + + float get_distance_to_telelocation(telelocation t) + { + return math::distance_between_vectors(Vector3(t.x,t.y,t.z), Vector3(g_local_player->m_navigation->get_position()->x, + g_local_player->m_navigation->get_position()->y, + g_local_player->m_navigation->get_position()->z)); + } + + void view::custom_teleport() + { + ImGui::BeginGroup(); + static std::string new_location_name; + static std::string category = "Default"; + static telelocation deletion_telelocation; + static std::string filter{}; + + if (!std::string(deletion_telelocation.name).empty()) + ImGui::OpenPopup("##deletelocation"); + + if (ImGui::BeginPopupModal("##deletelocation", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) + { + ImGui::Text("Are you sure you want to delete %s?", deletion_telelocation.name); + + ImGui::Spacing(); + + if (ImGui::Button("Yes")) + { + g_custom_teleport_service.delete_saved_location(category, deletion_telelocation.name); + deletion_telelocation.name = ""; + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("No")) + { + deletion_telelocation.name = ""; + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + + ImGui::PushItemWidth(300); + components::input_text_with_hint("Category", "Category", &category); + components::input_text_with_hint("Location name", "New location", &new_location_name); + ImGui::PopItemWidth(); + + components::button("Save current location", [] { + if (g_custom_teleport_service.get_saved_location_by_name(new_location_name)) + g_notification_service->push_warning("Custom Teleport", std::format("Location with the name {} already exists", new_location_name)); + else + g_custom_teleport_service.save_new_location(category, + {new_location_name, self::pos.x, self::pos.y, self::pos.z}); + }); + + ImGui::Separator(); + + components::small_text("Double click to teleport\nShift click to delete"); + + ImGui::Spacing(); + components::input_text_with_hint("##filter", "Search", &filter); + + ImGui::BeginGroup(); + components::small_text("Categories"); + if (ImGui::BeginListBox("##categories", {250, static_cast(*g_pointers->m_gta.m_resolution_y * 0.5)})) + { + for (auto& l : g_custom_teleport_service.all_saved_locations | std::ranges::views::keys) + { + if (ImGui::Selectable(l.data(), l == category)) + { + category = l; + } + } + ImGui::EndListBox(); + } + ImGui::EndGroup(); + ImGui::SameLine(); + ImGui::BeginGroup(); + components::small_text("Locations"); + if (ImGui::BeginListBox("##telelocations", {250, static_cast(*g_pointers->m_gta.m_resolution_y * 0.5)})) + { + if (g_custom_teleport_service.all_saved_locations.find(category) + != g_custom_teleport_service.all_saved_locations.end()) + { + std::vector current_list{}; + + if (!filter.empty()) + current_list = g_custom_teleport_service.saved_locations_filtered_list(filter); + else + current_list = g_custom_teleport_service.all_saved_locations.at(category); + + for (const auto& l : current_list) + { + if (ImGui::Selectable(l.name.data(), l.name == get_location_player_is_closest_to().name, ImGuiSelectableFlags_AllowDoubleClick)) + { + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + { + deletion_telelocation = l; + } + else + { + if (ImGui::IsMouseDoubleClicked(0)) + { + g_fiber_pool->queue_job([l] { + teleport::teleport_player_to_coords(g_player_service->get_self(), {l.x, l.y, l.z}); + }); + } + } + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + if (l.name.length() > 27) + ImGui::Text(l.name.data()); + ImGui::Text("Distance: %f", get_distance_to_telelocation(l)); + ImGui::EndTooltip(); + } + } + } + + ImGui::EndListBox(); + } + + ImGui::EndGroup(); + + ImGui::EndGroup(); + } +} diff --git a/src/views/self/view_teleport.cpp b/src/views/self/view_teleport.cpp index da271b01..f77c7bb7 100644 --- a/src/views/self/view_teleport.cpp +++ b/src/views/self/view_teleport.cpp @@ -141,91 +141,5 @@ namespace big ImGui::Text(std::vformat("IPL_POSITION"_T, std::make_format_args(selected_ipl.location.x, selected_ipl.location.y, selected_ipl.location.z)) .data()); - - ImGui::SeparatorText("Custom Locations"); - - ImGui::BeginGroup(); - static std::string new_location_name; - static std::string category = "Default"; - static teleport::telelocation deletion_telelocation; - - if (!std::string(deletion_telelocation.name).empty()) - ImGui::OpenPopup("##deletelocation"); - - if (ImGui::BeginPopupModal("##deletelocation")) - { - ImGui::Text("Are you sure you want to delete %s?", deletion_telelocation.name); - - if (ImGui::Button("Yes")) - { - teleport::delete_saved_location(category, deletion_telelocation.name); - deletion_telelocation.name = ""; - ImGui::CloseCurrentPopup(); - } - ImGui::SameLine(); - if (ImGui::Button("No")) - { - deletion_telelocation.name = ""; - ImGui::CloseCurrentPopup(); - } - - ImGui::EndPopup(); - } - - ImGui::PushItemWidth(300); - components::input_text_with_hint("Category", "Category", &category); - components::input_text_with_hint("Location name", "New location", &new_location_name); - ImGui::PopItemWidth(); - - components::button("Save current location", [] { - teleport::save_new_location(category, {new_location_name, self::pos.x, self::pos.y, self::pos.z}); - }); - - ImGui::BeginGroup(); - components::small_text("Categories"); - if (ImGui::BeginListBox("##categories", ImVec2(250, 150))) - { - for (auto& l : teleport::all_saved_locations | std::ranges::views::keys) - { - if (ImGui::Selectable(l.data(), l == category)) - { - category = l; - } - } - ImGui::EndListBox(); - } - ImGui::EndGroup(); - ImGui::SameLine(); - ImGui::BeginGroup(); - components::small_text("Locations"); - if (ImGui::BeginListBox("##telelocations", ImVec2(250, 150))) - { - if (teleport::all_saved_locations.find(category) != teleport::all_saved_locations.end()) - { - for (const auto& l : teleport::all_saved_locations.at(category)) - { - if (ImGui::Selectable(l.name.data())) - { - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - { - deletion_telelocation = l; - } - else - g_fiber_pool->queue_job([l] { - teleport::teleport_player_to_coords(g_player_service->get_self(), {l.x, l.y, l.z}); - }); - } - } - } - - ImGui::EndListBox(); - } - - if (ImGui::IsItemHovered()) - ImGui::SetTooltip("Shift click to delete"); - - ImGui::EndGroup(); - - ImGui::EndGroup(); } } diff --git a/src/views/view.hpp b/src/views/view.hpp index e34d672e..93ddcc1a 100644 --- a/src/views/view.hpp +++ b/src/views/view.hpp @@ -58,6 +58,7 @@ namespace big static void time_and_weather(); static void spoofing(); static void teleport(); + static void custom_teleport(); static void view_player(); static void players(); static void weapons();