From 2d9021f0b89591906d977e2d78c4bfebac5b1298 Mon Sep 17 00:00:00 2001 From: aa15032261 Date: Sun, 10 Jul 2022 06:33:14 +0800 Subject: [PATCH] feat(Personal Vehicle): Added clone personal vehicle feature. (#326) --- .../backend/looped/weapons/vehicle_gun.cpp | 2 +- BigBaseV2/src/core/enums.hpp | 54 +++++ BigBaseV2/src/core/globals.hpp | 61 ++++- BigBaseV2/src/services/gui/gui_service.hpp | 2 + .../src/services/mobile/mobile_service.cpp | 28 ++- .../src/services/mobile/mobile_service.hpp | 11 +- .../vehicle_preview_service.cpp | 188 ++++++++++----- .../vehicle_preview_service.hpp | 24 +- BigBaseV2/src/util/math.hpp | 4 +- BigBaseV2/src/util/mobile.hpp | 8 +- BigBaseV2/src/util/vehicle.hpp | 216 ++++++++++++++---- BigBaseV2/src/views/self/view_mobile.cpp | 73 +----- BigBaseV2/src/views/self/view_self.cpp | 40 ++-- BigBaseV2/src/views/vehicle/view_pv.cpp | 151 ++++++++++++ BigBaseV2/src/views/vehicle/view_spawn.cpp | 100 ++++---- BigBaseV2/src/views/view.hpp | 1 + 16 files changed, 715 insertions(+), 248 deletions(-) create mode 100644 BigBaseV2/src/views/vehicle/view_pv.cpp diff --git a/BigBaseV2/src/backend/looped/weapons/vehicle_gun.cpp b/BigBaseV2/src/backend/looped/weapons/vehicle_gun.cpp index 9e65f988..3db92de0 100644 --- a/BigBaseV2/src/backend/looped/weapons/vehicle_gun.cpp +++ b/BigBaseV2/src/backend/looped/weapons/vehicle_gun.cpp @@ -35,7 +35,7 @@ namespace big location.y += dist * sin(yaw) * cos(pitch); location.z += dist * sin(pitch); Vehicle veh = vehicle::spawn( - (const char*)g->weapons.vehicle_gun_model, + rage::joaat((const char*)g->weapons.vehicle_gun_model), location, ENTITY::GET_ENTITY_HEADING(self::ped) ); diff --git a/BigBaseV2/src/core/enums.hpp b/BigBaseV2/src/core/enums.hpp index 6611d8c4..973c64cf 100644 --- a/BigBaseV2/src/core/enums.hpp +++ b/BigBaseV2/src/core/enums.hpp @@ -119,6 +119,60 @@ namespace big UNK2 = 1 << 16 }; + enum eVehicleModType + { + VMT_SPOILER = 0, + VMT_BUMPER_F = 1, + VMT_BUMPER_R = 2, + VMT_SKIRT = 3, + VMT_EXHAUST = 4, + VMT_CHASSIS = 5, + VMT_GRILL = 6, + VMT_BONNET = 7, + VMT_WING_L = 8, + VMT_WING_R = 9, + VMT_ROOF = 10, + VMT_ENGINE = 11, + VMT_BRAKES = 12, + VMT_GEARBOX = 13, + VMT_HORN = 14, + VMT_SUSPENSION = 15, + VMT_ARMOUR = 16, + VMT_NITROUS = 17, + VMT_TURBO = 18, + VMT_SUBWOOFER = 19, + VMT_TYRE_SMOKE = 20, + VMT_HYDRAULICS = 21, + VMT_XENON_LIGHTS = 22, + VMT_WHEELS = 23, + VMT_WHEELS_REAR_OR_HYDRAULICS = 24, + VMT_PLTHOLDER = 25, + VMT_PLTVANITY = 26, + VMT_INTERIOR1 = 27, + VMT_INTERIOR2 = 28, + VMT_INTERIOR3 = 29, + VMT_INTERIOR4 = 30, + VMT_INTERIOR5 = 31, + VMT_SEATS = 32, + VMT_STEERING = 33, + VMT_KNOB = 34, + VMT_PLAQUE = 35, + VMT_ICE = 36, + VMT_TRUNK = 37, + VMT_HYDRO = 38, + VMT_ENGINEBAY1 = 39, + VMT_ENGINEBAY2 = 40, + VMT_ENGINEBAY3 = 41, + VMT_CHASSIS2 = 42, + VMT_CHASSIS3 = 43, + VMT_CHASSIS4 = 44, + VMT_CHASSIS5 = 45, + VMT_DOOR_L = 46, + VMT_DOOR_R = 47, + VMT_LIVERY_MOD = 48, + VMT_LIGHTBAR = 49 + }; + enum class ePedTask { TASK_NONE, diff --git a/BigBaseV2/src/core/globals.hpp b/BigBaseV2/src/core/globals.hpp index a74b8965..b59a3de3 100644 --- a/BigBaseV2/src/core/globals.hpp +++ b/BigBaseV2/src/core/globals.hpp @@ -181,6 +181,17 @@ namespace big bool preview_vehicle = false; bool spawn_inside = false; bool spawn_maxed = false; + std::string plate = ""; + }; + + struct clone_pv + { + bool preview_vehicle = false; + bool spawn_inside = false; + bool spawn_clone = false; + bool spawn_maxed = false; + bool clone_plate = false; + std::string plate = ""; }; struct spoofing @@ -228,8 +239,7 @@ namespace big bool vehicle_jump = false; bool instant_brake = false; bool is_targetable = true; - bool ls_customs = false; // don't save this to disk - bool pv_teleport_into = false; + bool ls_customs = false; // don't save this to dis bool seatbelt = false; bool turn_signals = false; int auto_drive_speed = 1; @@ -330,6 +340,7 @@ namespace big session session{}; settings settings{}; spawn spawn{}; + clone_pv clone_pv{}; spoofing spoofing{}; vehicle vehicle{}; weapons weapons{}; @@ -490,12 +501,29 @@ namespace big this->self.no_ragdoll = j["self"]["no_ragdoll"]; this->self.off_radar = j["self"]["off_radar"]; this->self.super_run = j["self"]["super_run"]; + this->self.proof_bullet = j["self"]["proof_bullet"]; + this->self.proof_fire = j["self"]["proof_fire"]; + this->self.proof_collision = j["self"]["proof_collision"]; + this->self.proof_melee = j["self"]["proof_melee"]; + this->self.proof_explosion = j["self"]["proof_explosion"]; + this->self.proof_steam = j["self"]["proof_steam"]; + this->self.proof_drown = j["self"]["proof_drown"]; + this->self.proof_water = j["self"]["proof_water"]; + this->self.proof_mask = j["self"]["proof_mask"]; this->settings.hotkeys.menu_toggle = j["settings"]["hotkeys"]["menu_toggle"]; this->spawn.preview_vehicle = j["spawn"]["preview_vehicle"]; this->spawn.spawn_inside = j["spawn"]["spawn_inside"]; this->spawn.spawn_maxed = j["spawn"]["spawn_maxed"]; + this->spawn.plate = j["spawn"]["plate"]; + + this->clone_pv.preview_vehicle = j["clone_pv"]["preview_vehicle"]; + this->clone_pv.spawn_inside = j["clone_pv"]["spawn_inside"]; + this->clone_pv.spawn_clone = j["clone_pv"]["spawn_clone"]; + this->clone_pv.spawn_maxed = j["clone_pv"]["spawn_maxed"]; + this->clone_pv.clone_plate = j["clone_pv"]["clone_plate"]; + this->clone_pv.plate = j["clone_pv"]["plate"]; this->spoofing.spoof_ip = j["spoofing"]["spoof_ip"]; this->spoofing.spoof_rockstar_id = j["spoofing"]["spoof_rockstar_id"]; @@ -517,7 +545,6 @@ namespace big this->vehicle.vehicle_jump = j["vehicle"]["vehicle_jump"]; this->vehicle.instant_brake = j["vehicle"]["instant_brake"]; this->vehicle.is_targetable = j["vehicle"]["is_targetable"]; - this->vehicle.pv_teleport_into = j["vehicle"]["pv_teleport_into"]; this->vehicle.rainbow_paint = j["vehicle"]["rainbow_paint"]; this->vehicle.seatbelt = j["vehicle"]["seatbelt"]; this->vehicle.turn_signals = j["vehicle"]["turn_signals"]; @@ -609,7 +636,7 @@ namespace big "notifications", { { "gta_thread_kill", return_notify_pair(g->notifications.gta_thread_kill) }, { "gta_thread_start", return_notify_pair(g->notifications.gta_thread_start) }, - {"net_array_error", return_notify_pair(g->notifications.net_array_error)}, + { "net_array_error", return_notify_pair(g->notifications.net_array_error) }, { "network_player_mgr_init", return_notify_pair(g->notifications.network_player_mgr_init) }, { "network_player_mgr_shutdown", return_notify_pair(g->notifications.network_player_mgr_shutdown) }, { "player_join", { @@ -714,7 +741,17 @@ namespace big { "never_wanted", this->self.never_wanted }, { "no_ragdoll", this->self.no_ragdoll }, { "off_radar", this->self.off_radar }, - { "super_run", this->self.super_run } + { "super_run", this->self.super_run }, + + { "proof_bullet", this->self.proof_bullet }, + { "proof_fire", this->self.proof_fire }, + { "proof_collision", this->self.proof_collision }, + { "proof_melee", this->self.proof_melee }, + { "proof_explosion", this->self.proof_explosion }, + { "proof_steam", this->self.proof_steam }, + { "proof_drown", this->self.proof_drown }, + { "proof_water", this->self.proof_water }, + { "proof_mask", this->self.proof_mask } } }, { @@ -725,11 +762,22 @@ namespace big } } }, + { + "clone_pv", { + { "preview_vehicle", this->clone_pv.preview_vehicle }, + { "spawn_inside", this->clone_pv.spawn_inside }, + { "spawn_clone", this->clone_pv.spawn_clone }, + { "spawn_maxed", this->clone_pv.spawn_maxed }, + { "clone_plate", this->clone_pv.clone_plate }, + { "plate", this->clone_pv.plate } + } + }, { "spawn", { { "preview_vehicle", this->spawn.preview_vehicle }, { "spawn_inside", this->spawn.spawn_inside }, - { "spawn_maxed", this->spawn.spawn_maxed} + { "spawn_maxed", this->spawn.spawn_maxed}, + { "plate", this->spawn.plate } } }, { @@ -760,7 +808,6 @@ namespace big { "vehicle_jump", this->vehicle.vehicle_jump }, { "instant_brake", this->vehicle.instant_brake }, { "is_targetable", this->vehicle.is_targetable }, - { "pv_teleport_into", this->vehicle.pv_teleport_into }, { "rainbow_paint", this->vehicle.rainbow_paint }, { "turn_signals", this->vehicle.turn_signals }, { "seatbelt", this->vehicle.seatbelt }, diff --git a/BigBaseV2/src/services/gui/gui_service.hpp b/BigBaseV2/src/services/gui/gui_service.hpp index b3bdf09e..a8cb91c2 100644 --- a/BigBaseV2/src/services/gui/gui_service.hpp +++ b/BigBaseV2/src/services/gui/gui_service.hpp @@ -23,6 +23,7 @@ namespace big SESSION, SETTINGS, SPAWN, + PV, SPOOFING, TELEPORT, VEHICLE, @@ -57,6 +58,7 @@ namespace big }}}, { tabs::LSC, {"LSC", view::lsc }}, { tabs::SPAWN, { "Spawn", view::spawn }}, + { tabs::PV, { "Personal Vehicle", view::pv }}, }}}, {tabs::NETWORK, { "Network", nullptr, { { tabs::SPOOFING, { "Spoofing", view::spoofing }}, diff --git a/BigBaseV2/src/services/mobile/mobile_service.cpp b/BigBaseV2/src/services/mobile/mobile_service.cpp index cf70ffd2..d24e0d1d 100644 --- a/BigBaseV2/src/services/mobile/mobile_service.cpp +++ b/BigBaseV2/src/services/mobile/mobile_service.cpp @@ -7,12 +7,17 @@ namespace big { personal_vehicle::personal_vehicle(int idx, script_global vehicle_idx) - : m_id(idx) + : m_id(idx), m_vehicle_idx(vehicle_idx) { - m_hash = *vehicle_idx.at(66).as(); - m_state_bitfield = vehicle_idx.at(103).as(); + m_plate = m_vehicle_idx.at(1).as(); + m_hash = *m_vehicle_idx.at(66).as(); + m_state_bitfield = m_vehicle_idx.at(103).as(); - m_name = HUD::GET_LABEL_TEXT_(VEHICLE::GET_DISPLAY_NAME_FROM_VEHICLE_MODEL(m_hash)); + m_name = fmt::format( + "{} ({})", + HUD::GET_LABEL_TEXT_(VEHICLE::GET_DISPLAY_NAME_FROM_VEHICLE_MODEL(m_hash)), + m_plate + ); } std::string personal_vehicle::get_display_name() const @@ -30,6 +35,16 @@ namespace big return m_id; } + const char* personal_vehicle::get_plate() const + { + return m_plate; + } + + script_global personal_vehicle::get_vehicle_idx() const + { + return m_vehicle_idx; + } + void personal_vehicle::summon() const { mobile::mechanic::summon_vehicle_by_index(m_id); @@ -51,8 +66,7 @@ namespace big if (std::chrono::duration_cast(now - m_last_update) < 10s) return; m_last_update = std::chrono::high_resolution_clock::now(); - g_fiber_pool->queue_job([this] - { + g_fiber_pool->queue_job([this] { register_vehicles(); }); } @@ -75,7 +89,7 @@ namespace big if (STREAMING::IS_MODEL_A_VEHICLE(hash)) { auto veh = std::make_unique(i, veh_idx_global); - + if (exists) { // vehicle name is no longer the same, update the vehicle at that index diff --git a/BigBaseV2/src/services/mobile/mobile_service.hpp b/BigBaseV2/src/services/mobile/mobile_service.hpp index 481b0577..cb900720 100644 --- a/BigBaseV2/src/services/mobile/mobile_service.hpp +++ b/BigBaseV2/src/services/mobile/mobile_service.hpp @@ -1,15 +1,16 @@ #pragma once +#include "script_global.hpp" namespace big { - class script_global; - class personal_vehicle final { - std::string m_name; - int m_id; Hash m_hash; + int m_id; + std::string m_name; + const char* m_plate; int* m_state_bitfield; + script_global m_vehicle_idx; public: personal_vehicle(int idx, script_global vehicle_idx); @@ -17,6 +18,8 @@ namespace big [[nodiscard]] std::string get_display_name() const; [[nodiscard]] Hash get_hash() const; [[nodiscard]] int get_id() const; + [[nodiscard]] const char* get_plate() const; + [[nodiscard]] script_global get_vehicle_idx() const; void summon() const; }; diff --git a/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.cpp b/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.cpp index 2e8656a8..66a18158 100644 --- a/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.cpp +++ b/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.cpp @@ -9,6 +9,36 @@ namespace big { + vehicle_preview_item::vehicle_preview_item() + { + this->name = ""; + this->display_name = ""; + this->display_manufacturer = ""; + this->hash = 0; + } + + vehicle_preview_item::vehicle_preview_item(nlohmann::json& item_json) + { + this->name = item_json["Name"]; + this->display_name = item_json["Name"]; + this->display_manufacturer = ""; + this->hash = item_json["Hash"]; + + if (!item_json["DisplayName"].is_null()) + { + this->display_name = item_json["DisplayName"]; + } + + if (!item_json["ManufacturerDisplayName"].is_null()) + { + this->display_manufacturer = item_json["ManufacturerDisplayName"]; + } + else if (!item_json["Manufacturer"].is_null()) + { + this->display_manufacturer = item_json["Manufacturer"]; + } + } + vehicle_preview_service::vehicle_preview_service() : m_vehicle_file(g_file_manager->get_project_file("./lib/vehicles.json")) { @@ -17,12 +47,12 @@ namespace big else { g_thread_pool->push([this]() - { - if (remote::download_binary("http://github-proxy.damon.sh/DurtyFree/gta-v-data-dumps/master/vehicles.json", m_vehicle_file.get_path())) - this->load(); - else - LOG(WARNING) << "Failed to download vehicles.json data..."; - }); + { + if (remote::download_binary("http://github-proxy.damon.sh/DurtyFree/gta-v-data-dumps/master/vehicles.json", m_vehicle_file.get_path())) + this->load(); + else + LOG(WARNING) << "Failed to download vehicles.json data..."; + }); } g_vehicle_preview_service = this; @@ -33,9 +63,45 @@ namespace big g_vehicle_preview_service = nullptr; } - nlohmann::json& vehicle_preview_service::get_vehicle_list() + const vehicle_preview_item& vehicle_preview_service::find_vehicle_item_by_hash(int hash) { - return m_all_vehicles; + int idx = -1; + + if (m_hash_idx_map.count(hash)) + { + idx = m_hash_idx_map[hash]; + } + + if (idx == -1) + { + return empty_item; + } + else + { + return m_vehicle_preview_item_arr[idx]; + } + } + + std::vector& vehicle_preview_service::get_vehicle_preview_item_arr() + { + return m_vehicle_preview_item_arr; + } + + void vehicle_preview_service::set_preview_vehicle(const vehicle_preview_item& item) + { + if (item.hash != 0) + { + if (m_model_hash != item.hash) + { + m_model_hash = item.hash; + m_new_model = true; + } + + if (!m_running) + { + g_thread_pool->push([this] { preview_loop(); }); + } + } } void vehicle_preview_service::preview_loop() @@ -43,61 +109,49 @@ namespace big if (m_running) return; m_running = true; - + g_fiber_pool->queue_job([this] - { - while (g_running && m_running && g->spawn.preview_vehicle && g_gui.m_opened) { - auto location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 2.5f, 2.5f, .5f); - if (m_current_veh == -1) + while (g_running && m_running && g->spawn.preview_vehicle && g_gui.m_opened) { - m_new_model = false; - location.z = -10.f; - m_current_veh = vehicle::spawn(m_model, location, 0.f, false); - ENTITY::FREEZE_ENTITY_POSITION(m_current_veh, true); - ENTITY::SET_ENTITY_ALPHA(m_current_veh, 0, 0); - ENTITY::SET_ENTITY_COLLISION(m_current_veh, false, false); - ENTITY::SET_CAN_CLIMB_ON_ENTITY(m_current_veh, false); - OBJECT::SET_OBJECT_ALLOW_LOW_LOD_BUOYANCY(m_current_veh, false); - } - else if (m_new_model) - { - entity::delete_entity(m_current_veh); + auto location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f); + if (m_current_veh == -1) + { + m_new_model = false; + location.z = -10.f; + m_current_veh = vehicle::spawn(m_model_hash, location, 0.f, false); + ENTITY::FREEZE_ENTITY_POSITION(m_current_veh, true); + ENTITY::SET_ENTITY_ALPHA(m_current_veh, 0, 0); + ENTITY::SET_ENTITY_COLLISION(m_current_veh, false, false); + ENTITY::SET_CAN_CLIMB_ON_ENTITY(m_current_veh, false); + OBJECT::SET_OBJECT_ALLOW_LOW_LOD_BUOYANCY(m_current_veh, false); + } + else if (m_new_model) + { + entity::delete_entity(m_current_veh); - m_current_veh = -1; - } - else - { - if (const int alpha = ENTITY::GET_ENTITY_ALPHA(m_current_veh); alpha < 250) - ENTITY::SET_ENTITY_ALPHA(m_current_veh, std::min(255, alpha + 10), 0); + m_current_veh = -1; + } + else + { + if (const int alpha = ENTITY::GET_ENTITY_ALPHA(m_current_veh); alpha < 250) + { + ENTITY::SET_ENTITY_ALPHA(m_current_veh, std::min(255, alpha + 10), 0); + } - ENTITY::SET_ENTITY_HEADING(m_current_veh, m_heading); - ENTITY::SET_ENTITY_COORDS(m_current_veh, location.x, location.y, location.z, 0, 0, 0, 0); + ENTITY::SET_ENTITY_HEADING(m_current_veh, m_heading); + ENTITY::SET_ENTITY_COORDS(m_current_veh, location.x, location.y, location.z, 0, 0, 0, 0); + } + + if (m_heading += 0.5f; m_heading > 359) m_heading = 0; + + script::get_current()->yield(); } - if (m_heading += 0.5f; m_heading > 359) m_heading = 0; - - script::get_current()->yield(); - } - - entity::delete_entity(m_current_veh); - m_current_veh = -1; - m_running = false; - }); - } - - - void vehicle_preview_service::set_preview_vehicle(const nlohmann::json& item) - { - if (m_model != item["Name"]) - { - m_model = item["Name"]; - - m_new_model = true; - } - - if (!m_running) - g_thread_pool->push([this] { preview_loop(); }); + entity::delete_entity(m_current_veh); + m_current_veh = -1; + m_running = false; + }); } void vehicle_preview_service::stop_preview() @@ -107,15 +161,35 @@ namespace big void vehicle_preview_service::load() { + m_hash_idx_map.clear(); + m_vehicle_preview_item_arr.clear(); + std::ifstream file(m_vehicle_file.get_path()); + nlohmann::json all_vehicles; try { - file >> m_all_vehicles; + file >> all_vehicles; } catch (const std::exception& ex) { LOG(WARNING) << "Failed to load vehicles.json:\n" << ex.what(); } + + for (auto& item_json : all_vehicles) + { + if ( + item_json["Hash"].is_null() || + item_json["Name"].is_null() || + !item_json["Bones"].is_array() || + item_json["Bones"][0] == "stub" + ) + { + continue; + } + + m_hash_idx_map[item_json["SignedHash"]] = (int)m_vehicle_preview_item_arr.size(); + m_vehicle_preview_item_arr.push_back(vehicle_preview_item(item_json)); + } } } diff --git a/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.hpp b/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.hpp index b8f44364..d2e5c4de 100644 --- a/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.hpp +++ b/BigBaseV2/src/services/vehicle_preview/vehicle_preview_service.hpp @@ -3,6 +3,18 @@ namespace big { + class vehicle_preview_item { + + public: + vehicle_preview_item(); + vehicle_preview_item(nlohmann::json& item_json); + + std::string name; + std::string display_name; + std::string display_manufacturer; + Hash hash; + }; + class vehicle_preview_service { file m_vehicle_file; @@ -10,10 +22,12 @@ namespace big std::condition_variable m_cond; std::mutex m_mutex; - nlohmann::json m_all_vehicles; + std::map m_hash_idx_map; + std::vector m_vehicle_preview_item_arr; + const vehicle_preview_item empty_item = vehicle_preview_item(); Vehicle m_current_veh = -1; - std::string m_model; + Hash m_model_hash; bool m_new_model = false; float m_heading = 0.f; bool m_running = false; @@ -21,11 +35,11 @@ namespace big vehicle_preview_service(); ~vehicle_preview_service(); - nlohmann::json& get_vehicle_list(); + const vehicle_preview_item& find_vehicle_item_by_hash(int hash); + std::vector& get_vehicle_preview_item_arr(); + void set_preview_vehicle(const vehicle_preview_item& item); void preview_loop(); - - void set_preview_vehicle(const nlohmann::json& item); void stop_preview(); private: diff --git a/BigBaseV2/src/util/math.hpp b/BigBaseV2/src/util/math.hpp index 4ed74433..d14b60e1 100644 --- a/BigBaseV2/src/util/math.hpp +++ b/BigBaseV2/src/util/math.hpp @@ -9,9 +9,9 @@ namespace big::math return (float)radian; } - inline double distance_between_vectors(Vector3 a, Vector3 b) + inline float distance_between_vectors(Vector3 a, Vector3 b) { - return sqrt(pow((a.x - b.x), 2) + pow((a.y - b.y), 2) + pow((a.z - b.z), 2)); + return (float)sqrt(pow((a.x - b.x), 2) + pow((a.y - b.y), 2) + pow((a.z - b.z), 2)); } inline Vector3 rotation_to_direction(Vector3 rotation) diff --git a/BigBaseV2/src/util/mobile.hpp b/BigBaseV2/src/util/mobile.hpp index 49f93912..7309fed3 100644 --- a/BigBaseV2/src/util/mobile.hpp +++ b/BigBaseV2/src/util/mobile.hpp @@ -89,7 +89,7 @@ namespace big::mobile if (*mechanic_global.at(958).as() != -1) return g_notification_service->push_warning("Vehicle", "Mechanic is not ready to deliver a vehicle right now."); - if (g->vehicle.pv_teleport_into && self::veh) + if (g->clone_pv.spawn_inside && self::veh) TASK::CLEAR_PED_TASKS_IMMEDIATELY(PLAYER::PLAYER_PED_ID()); // despawn current veh @@ -112,8 +112,10 @@ namespace big::mobile // blocking call till vehicle is delivered notify::busy_spinner("Delivering vehicle...", mechanic_global.at(958).as(), -1); - if (g->vehicle.pv_teleport_into) - vehicle::bring(globals::get_personal_vehicle(), self::pos); + if (g->clone_pv.spawn_inside) + { + big::vehicle::bring(globals::get_personal_vehicle(), self::pos, true); + } } } } \ No newline at end of file diff --git a/BigBaseV2/src/util/vehicle.hpp b/BigBaseV2/src/util/vehicle.hpp index 0d154287..4f6d89cc 100644 --- a/BigBaseV2/src/util/vehicle.hpp +++ b/BigBaseV2/src/util/vehicle.hpp @@ -10,6 +10,8 @@ namespace big::vehicle { + inline auto spawn_global = script_global(2725269); + inline void go_into_personal_vehicle() { *script_global(2671447).at(8).as() = 1; @@ -19,12 +21,12 @@ namespace big::vehicle { if (!ENTITY::IS_ENTITY_A_VEHICLE(veh)) return g_notification_service->push_error("Vehicle", "Invalid handle"); - Vector3 vecVehicleLocation = ENTITY::GET_ENTITY_COORDS(veh, true); + auto vecVehicleLocation = ENTITY::GET_ENTITY_COORDS(veh, true); teleport::load_ground_at_3dcoord(vecVehicleLocation); if (!entity::take_control_of(veh)) return g_notification_service->push_warning("Vehicle", "Failed to take control of remote vehicle."); - Ped ped = self::ped; + auto ped = self::ped; ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0); ENTITY::SET_ENTITY_HEADING(veh, ENTITY::GET_ENTITY_HEADING(ped)); @@ -38,14 +40,67 @@ namespace big::vehicle } } - inline Vehicle get_closest_to_location(Vector3 location, float range, int flags = 70) + inline Vehicle get_closest_to_location(Vector3 location, float range) { - return VEHICLE::GET_CLOSEST_VEHICLE(location.x, location.y, location.z, range, 0, flags); + if (const auto replay = *g_pointers->m_replay_interface; replay) + { + if (const auto veh_interface = replay->m_vehicle_interface; veh_interface) + { + const auto veh_interface_size = veh_interface->m_max_vehicles; + + float min_dist = range + 1; + int32_t m_handle = 0; + + for (int32_t i = 0; i < veh_interface_size; i++) + { + auto veh_entity = veh_interface->m_vehicle_list->m_vehicles[i]; + auto veh_ptr = veh_entity.m_entity_ptr; + + if (!veh_ptr || !veh_ptr->m_navigation) + { + continue; + } + + auto veh_pos_arr = veh_ptr->m_navigation->m_position; + Vector3 veh_pos(veh_pos_arr.x, veh_pos_arr.y, veh_pos_arr.z); + + float dist = math::distance_between_vectors(veh_pos, location); + + if (dist < min_dist) + { + min_dist = dist; + m_handle = g_pointers->m_ptr_to_handle(veh_ptr); + } + } + + return m_handle; + } + } + + return 0; + } + + inline bool set_plate(Vehicle veh, const char* plate) + { + if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh)) + { + return false; + } + + if (plate != nullptr && plate[0] != 0) + { + VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT(veh, plate); + } + + return true; } inline bool repair(Vehicle veh) { - if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh)) return false; + if (!ENTITY::IS_ENTITY_A_VEHICLE(veh) || !entity::take_control_of(veh)) + { + return false; + } VEHICLE::SET_VEHICLE_FIXED(veh); VEHICLE::SET_VEHICLE_DEFORMATION_FIXED(veh); @@ -54,45 +109,123 @@ namespace big::vehicle return true; } - inline int spawn(std::string_view model, Vector3 location, float heading, bool is_networked = true) + inline int spawn(Hash hash, Vector3 location, float heading, bool is_networked = true) { - if (const Hash hash = rage::joaat(model.data()); hash) + for (uint8_t i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) { - for (uint8_t i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) - { - STREAMING::REQUEST_MODEL(hash); - - script::get_current()->yield(); - } - if (!STREAMING::HAS_MODEL_LOADED(hash)) - { - g_notification_service->push_warning("Spawn", "Failed to spawn model, did you give an incorrect model?"); - - return -1; - } - - *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x9090; - Vehicle veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, false, false); - *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x0574; + STREAMING::REQUEST_MODEL(hash); script::get_current()->yield(); - - STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); - - if (*g_pointers->m_is_session_started) - { - DECORATOR::DECOR_SET_INT(veh, "MPBitset", 0); - ENTITY::SET_ENTITY_CLEANUP_BY_ENGINE_(veh, true); - int networkId = NETWORK::VEH_TO_NET(veh); - if (NETWORK::NETWORK_GET_ENTITY_IS_NETWORKED(veh)) - NETWORK::SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(networkId, true); - VEHICLE::SET_VEHICLE_IS_STOLEN(veh, false); - } - - return veh; } - return -1; + if (!STREAMING::HAS_MODEL_LOADED(hash)) + { + g_notification_service->push_warning("Spawn", "Failed to spawn model, did you give an incorrect model?"); + + return -1; + } + + *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x9090; + auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, false, false); + *(unsigned short*)g_pointers->m_model_spawn_bypass = 0x0574; + + script::get_current()->yield(); + + STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); + + if (*g_pointers->m_is_session_started) + { + DECORATOR::DECOR_SET_INT(veh, "MPBitset", 0); + ENTITY::SET_ENTITY_CLEANUP_BY_ENGINE_(veh, true); + int networkId = NETWORK::VEH_TO_NET(veh); + if (NETWORK::NETWORK_GET_ENTITY_IS_NETWORKED(veh)) + NETWORK::SET_NETWORK_ID_EXISTS_ON_ALL_MACHINES(networkId, true); + VEHICLE::SET_VEHICLE_IS_STOLEN(veh, false); + } + + return veh; + } + + inline Vehicle clone(std::map& data, Vector3 location, float heading) + { + Vector3 tmpLocation = { location.x, location.y, 1200.0f }; + if (location.z > 1000.0f && location.z < 1400.0) + { + tmpLocation.z = 800.0f; + } + + // vehicle data + for (const auto& [idx, val] : data) + { + if (idx >= 0 && idx < 142) + { + *spawn_global.at(27).at(idx).as() = val; + } + } + + // permission fix + *spawn_global.at(27).at(19).as() = -1; + *spawn_global.at(27).at(60).as() = 1; + *spawn_global.at(27).at(77).as() = 4030726305; + + // personal car flag + *spawn_global.at(27).at(94).as() = 0; + *spawn_global.at(27).at(95).as() = 0; + + // mmi + *spawn_global.at(27).at(103).as() = 0; + + // spawn location + *spawn_global.at(7).at(0).as() = tmpLocation.x; + *spawn_global.at(7).at(1).as() = tmpLocation.y; + *spawn_global.at(7).at(2).as() = tmpLocation.z; + + // spawn non pegasus + *spawn_global.at(3).as() = 0; + + // spawn signal + int* spawn_signal = spawn_global.at(2).as(); + *spawn_global.at(5).as() = 1; + *spawn_signal = 1; + + // wait until the vehicle is spawned + for (size_t retry = 0; *spawn_signal != 0 && retry < 200; retry++) + { + script::get_current()->yield(10ms); + } + + if (*spawn_signal == 1) + { + g_notification_service->push_error("Vehicle", "Unable to clone vehicle"); + return 0; + } + + auto veh = vehicle::get_closest_to_location(tmpLocation, 200); + if (!ENTITY::IS_ENTITY_A_VEHICLE(veh)) + { + g_notification_service->push_error("Vehicle", "Unable to clone vehicle"); + return 0; + } + + ENTITY::SET_ENTITY_COORDS(veh, location.x, location.y, location.z + 1.f, 0, 0, 0, 0); + ENTITY::SET_ENTITY_HEADING(veh, heading); + + return veh; + } + + inline std::map get_vehicle_data_from_vehicle_idx(script_global vehicle_idx) + { + std::map veh_data; + + for (int i = 0; i < 142; i++) + { + veh_data[i] = *vehicle_idx.at(i).as(); + } + + veh_data.erase(1); veh_data.erase(19); veh_data.erase(60); veh_data.erase(77); + veh_data.erase(94); veh_data.erase(95); veh_data.erase(103); + + return veh_data; } inline void telport_into_veh(Vehicle veh) @@ -108,9 +241,14 @@ namespace big::vehicle VEHICLE::TOGGLE_VEHICLE_MOD(veh, 17 /* Xenon Headlights */, TRUE); VEHICLE::SET_VEHICLE_WINDOW_TINT(veh, 1); VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(veh, false); + for (int i = 0; i < 50; i++) { - VEHICLE::SET_VEHICLE_MOD(veh, i, VEHICLE::GET_NUM_VEHICLE_MODS(veh, i) - 1, true); + if ( + i != eVehicleModType::VMT_LIVERY_MOD + ) { + VEHICLE::SET_VEHICLE_MOD(veh, i, VEHICLE::GET_NUM_VEHICLE_MODS(veh, i) - 1, true); + } } } diff --git a/BigBaseV2/src/views/self/view_mobile.cpp b/BigBaseV2/src/views/self/view_mobile.cpp index 2d5d52c9..4054a9c0 100644 --- a/BigBaseV2/src/views/self/view_mobile.cpp +++ b/BigBaseV2/src/views/self/view_mobile.cpp @@ -6,14 +6,7 @@ namespace big { void view::mobile() { - components::button("Mors Mutual Fix All Vehicles", [] { - int amount_fixed = mobile::mors_mutual::fix_all(); - g_notification_service->push("Mobile", - fmt::format("{} vehicle{} been fixed.", amount_fixed, amount_fixed == 1 ? " has" : "s have") - ); - }); - - ImGui::Separator(); + ImGui::SetWindowSize({ 0.f, (float)*g_pointers->m_resolution_y }, ImGuiCond_Always); components::small_text("Lester"); @@ -21,63 +14,11 @@ namespace big ImGui::Separator(); - components::small_text("Mechanic - Personal Vehicles"); - - static char search[64]; - static std::string lower_search; - - ImGui::BeginGroup(); - - ImGui::SetNextItemWidth(400.f); - if (ImGui::InputTextWithHint("##search_pv_list", "Search", search, sizeof(search))) - { - lower_search = search; - std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower); - } - - g_mobile_service->refresh_personal_vehicles(); - if (ImGui::ListBoxHeader("##personal_veh_list", { 400.f, 500.f })) - { - if (g_mobile_service->personal_vehicles().empty()) - { - ImGui::Text("No personal vehicles found, are you online?"); - } - else - { - const auto personal_veh_idx = mobile::util::get_current_personal_vehicle(); - for (const auto& it : g_mobile_service->personal_vehicles()) - { - const auto& label = it.first; - const auto& personal_veh = it.second; - - auto lower = label; - std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); - - if (lower.find(lower_search) != std::string::npos) - { - if (ImGui::Selectable(label.c_str(), personal_veh->get_id() == personal_veh_idx)) - { - strcpy(search, ""); - lower_search = search; - - g_fiber_pool->queue_job([&personal_veh] { - personal_veh->summon(); - }); - } - } - } - } - - ImGui::ListBoxFooter(); - } - - ImGui::EndGroup(); - - ImGui::BeginGroup(); - - ImGui::Checkbox("Spawn in Vehicle", &g->vehicle.pv_teleport_into); - - ImGui::EndGroup(); - + components::button("Mors Mutual Fix All Vehicles", [] { + int amount_fixed = mobile::mors_mutual::fix_all(); + g_notification_service->push("Mobile", + fmt::format("{} vehicle{} been fixed.", amount_fixed, amount_fixed == 1 ? " has" : "s have") + ); + }); } } diff --git a/BigBaseV2/src/views/self/view_self.cpp b/BigBaseV2/src/views/self/view_self.cpp index aff3cabf..176be029 100644 --- a/BigBaseV2/src/views/self/view_self.cpp +++ b/BigBaseV2/src/views/self/view_self.cpp @@ -93,7 +93,7 @@ namespace big components::button("Clean Player", [] { entity::clean_ped(self::ped); - }); + }); ImGui::EndGroup(); @@ -111,7 +111,7 @@ namespace big ImGui::SliderInt("###wanted_level", &g->self.wanted_level, 0, 5) && !g->self.force_wanted_level && g_local_player != nullptr - ) { + ) { g_local_player->m_player_info->m_wanted_level = g->self.wanted_level; } } @@ -120,7 +120,8 @@ namespace big components::small_text("Proofs"); - if (ImGui::Button("Check all")) { + if (ImGui::Button("Check all")) + { g->self.proof_bullet = true; g->self.proof_fire = true; g->self.proof_collision = true; @@ -133,7 +134,8 @@ namespace big ImGui::SameLine(); - if (ImGui::Button("Uncheck all")) { + if (ImGui::Button("Uncheck all")) + { g->self.proof_bullet = false; g->self.proof_fire = false; g->self.proof_collision = false; @@ -173,31 +175,41 @@ namespace big ImGui::EndGroup(); g->self.proof_mask = 0; - if (g->self.godmode) { + if (g->self.godmode) + { g->self.proof_mask |= static_cast(eEntityProofs::GOD); - } else { - if (g->self.proof_bullet) { + } else + { + if (g->self.proof_bullet) + { g->self.proof_mask |= static_cast(eEntityProofs::BULLET); } - if (g->self.proof_fire) { + if (g->self.proof_fire) + { g->self.proof_mask |= static_cast(eEntityProofs::FIRE); } - if (g->self.proof_collision) { + if (g->self.proof_collision) + { g->self.proof_mask |= static_cast(eEntityProofs::COLLISION); } - if (g->self.proof_melee) { + if (g->self.proof_melee) + { g->self.proof_mask |= static_cast(eEntityProofs::MELEE); } - if (g->self.proof_explosion) { + if (g->self.proof_explosion) + { g->self.proof_mask |= static_cast(eEntityProofs::EXPLOSION); } - if (g->self.proof_steam) { + if (g->self.proof_steam) + { g->self.proof_mask |= static_cast(eEntityProofs::STEAM); } - if (g->self.proof_drown) { + if (g->self.proof_drown) + { g->self.proof_mask |= static_cast(eEntityProofs::DROWN); } - if (g->self.proof_water) { + if (g->self.proof_water) + { g->self.proof_mask |= static_cast(eEntityProofs::WATER); } } diff --git a/BigBaseV2/src/views/vehicle/view_pv.cpp b/BigBaseV2/src/views/vehicle/view_pv.cpp new file mode 100644 index 00000000..813bc07f --- /dev/null +++ b/BigBaseV2/src/views/vehicle/view_pv.cpp @@ -0,0 +1,151 @@ +#include "views/view.hpp" +#include "fiber_pool.hpp" +#include "natives.hpp" +#include "services/mobile/mobile_service.hpp" +#include "services/vehicle_preview/vehicle_preview_service.hpp" +#include "util/vehicle.hpp" + +namespace big +{ + void view::pv() { + ImGui::SetWindowSize({ 0.f, (float)*g_pointers->m_resolution_y }, ImGuiCond_Always); + + ImGui::Checkbox("Preview", &g->clone_pv.preview_vehicle); + ImGui::SameLine(); + ImGui::Checkbox("Spawn In", &g->clone_pv.spawn_inside); + ImGui::SameLine(); + + static char plate[9] = { 0 }; + int num_of_rows = 2; + + ImGui::Checkbox("Spawn Clone", &g->clone_pv.spawn_clone); + if (g->clone_pv.spawn_clone) + { + num_of_rows = 4; + + ImGui::Checkbox("Spawn Maxed", &g->clone_pv.spawn_maxed); + + ImGui::SameLine(); + strncpy(plate, g->clone_pv.plate.c_str(), 9); + ImGui::Checkbox("Clone PV Plate", &g->clone_pv.clone_plate); + if (g->clone_pv.clone_plate) + { + num_of_rows = 3; + } + else + { + ImGui::SetNextItemWidth(300.f); + + components::input_text_with_hint("Plate", "Plate Number", plate, sizeof(plate), ImGuiInputTextFlags_None, [] { + g->clone_pv.plate = plate; + }); + } + } + + static char search[64]; + static std::string lower_search; + + ImGui::SetNextItemWidth(300.f); + components::input_text_with_hint("Model Name", "Search", search, sizeof(search), ImGuiInputTextFlags_None, [] { + lower_search = search; + std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower); + }); + + g_mobile_service->refresh_personal_vehicles(); + if (ImGui::ListBoxHeader("##personal_veh_list", { 300, static_cast(*g_pointers->m_resolution_y - 184 - 38 * num_of_rows) })) + { + + if (g_mobile_service->personal_vehicles().empty()) + { + ImGui::Text("No personal vehicles found, \nare you online?"); + } + else + { + + for (const auto& it : g_mobile_service->personal_vehicles()) + { + const auto& label = it.first; + const auto& personal_veh = it.second; + auto item = g_vehicle_preview_service->find_vehicle_item_by_hash(personal_veh->get_hash()); + + std::string display_name = label; + std::string display_manufacturer = item.display_manufacturer; + std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower); + std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower); + + if ( + display_name.find(lower_search) != std::string::npos || + display_manufacturer.find(lower_search) != std::string::npos + ) { + ImGui::PushID(personal_veh->get_id()); + if (ImGui::Selectable(label.c_str(), false)) { + + if (g->clone_pv.spawn_clone) + { + g_fiber_pool->queue_job([&personal_veh] { + auto vehicle_idx = personal_veh->get_vehicle_idx(); + auto veh_data = vehicle::get_vehicle_data_from_vehicle_idx(vehicle_idx); + + float y_offset = 0; + + if (PED::IS_PED_IN_ANY_VEHICLE(self::ped, false)) + { + y_offset = 10.f; + } + else if (!g->spawn.spawn_inside) + { + y_offset = 5.f; + } + + auto spawn_location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, y_offset, 0.f); + float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped); + + const char* spawn_plate = plate; + if (g->clone_pv.clone_plate) + { + spawn_plate = personal_veh->get_plate(); + } + + auto veh = vehicle::clone(veh_data, spawn_location, spawn_heading); + + if (g->clone_pv.spawn_inside) + { + vehicle::telport_into_veh(veh); + } + + if (g->clone_pv.spawn_maxed) + { + vehicle::max_vehicle(veh); + } + + vehicle::set_plate(veh, spawn_plate); + }); + } + else + { + strcpy(search, ""); + lower_search = search; + + g_fiber_pool->queue_job([&personal_veh] { + personal_veh->summon(); + }); + } + } + ImGui::PopID(); + + if (g->clone_pv.preview_vehicle && ImGui::IsItemHovered()) + { + g_vehicle_preview_service->set_preview_vehicle(item); + } + else if (g->clone_pv.preview_vehicle && !ImGui::IsAnyItemHovered()) + { + g_vehicle_preview_service->stop_preview(); + } + } + } + } + + ImGui::ListBoxFooter(); + } + } +} \ No newline at end of file diff --git a/BigBaseV2/src/views/vehicle/view_spawn.cpp b/BigBaseV2/src/views/vehicle/view_spawn.cpp index 48ae15cf..90279f4c 100644 --- a/BigBaseV2/src/views/vehicle/view_spawn.cpp +++ b/BigBaseV2/src/views/vehicle/view_spawn.cpp @@ -6,15 +6,6 @@ namespace big { - static char model[12] = ""; - - bool does_search_match(std::string& input, const std::string& search) - { - std::transform(input.begin(), input.end(), input.begin(), ::tolower); - - return input.find(search) != std::string::npos; - } - void view::spawn() { ImGui::SetWindowSize({ 0.f, (float)*g_pointers->m_resolution_y }, ImGuiCond_Always); @@ -24,48 +15,61 @@ namespace big ImGui::SameLine(); ImGui::Checkbox("Spawn Maxed", &g->spawn.spawn_maxed); - components::input_text_with_hint("Model Name", "Search", model, sizeof(model), ImGuiInputTextFlags_EnterReturnsTrue, [] - { - const auto ped = self::ped; + static char plate[9] = { 0 }; + strncpy(plate, g->spawn.plate.c_str(), 9); - const auto location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(ped, 2.f, 2.f, 0.f); - const auto veh = vehicle::spawn(model, location, g_local_player->m_player_info->m_ped->m_navigation->m_right.x + 90.f); - - if (g->spawn.spawn_inside) - PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), veh, -1); - - if (g->spawn.spawn_maxed) - vehicle::max_vehicle(veh); + ImGui::SetNextItemWidth(300.f); + components::input_text_with_hint("Plate", "Plate Number", plate, sizeof(plate), ImGuiInputTextFlags_None, [] { + g->spawn.plate = plate; }); + + static char search[64]; + static std::string lower_search; + + ImGui::SetNextItemWidth(300.f); + components::input_text_with_hint("Model Name", "Search", search, sizeof(search), ImGuiInputTextFlags_None, [] { + lower_search = search; + std::transform(lower_search.begin(), lower_search.end(), lower_search.begin(), tolower); + }); + // arbitrary subtraction this looked nice so idc, works for all resolutions as well - if (ImGui::ListBoxHeader("###vehicles", { 0, static_cast(*g_pointers->m_resolution_y - 260)})) + if (ImGui::ListBoxHeader("###vehicles", { 300, static_cast(*g_pointers->m_resolution_y - 184 - 38 * 3) })) { - if (!g_vehicle_preview_service->get_vehicle_list().is_null()) + + auto item_arr = g_vehicle_preview_service->get_vehicle_preview_item_arr(); + + if (item_arr.size() > 0) { - for (auto& item : g_vehicle_preview_service->get_vehicle_list()) - { - if (item["Name"].is_null() || item["DisplayName"].is_null()) - continue; - std::string name = item["Name"]; - std::string display_name = item["DisplayName"]; + for (auto& item : item_arr) { + std::string display_name = item.display_name; + std::string display_manufacturer = item.display_manufacturer; - std::string manufacturer; - std::string search = model; - std::transform(search.begin(), search.end(), search.begin(), ::tolower); + std::transform(display_name.begin(), display_name.end(), display_name.begin(), ::tolower); + std::transform(display_manufacturer.begin(), display_manufacturer.end(), display_manufacturer.begin(), ::tolower); - if (!item["ManufacturerDisplayName"].is_null()) - manufacturer = item["ManufacturerDisplayName"]; + if ( + display_name.find(lower_search) != std::string::npos || + display_manufacturer.find(lower_search) != std::string::npos + ) { + //ImGui::PushID(item.hash); + components::selectable(item.display_name, false, [item] { - if (search.empty() || - does_search_match(name, search) || - does_search_match(display_name, search) || - does_search_match(manufacturer, search)) - { - components::selectable(item["DisplayName"], item["Name"] == search, [&item] - { - const auto location = self::pos; - const Vehicle veh = vehicle::spawn(item["Name"], location, 0.f); + float y_offset = 0; + + if (PED::IS_PED_IN_ANY_VEHICLE(self::ped, false)) + { + y_offset = 10.f; + } + else if (!g->spawn.spawn_inside) + { + y_offset = 5.f; + } + + Vector3 spawn_location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, y_offset, 0.f); + float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped); + + const Vehicle veh = vehicle::spawn(item.hash, spawn_location, spawn_heading); if (g->spawn.spawn_inside) { @@ -77,17 +81,27 @@ namespace big vehicle::max_vehicle(veh); } + vehicle::set_plate(veh, plate); + g_vehicle_preview_service->stop_preview(); }); + //ImGui::PopID(); if (g->spawn.preview_vehicle && ImGui::IsItemHovered()) + { g_vehicle_preview_service->set_preview_vehicle(item); + } else if (g->spawn.preview_vehicle && !ImGui::IsAnyItemHovered()) + { g_vehicle_preview_service->stop_preview(); + } } } } - else ImGui::Text("No vehicles in registry."); + else + { + ImGui::Text("No vehicles in registry."); + } ImGui::ListBoxFooter(); } } diff --git a/BigBaseV2/src/views/view.hpp b/BigBaseV2/src/views/view.hpp index 6f5fb83f..c50ba761 100644 --- a/BigBaseV2/src/views/view.hpp +++ b/BigBaseV2/src/views/view.hpp @@ -33,6 +33,7 @@ namespace big static void session(); static void settings(); static void spawn(); + static void pv(); static void spoofing(); static void teleport(); static void vehicle();