mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2025-01-03 16:13:36 +08:00
Custom teleport sub tab (#1652)
This commit is contained in:
parent
3dd9be8a95
commit
27e66b9394
@ -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)
|
||||
{
|
||||
|
114
src/services/custom_teleport/custom_teleport_service.cpp
Normal file
114
src/services/custom_teleport/custom_teleport_service.cpp
Normal file
@ -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<telelocation> custom_teleport_service::saved_locations_filtered_list(std::string filter)
|
||||
{
|
||||
std::vector<telelocation> 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<std::map<std::string, std::vector<telelocation>>>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
29
src/services/custom_teleport/custom_teleport_service.hpp
Normal file
29
src/services/custom_teleport/custom_teleport_service.hpp
Normal file
@ -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<std::string, std::vector<telelocation>> 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<telelocation> saved_locations_filtered_list(std::string filter = "");
|
||||
|
||||
private:
|
||||
std::filesystem::path get_telelocations_file_path();
|
||||
};
|
||||
|
||||
inline custom_teleport_service g_custom_teleport_service;
|
||||
}
|
@ -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{};
|
||||
}
|
||||
}
|
@ -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<std::string, std::vector<telelocation>> 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<std::map<std::string, std::vector<telelocation>>>();
|
||||
|
||||
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;
|
||||
|
156
src/views/self/view_custom_teleport.cpp
Normal file
156
src/views/self/view_custom_teleport.cpp
Normal file
@ -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<float>(*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<float>(*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<telelocation> 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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user