feat(Personal Vehicle): Added clone personal vehicle feature. (#326)

This commit is contained in:
aa15032261 2022-07-10 06:33:14 +08:00 committed by GitHub
parent 964347dbe4
commit 2d9021f0b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 715 additions and 248 deletions

View File

@ -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)
);

View File

@ -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,

View File

@ -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 },

View File

@ -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 }},

View File

@ -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<Hash*>();
m_state_bitfield = vehicle_idx.at(103).as<int*>();
m_plate = m_vehicle_idx.at(1).as<char*>();
m_hash = *m_vehicle_idx.at(66).as<Hash*>();
m_state_bitfield = m_vehicle_idx.at(103).as<int*>();
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<std::chrono::seconds>(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<personal_vehicle>(i, veh_idx_global);
if (exists)
{
// vehicle name is no longer the same, update the vehicle at that index

View File

@ -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;
};

View File

@ -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_item>& 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<int>(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<int>(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));
}
}
}

View File

@ -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<Hash, int> m_hash_idx_map;
std::vector<vehicle_preview_item> 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<vehicle_preview_item>& 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:

View File

@ -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)

View File

@ -89,7 +89,7 @@ namespace big::mobile
if (*mechanic_global.at(958).as<int*>() != -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<int*>(), -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);
}
}
}
}

View File

@ -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<int*>() = 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<int, int32_t>& 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<int32_t*>() = val;
}
}
// permission fix
*spawn_global.at(27).at(19).as<int32_t*>() = -1;
*spawn_global.at(27).at(60).as<int32_t*>() = 1;
*spawn_global.at(27).at(77).as<int32_t*>() = 4030726305;
// personal car flag
*spawn_global.at(27).at(94).as<int32_t*>() = 0;
*spawn_global.at(27).at(95).as<int32_t*>() = 0;
// mmi
*spawn_global.at(27).at(103).as<int32_t*>() = 0;
// spawn location
*spawn_global.at(7).at(0).as<float*>() = tmpLocation.x;
*spawn_global.at(7).at(1).as<float*>() = tmpLocation.y;
*spawn_global.at(7).at(2).as<float*>() = tmpLocation.z;
// spawn non pegasus
*spawn_global.at(3).as<int*>() = 0;
// spawn signal
int* spawn_signal = spawn_global.at(2).as<int32_t*>();
*spawn_global.at(5).as<int32_t*>() = 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<int, int32_t> get_vehicle_data_from_vehicle_idx(script_global vehicle_idx)
{
std::map<int, int32_t> veh_data;
for (int i = 0; i < 142; i++)
{
veh_data[i] = *vehicle_idx.at(i).as<int32_t*>();
}
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);
}
}
}

View File

@ -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")
);
});
}
}

View File

@ -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<int>(eEntityProofs::GOD);
} else {
if (g->self.proof_bullet) {
} else
{
if (g->self.proof_bullet)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::BULLET);
}
if (g->self.proof_fire) {
if (g->self.proof_fire)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::FIRE);
}
if (g->self.proof_collision) {
if (g->self.proof_collision)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::COLLISION);
}
if (g->self.proof_melee) {
if (g->self.proof_melee)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::MELEE);
}
if (g->self.proof_explosion) {
if (g->self.proof_explosion)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::EXPLOSION);
}
if (g->self.proof_steam) {
if (g->self.proof_steam)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::STEAM);
}
if (g->self.proof_drown) {
if (g->self.proof_drown)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::DROWN);
}
if (g->self.proof_water) {
if (g->self.proof_water)
{
g->self.proof_mask |= static_cast<int>(eEntityProofs::WATER);
}
}

View File

@ -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<float>(*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();
}
}
}

View File

@ -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<float>(*g_pointers->m_resolution_y - 260)}))
if (ImGui::ListBoxHeader("###vehicles", { 300, static_cast<float>(*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();
}
}

View File

@ -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();