From 9c9164bfef4975ddab1b71b72de48d79ab396cc0 Mon Sep 17 00:00:00 2001 From: Aure7138 <100095051+Aure7138@users.noreply.github.com> Date: Tue, 21 Feb 2023 06:20:40 +0800 Subject: [PATCH] feat(world): model swapper (#1003) --- src/core/globals.hpp | 10 +- src/hooking.cpp | 2 + src/hooking.hpp | 2 + src/hooks/misc/get_model_info.cpp | 37 +++++++ src/pointers.cpp | 6 ++ src/pointers.hpp | 4 +- .../context_menu/context_menu_service.hpp | 4 + src/services/gui/gui_service.hpp | 2 + src/util/model_info.hpp | 1 + src/views/view.hpp | 1 + src/views/world/model_swapper.cpp | 101 ++++++++++++++++++ 11 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 src/hooks/misc/get_model_info.cpp create mode 100644 src/views/world/model_swapper.cpp diff --git a/src/core/globals.hpp b/src/core/globals.hpp index dce4d544..e0e639e5 100644 --- a/src/core/globals.hpp +++ b/src/core/globals.hpp @@ -472,7 +472,15 @@ namespace big NLOHMANN_DEFINE_TYPE_INTRUSIVE(blackhole, enable, include_peds, include_vehicles, color, alpha) } blackhole{}; - NLOHMANN_DEFINE_TYPE_INTRUSIVE(world, water, spawn_ped, custom_time, blackhole) + struct model_swapper + { + std::vector> models; + std::mutex m; + bool update = false; + NLOHMANN_DEFINE_TYPE_INTRUSIVE(model_swapper, models) + } model_swapper{}; + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(world, water, spawn_ped, custom_time, blackhole, model_swapper) } world{}; struct spoofing diff --git a/src/hooking.cpp b/src/hooking.cpp index 277b7e3d..5b736667 100644 --- a/src/hooking.cpp +++ b/src/hooking.cpp @@ -104,6 +104,8 @@ namespace big detour_hook_helper::add("WPCDN", g_pointers->m_write_player_camera_data_node); + detour_hook_helper::add("GMI", g_pointers->m_get_model_info); + g_hooking = this; } diff --git a/src/hooking.hpp b/src/hooking.hpp index a699b09f..a91d5938 100644 --- a/src/hooking.hpp +++ b/src/hooking.hpp @@ -150,6 +150,8 @@ namespace big static bool receive_pickup(rage::netObject* netobject, void* unk, CPed* ped); static bool write_player_camera_data_node(rage::netObject* player, CPlayerCameraDataNode* node); + + static CBaseModelInfo* get_model_info(rage::joaat_t hash, uint32_t* a2); }; class minhook_keepalive diff --git a/src/hooks/misc/get_model_info.cpp b/src/hooks/misc/get_model_info.cpp new file mode 100644 index 00000000..b190fdc9 --- /dev/null +++ b/src/hooks/misc/get_model_info.cpp @@ -0,0 +1,37 @@ +#include "hooking.hpp" +#include "util/model_info.hpp" + +namespace big +{ + static auto get_hash(const std::string& str) + { + rage::joaat_t hash = 0; + if (str.substr(0, 2) == "0x") + std::stringstream(str.substr(2)) >> std::hex >> hash; + else + hash = rage::joaat(str.c_str()); + return hash; + } + + static std::vector> cache_models; + + static void update() + { + std::lock_guard lock(g.world.model_swapper.m); + cache_models.clear(); + for (size_t i = 0; i < g.world.model_swapper.models.size(); i++) + cache_models.push_back(std::make_pair(get_hash(g.world.model_swapper.models[i].first), get_hash(g.world.model_swapper.models[i].second))); + g.world.model_swapper.update = false; + } + + CBaseModelInfo* hooks::get_model_info(rage::joaat_t hash, uint32_t* a2) + { + static bool init = ([] { update(); }(), true); + if (g.world.model_swapper.update) + update(); + for (size_t i = 0; i < cache_models.size(); i++) + if (cache_models[i].first == hash) + return g_hooking->get_original()(cache_models[i].second, a2); + return g_hooking->get_original()(hash, a2); + } +} diff --git a/src/pointers.cpp b/src/pointers.cpp index 74f297fb..8192a76d 100644 --- a/src/pointers.cpp +++ b/src/pointers.cpp @@ -337,6 +337,12 @@ namespace big m_model_table = ptr.add(3).rip().as*>(); }); + // Get Model Info + main_batch.add("GMI", "41 3B 0A 74 54", [this](memory::handle ptr) + { + m_get_model_info = ptr.sub(46).as(); + }); + // Get Label Text main_batch.add("GLT", "75 ? E8 ? ? ? ? 8B 0D ? ? ? ? 65 48 8B 04 25 ? ? ? ? BA ? ? ? ? 48 8B 04 C8 8B 0C 02 D1 E9", [this](memory::handle ptr) { diff --git a/src/pointers.hpp b/src/pointers.hpp index 7cc6b76c..e0ce455e 100644 --- a/src/pointers.hpp +++ b/src/pointers.hpp @@ -79,6 +79,7 @@ namespace big functions::get_screen_coords_for_world_coords m_get_screen_coords_for_world_coords{}; HashTable* m_model_table; + PVOID m_get_model_info; PVOID m_gta_thread_start{}; PVOID m_gta_thread_kill{}; @@ -88,8 +89,6 @@ namespace big functions::get_gameplay_cam_coords m_get_gameplay_cam_coords; - functions::give_pickup_rewards m_give_pickup_rewards{}; - PVOID m_write_player_gamer_data_node{}; functions::trigger_script_event m_trigger_script_event{}; @@ -187,6 +186,7 @@ namespace big PVOID m_serialize_join_request_message; + functions::give_pickup_rewards m_give_pickup_rewards{}; functions::send_network_damage m_send_network_damage; functions::request_ragdoll m_request_ragdoll; functions::request_control m_request_control; diff --git a/src/services/context_menu/context_menu_service.hpp b/src/services/context_menu/context_menu_service.hpp index 36cb6dbd..e2e989c1 100644 --- a/src/services/context_menu/context_menu_service.hpp +++ b/src/services/context_menu/context_menu_service.hpp @@ -103,6 +103,10 @@ namespace big rage::fvector3 pos = *m_pointer->m_navigation->get_position(); teleport::to_coords({ pos.x, pos.y, pos.z }); }}, + {"COPY HASH", [this] { + ImGui::SetClipboardText(std::format("0x{:08X}", (rage::joaat_t)m_pointer->m_model_info->m_hash).c_str()); + g_notification_service->push("Context Menu", std::format("Copy hash 0x{:08X}", (rage::joaat_t)m_pointer->m_model_info->m_hash).c_str()); + }} } }; diff --git a/src/services/gui/gui_service.hpp b/src/services/gui/gui_service.hpp index cc7837d7..458293cb 100644 --- a/src/services/gui/gui_service.hpp +++ b/src/services/gui/gui_service.hpp @@ -30,6 +30,7 @@ namespace big TRAIN, WATER, BLACKHOLE, + MODEL_SWAPPER, NETWORK, SESSION, @@ -88,6 +89,7 @@ namespace big { tabs::TRAIN, { "Train", view::train }}, { tabs::WATER, { "Water", view::water }}, { tabs::BLACKHOLE, { "Blackhole", view::blackhole }}, + { tabs::MODEL_SWAPPER, { "Model Swapper", view::model_swapper }}, }}}, {tabs::NETWORK, { "Network", nullptr, { { tabs::SPOOFING, { "Spoofing", view::spoofing }}, diff --git a/src/util/model_info.hpp b/src/util/model_info.hpp index eca09377..e7742bf0 100644 --- a/src/util/model_info.hpp +++ b/src/util/model_info.hpp @@ -1,6 +1,7 @@ #pragma once #include "gta/joaat.hpp" #include "pointers.hpp" +#include "vehicle/CVehicleModelInfo.hpp" namespace big { diff --git a/src/views/view.hpp b/src/views/view.hpp index 281888fc..e20e4d6e 100644 --- a/src/views/view.hpp +++ b/src/views/view.hpp @@ -55,6 +55,7 @@ namespace big static void train(); static void water(); static void blackhole(); + static void model_swapper(); static void player_info(); static void player_troll(); diff --git a/src/views/world/model_swapper.cpp b/src/views/world/model_swapper.cpp new file mode 100644 index 00000000..a24b41fc --- /dev/null +++ b/src/views/world/model_swapper.cpp @@ -0,0 +1,101 @@ +#include "views/view.hpp" +#include "pointers.hpp" + +namespace big +{ + void view::model_swapper() + { + ImGui::Text("Models that have already been created will not be affected much"); + ImGui::Text("Prefix 0x for hexadecimal hash"); + ImGui::Text("Use context menu to copy entity hash"); + + static char dst_text[256]; + static char src_text[256]; + static size_t selected_index = -1; + static float width = *g_pointers->m_resolution_x / 5.0; + + ImGui::SetNextItemWidth(width); + ImGui::InputText("Dst", dst_text, IM_ARRAYSIZE(dst_text)); ImGui::SameLine(); + ImGui::SetNextItemWidth(width); + ImGui::InputText("Src", src_text, IM_ARRAYSIZE(src_text)); ImGui::SameLine(); + + if (ImGui::Button("Add/Change")) + { + std::lock_guard lock(g.world.model_swapper.m); + if (dst_text[0] == '\0' || src_text[0] == '\0') + { + g_notification_service->push_error("Model Swapper", "Wrong input"); + return; + } + std::string str = dst_text; + transform(str.begin(), str.end(), str.begin(), ::tolower); + size_t i = 0; + for (; i < g.world.model_swapper.models.size(); i++) + { + std::string tmp = g.world.model_swapper.models[i].first; + transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower); + if (str == tmp) + { + g.world.model_swapper.models[i].first = dst_text; + g.world.model_swapper.models[i].second = src_text; + break; + } + } + if (i == g.world.model_swapper.models.size()) + g.world.model_swapper.models.push_back(std::make_pair(dst_text, src_text)); + g.world.model_swapper.update = true; + } ImGui::SameLine(); + if (ImGui::Button("Delete")) + { + std::lock_guard lock(g.world.model_swapper.m); + if (!g.world.model_swapper.models.size() || selected_index < 0 || selected_index >= g.world.model_swapper.models.size()) + { + g_notification_service->push_error("Model Swapper", "Invalid index"); + return; + } + g.world.model_swapper.models.erase(std::begin(g.world.model_swapper.models) + selected_index); + g.world.model_swapper.update = true; + } ImGui::SameLine(); + if (ImGui::Button("Clear")) + { + std::lock_guard lock(g.world.model_swapper.m); + g.world.model_swapper.models.clear(); + g.world.model_swapper.update = true; + } + + ImGui::SetNextItemWidth(width); + if (ImGui::BeginListBox("Dst##model_swapper_dst")) + { + for (size_t i = 0; i < g.world.model_swapper.models.size(); i++) + { + if (ImGui::Selectable(g.world.model_swapper.models[i].first.c_str(), selected_index == i)) + { + selected_index = i; + strcpy_s(dst_text, sizeof(dst_text), g.world.model_swapper.models[i].first.c_str()); + strcpy_s(src_text, sizeof(src_text), g.world.model_swapper.models[i].second.c_str()); + } + + if (selected_index == i) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } ImGui::SameLine(); + ImGui::SetNextItemWidth(width); + if (ImGui::BeginListBox("Src##model_swapper_src")) + { + for (size_t i = 0; i < g.world.model_swapper.models.size(); i++) + { + if (ImGui::Selectable(g.world.model_swapper.models[i].second.c_str(), selected_index == i)) + { + selected_index = i; + strcpy_s(dst_text, sizeof(dst_text), g.world.model_swapper.models[i].first.c_str()); + strcpy_s(src_text, sizeof(src_text), g.world.model_swapper.models[i].second.c_str()); + } + + if (selected_index == i) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + } +} \ No newline at end of file