2022-07-28 20:42:57 +02:00
|
|
|
#include "persist_car_service.hpp"
|
2023-03-01 21:27:15 +00:00
|
|
|
|
|
|
|
#include "base/CObject.hpp"
|
|
|
|
#include "pointers.hpp"
|
|
|
|
#include "util/misc.hpp"
|
2022-07-28 20:42:57 +02:00
|
|
|
#include "util/vehicle.hpp"
|
2022-09-20 14:51:43 +02:00
|
|
|
#include "util/world_model.hpp"
|
2022-10-18 15:08:05 -04:00
|
|
|
#include "vehicle/CVehicle.hpp"
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
namespace big
|
|
|
|
{
|
2023-08-27 15:32:14 -04:00
|
|
|
void persist_car_service::save_vehicle(Vehicle vehicle, std::string_view file_name, std::string folder_name)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-03-01 21:27:15 +00:00
|
|
|
if (!ENTITY::DOES_ENTITY_EXIST(vehicle) || !ENTITY::IS_ENTITY_A_VEHICLE(vehicle))
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-03-01 21:27:15 +00:00
|
|
|
g_notification_service->push_warning("PERSIST_CAR_TITLE"_T.data(),
|
|
|
|
"PERSIST_CAR_INVALID_VEHICLE_SAVE_ATTEMPT"_T.data());
|
2022-07-28 20:42:57 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
std::ofstream file_stream(file.get_path(), std::ios::out | std::ios::trunc);
|
|
|
|
|
|
|
|
file_stream << get_full_vehicle_json(vehicle).dump(4);
|
|
|
|
|
|
|
|
file_stream.close();
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
Vehicle persist_car_service::load_vehicle(std::string_view file_name, std::string folder_name)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-08-27 15:32:14 -04:00
|
|
|
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
std::ifstream file_stream(file.get_path());
|
|
|
|
|
|
|
|
nlohmann::json vehicle_json;
|
|
|
|
|
2023-07-01 22:25:40 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
file_stream >> vehicle_json;
|
|
|
|
file_stream.close();
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
g_notification_service->push_warning("PERSIST_CAR_TITLE"_T.data(), "Failed to load JSON file");
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
return spawn_vehicle_full(vehicle_json, self::ped);
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
std::vector<std::string> persist_car_service::list_files(std::string folder_name)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
|
|
|
std::vector<std::string> file_paths;
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
const auto file_path = check_vehicle_folder(folder_name);
|
2022-07-28 20:42:57 +02:00
|
|
|
for (const auto& directory_entry : std::filesystem::directory_iterator(file_path.get_path()))
|
|
|
|
if (directory_entry.path().extension() == ".json")
|
|
|
|
file_paths.push_back(directory_entry.path().filename().generic_string());
|
|
|
|
|
|
|
|
return file_paths;
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
std::vector<std::string> persist_car_service::list_sub_folders()
|
|
|
|
{
|
|
|
|
std::vector<std::string> folders;
|
|
|
|
|
|
|
|
const auto file_path = check_vehicle_folder();
|
|
|
|
for (const auto& directory_entry : std::filesystem::directory_iterator(file_path.get_path()))
|
|
|
|
if (directory_entry.is_directory())
|
|
|
|
folders.push_back(directory_entry.path().filename().generic_string());
|
|
|
|
|
|
|
|
return folders;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2022-07-28 20:42:57 +02:00
|
|
|
Vehicle persist_car_service::clone_ped_car(Ped ped, Vehicle vehicle)
|
|
|
|
{
|
|
|
|
return spawn_vehicle_full(get_full_vehicle_json(vehicle), ped);
|
|
|
|
}
|
|
|
|
|
|
|
|
Vehicle persist_car_service::spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped)
|
|
|
|
{
|
|
|
|
const auto vehicle = spawn_vehicle(vehicle_json, ped);
|
|
|
|
|
|
|
|
if (!vehicle_json[tow_key].is_null())
|
|
|
|
{
|
|
|
|
const auto tow = spawn_vehicle(vehicle_json[tow_key], ped);
|
|
|
|
|
|
|
|
auto pos = ENTITY::GET_ENTITY_COORDS(tow, true);
|
|
|
|
pos.x -= 10;
|
|
|
|
|
|
|
|
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(tow, pos.x, pos.y, 0.f, true, true, false);
|
|
|
|
|
|
|
|
VEHICLE::ATTACH_VEHICLE_TO_TOW_TRUCK(vehicle, tow, -1, 0.f, 0.5f, 0.f);
|
|
|
|
VEHICLE::SET_VEHICLE_TOW_TRUCK_ARM_POSITION(vehicle, 1.f);
|
|
|
|
|
|
|
|
const auto rotation = ENTITY::GET_ENTITY_ROTATION(tow, 2);
|
|
|
|
ENTITY::SET_ENTITY_ROTATION(tow, 0, 0, rotation.z, 2, true);
|
|
|
|
}
|
|
|
|
else if (!vehicle_json[trailer_key].is_null())
|
|
|
|
{
|
|
|
|
const auto trailer = spawn_vehicle(vehicle_json[trailer_key], ped);
|
|
|
|
VEHICLE::ATTACH_VEHICLE_TO_TRAILER(vehicle, trailer, 1.0f);
|
|
|
|
|
|
|
|
const auto rotation = ENTITY::GET_ENTITY_ROTATION(trailer, 2);
|
|
|
|
ENTITY::SET_ENTITY_ROTATION(trailer, 0, 0, rotation.z, 2, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto rotation = ENTITY::GET_ENTITY_ROTATION(vehicle, 2);
|
|
|
|
ENTITY::SET_ENTITY_ROTATION(vehicle, rotation.x, 0, rotation.z, 2, true);
|
|
|
|
|
|
|
|
return vehicle;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vehicle persist_car_service::spawn_vehicle(nlohmann::json vehicle_json, Ped ped)
|
|
|
|
{
|
|
|
|
const auto vehicle = spawn_vehicle_json(vehicle_json, ped);
|
|
|
|
|
|
|
|
std::vector<nlohmann::json> model_attachments = vehicle_json[model_attachments_key];
|
|
|
|
for (const auto& j : model_attachments)
|
|
|
|
{
|
|
|
|
const auto attachment = j.get<model_attachment>();
|
2023-03-01 21:27:15 +00:00
|
|
|
const auto object = world_model::spawn(attachment.model_hash);
|
2022-09-20 14:51:43 +02:00
|
|
|
if (object)
|
|
|
|
{
|
2023-03-01 21:27:15 +00:00
|
|
|
ENTITY::ATTACH_ENTITY_TO_ENTITY(object,
|
|
|
|
vehicle,
|
|
|
|
0,
|
|
|
|
attachment.position.x,
|
|
|
|
attachment.position.y,
|
|
|
|
attachment.position.z,
|
|
|
|
attachment.rotation.x,
|
|
|
|
attachment.rotation.y,
|
|
|
|
attachment.rotation.z,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
true,
|
|
|
|
0);
|
2022-10-18 15:08:05 -04:00
|
|
|
|
|
|
|
ENTITY::SET_ENTITY_VISIBLE(object, attachment.is_visible, 0);
|
|
|
|
ENTITY::SET_ENTITY_COLLISION(object, attachment.has_collision, true);
|
|
|
|
ENTITY::SET_ENTITY_INVINCIBLE(object, attachment.is_invincible);
|
2022-09-20 14:51:43 +02:00
|
|
|
}
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<nlohmann::json> vehicle_attachments = vehicle_json[vehicle_attachments_key];
|
|
|
|
for (const auto& j : vehicle_attachments)
|
|
|
|
{
|
|
|
|
const auto vehicle_to_attach = spawn_vehicle_json(j[vehicle_key], ped);
|
2023-03-01 21:27:15 +00:00
|
|
|
auto attachment = j[model_attachment_key].get<big::model_attachment>();
|
|
|
|
ENTITY::ATTACH_ENTITY_TO_ENTITY(vehicle_to_attach,
|
|
|
|
vehicle,
|
|
|
|
0,
|
|
|
|
attachment.position.x,
|
|
|
|
attachment.position.y,
|
|
|
|
attachment.position.z,
|
|
|
|
attachment.rotation.x,
|
|
|
|
attachment.rotation.y,
|
|
|
|
attachment.rotation.z,
|
|
|
|
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
false,
|
|
|
|
0,
|
|
|
|
true,
|
|
|
|
0);
|
|
|
|
|
2022-11-16 21:31:12 +02:00
|
|
|
ENTITY::SET_ENTITY_VISIBLE(vehicle_to_attach, attachment.is_visible, 0);
|
|
|
|
ENTITY::SET_ENTITY_COLLISION(vehicle_to_attach, attachment.has_collision, true);
|
|
|
|
ENTITY::SET_ENTITY_INVINCIBLE(vehicle_to_attach, attachment.is_invincible);
|
2023-02-13 20:38:30 +00:00
|
|
|
VEHICLE::SET_VEHICLE_IS_CONSIDERED_BY_PLAYER(vehicle_to_attach, false);
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return vehicle;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped)
|
|
|
|
{
|
|
|
|
const Hash vehicle_hash = vehicle_json[vehicle_model_hash_key];
|
|
|
|
|
|
|
|
const auto pos = ENTITY::GET_ENTITY_COORDS(self::ped, true);
|
|
|
|
|
|
|
|
const auto vehicle = big::vehicle::spawn(vehicle_hash, pos, ENTITY::GET_ENTITY_HEADING(ped));
|
|
|
|
|
|
|
|
VEHICLE::SET_VEHICLE_DIRT_LEVEL(vehicle, 0.0f);
|
|
|
|
VEHICLE::SET_VEHICLE_MOD_KIT(vehicle, 0);
|
|
|
|
VEHICLE::SET_VEHICLE_TYRES_CAN_BURST(vehicle, false);
|
|
|
|
VEHICLE::SET_VEHICLE_COLOURS(vehicle, vehicle_json[primary_color_key], vehicle_json[secondary_color_key]);
|
|
|
|
|
|
|
|
if (!vehicle_json[custom_primary_color_key].is_null())
|
|
|
|
{
|
|
|
|
std::vector<int> primary_custom_color = vehicle_json[custom_primary_color_key];
|
|
|
|
VEHICLE::SET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, primary_custom_color[0], primary_custom_color[1], primary_custom_color[2]);
|
|
|
|
}
|
|
|
|
|
2022-10-18 15:08:05 -04:00
|
|
|
if (!vehicle_json[is_visible_key].is_null())
|
|
|
|
{
|
|
|
|
bool is_visible = vehicle_json[is_visible_key];
|
|
|
|
ENTITY::SET_ENTITY_VISIBLE(vehicle, is_visible, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vehicle_json[has_collision_key].is_null())
|
|
|
|
{
|
|
|
|
bool has_collision = vehicle_json[has_collision_key];
|
|
|
|
ENTITY::SET_ENTITY_COLLISION(vehicle, has_collision, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vehicle_json[is_invincible_key].is_null())
|
|
|
|
{
|
|
|
|
bool is_invincible = vehicle_json[is_invincible_key];
|
|
|
|
ENTITY::SET_ENTITY_INVINCIBLE(vehicle, is_invincible);
|
|
|
|
}
|
|
|
|
|
2022-07-28 20:42:57 +02:00
|
|
|
if (!vehicle_json[custom_secondary_color_key].is_null())
|
|
|
|
{
|
|
|
|
std::vector<int> secondary_custom_color = vehicle_json[custom_secondary_color_key];
|
|
|
|
VEHICLE::SET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, secondary_custom_color[0], secondary_custom_color[1], secondary_custom_color[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
VEHICLE::SET_VEHICLE_WINDOW_TINT(vehicle, vehicle_json[vehicle_window_tint_key]);
|
|
|
|
|
|
|
|
if (!vehicle_json[radio_station_key].is_null())
|
|
|
|
AUDIO::SET_VEH_RADIO_STATION(vehicle, vehicle_json[radio_station_key].get<std::string>().c_str());
|
|
|
|
|
|
|
|
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT(vehicle, vehicle_json[plate_text_key].get<std::string>().c_str());
|
|
|
|
VEHICLE::SET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle, vehicle_json[plate_text_index_key]);
|
|
|
|
VEHICLE::SET_VEHICLE_EXTRA_COLOURS(vehicle, vehicle_json[pearlescent_color_key], vehicle_json[wheel_color_key]);
|
|
|
|
|
|
|
|
std::map<int, bool> vehicle_extras = vehicle_json[vehicle_extras_key];
|
2023-08-25 02:53:24 -04:00
|
|
|
for (const auto& [extra, extra_enabled] : vehicle_extras)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-08-25 02:53:24 -04:00
|
|
|
VEHICLE::SET_VEHICLE_EXTRA(vehicle, extra, extra_enabled);
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!vehicle_json[vehicle_livery_key].is_null())
|
|
|
|
{
|
|
|
|
VEHICLE::SET_VEHICLE_LIVERY(vehicle, vehicle_json[vehicle_livery_key]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VEHICLE::IS_THIS_MODEL_A_CAR(ENTITY::GET_ENTITY_MODEL(vehicle)) || VEHICLE::IS_THIS_MODEL_A_BIKE(ENTITY::GET_ENTITY_MODEL(vehicle)))
|
|
|
|
{
|
|
|
|
VEHICLE::SET_VEHICLE_WHEEL_TYPE(vehicle, vehicle_json[wheel_type_key]);
|
2022-08-31 00:16:07 +08:00
|
|
|
for (int i = MOD_SPOILERS; i < MOD_LIGHTBAR; i++)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
|
|
|
const bool has_mod = !vehicle_json[mod_names[i]].is_null();
|
|
|
|
if (has_mod)
|
|
|
|
{
|
|
|
|
if (i == MOD_TYRE_SMOKE)
|
|
|
|
{
|
|
|
|
std::vector<int> tire_smoke_color = vehicle_json[tire_smoke_color_key];
|
|
|
|
VEHICLE::SET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, tire_smoke_color[0], tire_smoke_color[1], tire_smoke_color[2]);
|
|
|
|
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, MOD_TYRE_SMOKE, true);
|
|
|
|
}
|
|
|
|
else if (vehicle_json[mod_names[i]].is_array())
|
|
|
|
{
|
|
|
|
std::vector<int> mod = vehicle_json[mod_names[i]];
|
|
|
|
VEHICLE::SET_VEHICLE_MOD(vehicle, i, mod[0], mod[1]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VEHICLE::TOGGLE_VEHICLE_MOD(vehicle, i, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::vector<bool> neon_lights = vehicle_json[neon_lights_key];
|
|
|
|
for (int i = NEON_LEFT; i <= NEON_BACK; i++)
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::SET_VEHICLE_NEON_ENABLED(vehicle, i, neon_lights[i]);
|
2022-07-28 20:42:57 +02:00
|
|
|
std::vector<int> neon_color = vehicle_json[neon_color_key];
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::SET_VEHICLE_NEON_COLOUR(vehicle, neon_color[0], neon_color[1], neon_color[2]);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
if (VEHICLE::IS_VEHICLE_A_CONVERTIBLE(vehicle, 0))
|
|
|
|
{
|
|
|
|
int convertable_state = vehicle_json[convertable_state_key];
|
|
|
|
if (convertable_state == 0 || convertable_state == 3 || convertable_state == 5)
|
|
|
|
VEHICLE::RAISE_CONVERTIBLE_ROOF(vehicle, true);
|
|
|
|
else
|
|
|
|
VEHICLE::LOWER_CONVERTIBLE_ROOF(vehicle, true);
|
|
|
|
}
|
|
|
|
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_5(vehicle, vehicle_json[interior_color_key]);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::SET_VEHICLE_EXTRA_COLOUR_6(vehicle, vehicle_json[dash_color_key]);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
const BOOL have_clan_logo = vehicle_json[clan_logo_key];
|
|
|
|
if (have_clan_logo)
|
|
|
|
vehicle_helper::add_clan_logo_to_vehicle(vehicle, ped);
|
|
|
|
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::SET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle, vehicle_json[headlight_color_key]);
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return vehicle;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json persist_car_service::get_full_vehicle_json(Vehicle vehicle)
|
|
|
|
{
|
|
|
|
// The car needs to be rotated at (0, 0, 0) for the relative offset calculations to be accurate.
|
|
|
|
ENTITY::SET_ENTITY_ROTATION(vehicle, 0, 0, 0, 0, true);
|
|
|
|
script::get_current()->yield();
|
|
|
|
ENTITY::SET_ENTITY_ROTATION(vehicle, 0, 0, 0, 0, true);
|
|
|
|
|
|
|
|
nlohmann::json vehicle_json = get_vehicle_json(vehicle);
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[model_attachments_key] = get_model_attachments(vehicle);
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[vehicle_attachments_key] = get_vehicle_attachents(vehicle);
|
|
|
|
|
|
|
|
Vehicle tow = VEHICLE::GET_ENTITY_ATTACHED_TO_TOW_TRUCK(vehicle);
|
|
|
|
if (ENTITY::DOES_ENTITY_EXIST(tow))
|
|
|
|
{
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[tow_key] = get_vehicle_json(tow);
|
|
|
|
vehicle_json[tow_key][model_attachments_key] = get_model_attachments(tow, true);
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[tow_key][vehicle_attachments_key] = get_vehicle_attachents(tow);
|
|
|
|
}
|
|
|
|
if (VEHICLE::IS_VEHICLE_ATTACHED_TO_TRAILER(vehicle))
|
|
|
|
{
|
|
|
|
Vehicle trailer;
|
|
|
|
VEHICLE::GET_VEHICLE_TRAILER_VEHICLE(vehicle, &trailer);
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[trailer_key] = get_vehicle_json(trailer);
|
|
|
|
vehicle_json[trailer_key][model_attachments_key] = get_model_attachments(trailer);
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[trailer_key][vehicle_attachments_key] = get_vehicle_attachents(trailer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return vehicle_json;
|
|
|
|
}
|
|
|
|
|
|
|
|
model_attachment persist_car_service::get_model_attachment(Vehicle vehicle, Object object)
|
|
|
|
{
|
|
|
|
const auto object_location = ENTITY::GET_ENTITY_COORDS(object, 0);
|
2023-03-01 21:27:15 +00:00
|
|
|
const auto location = ENTITY::GET_OFFSET_FROM_ENTITY_GIVEN_WORLD_COORDS(vehicle,
|
|
|
|
object_location.x,
|
|
|
|
object_location.y,
|
|
|
|
object_location.z);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
const auto object_rotation = ENTITY::GET_ENTITY_ROTATION(object, 0);
|
2022-07-28 20:42:57 +02:00
|
|
|
const auto vehicle_rotation = ENTITY::GET_ENTITY_ROTATION(vehicle, 0);
|
2023-03-01 21:27:15 +00:00
|
|
|
bool has_collision = ENTITY::GET_ENTITY_COLLISION_DISABLED(object);
|
|
|
|
bool is_visible = ENTITY::IS_ENTITY_VISIBLE(object);
|
2023-04-14 18:54:07 +02:00
|
|
|
CObject* cobject = (CObject*)g_pointers->m_gta.m_handle_to_ptr(vehicle);
|
2023-03-01 21:27:15 +00:00
|
|
|
bool is_invincible = misc::has_bit_set(&(int&)cobject->m_damage_bits, 8);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
Vector3 rotation;
|
|
|
|
rotation.x = (object_rotation.x - vehicle_rotation.x);
|
|
|
|
rotation.y = (object_rotation.y - vehicle_rotation.y);
|
|
|
|
rotation.z = (object_rotation.z - vehicle_rotation.z);
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
model_attachment attachment = {ENTITY::GET_ENTITY_MODEL(object), location, rotation, !has_collision, is_visible, is_invincible};
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
return attachment;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json persist_car_service::get_model_attachments(Vehicle vehicle, bool is_towed_vehicle)
|
|
|
|
{
|
|
|
|
std::vector<nlohmann::json> attached_objects;
|
|
|
|
|
2023-04-16 18:28:49 +00:00
|
|
|
for (auto obj : pools::get_all_props())
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-04-16 18:28:49 +00:00
|
|
|
const auto object = g_pointers->m_gta.m_ptr_to_handle(obj);
|
2022-07-28 20:42:57 +02:00
|
|
|
if (!object)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!ENTITY::IS_ENTITY_ATTACHED_TO_ENTITY(vehicle, object))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't save tow hook.
|
2023-04-16 18:28:49 +00:00
|
|
|
if (is_towed_vehicle && ENTITY::GET_ENTITY_MODEL(object) == RAGE_JOAAT("prop_v_hook_s"))
|
2022-07-28 20:42:57 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
attached_objects.push_back(get_model_attachment(vehicle, object));
|
|
|
|
};
|
|
|
|
|
|
|
|
return attached_objects;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json persist_car_service::get_vehicle_attachents(Vehicle vehicle)
|
|
|
|
{
|
|
|
|
std::vector<nlohmann::json> attached_vehicles;
|
|
|
|
|
|
|
|
Vehicle trailer;
|
|
|
|
VEHICLE::GET_VEHICLE_TRAILER_VEHICLE(vehicle, &trailer);
|
|
|
|
|
2023-04-16 18:28:49 +00:00
|
|
|
for (auto veh : pools::get_all_vehicles())
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-04-16 18:28:49 +00:00
|
|
|
const auto object = g_pointers->m_gta.m_ptr_to_handle(veh);
|
2022-07-28 20:42:57 +02:00
|
|
|
if (!object)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!ENTITY::IS_ENTITY_ATTACHED_TO_ENTITY(vehicle, object))
|
|
|
|
continue;
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
if (object == VEHICLE::GET_ENTITY_ATTACHED_TO_TOW_TRUCK(vehicle) || VEHICLE::IS_VEHICLE_ATTACHED_TO_TOW_TRUCK(object, vehicle))
|
2022-07-28 20:42:57 +02:00
|
|
|
continue;
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
if (object == trailer || VEHICLE::IS_VEHICLE_ATTACHED_TO_TRAILER(object))
|
2022-07-28 20:42:57 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
nlohmann::json model_attachment;
|
2023-03-01 21:27:15 +00:00
|
|
|
model_attachment[vehicle_key] = get_vehicle_json(object);
|
2022-07-28 20:42:57 +02:00
|
|
|
model_attachment[model_attachment_key] = get_model_attachment(vehicle, object);
|
|
|
|
|
|
|
|
attached_vehicles.push_back(model_attachment);
|
|
|
|
}
|
|
|
|
|
|
|
|
return attached_vehicles;
|
|
|
|
}
|
|
|
|
|
|
|
|
nlohmann::json persist_car_service::get_vehicle_json(Vehicle vehicle)
|
|
|
|
{
|
|
|
|
nlohmann::json vehicle_json;
|
|
|
|
|
|
|
|
vehicle_json[vehicle_model_hash_key] = ENTITY::GET_ENTITY_MODEL(vehicle);
|
|
|
|
|
|
|
|
int primary_color, secondary_color;
|
|
|
|
VEHICLE::GET_VEHICLE_COLOURS(vehicle, &primary_color, &secondary_color);
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[primary_color_key] = primary_color;
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[secondary_color_key] = secondary_color;
|
|
|
|
if (VEHICLE::GET_IS_VEHICLE_PRIMARY_COLOUR_CUSTOM(vehicle))
|
|
|
|
{
|
|
|
|
int custom_primary_color[3]{};
|
|
|
|
VEHICLE::GET_VEHICLE_CUSTOM_PRIMARY_COLOUR(vehicle, &custom_primary_color[0], &custom_primary_color[1], &custom_primary_color[2]);
|
|
|
|
vehicle_json[custom_primary_color_key] = custom_primary_color;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VEHICLE::GET_IS_VEHICLE_SECONDARY_COLOUR_CUSTOM(vehicle))
|
|
|
|
{
|
|
|
|
int custom_secondary_color[3]{};
|
|
|
|
VEHICLE::GET_VEHICLE_CUSTOM_SECONDARY_COLOUR(vehicle, &custom_secondary_color[0], &custom_secondary_color[1], &custom_secondary_color[2]);
|
|
|
|
vehicle_json[custom_secondary_color_key] = custom_secondary_color;
|
|
|
|
}
|
|
|
|
|
|
|
|
vehicle_json[vehicle_window_tint_key] = VEHICLE::GET_VEHICLE_WINDOW_TINT(vehicle);
|
|
|
|
|
|
|
|
auto radio_station = AUDIO::GET_PLAYER_RADIO_STATION_NAME();
|
|
|
|
|
|
|
|
if (!radio_station)
|
|
|
|
radio_station = "OFF";
|
|
|
|
|
|
|
|
vehicle_json[radio_station_key] = radio_station;
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[plate_text_key] = VEHICLE::GET_VEHICLE_NUMBER_PLATE_TEXT(vehicle);
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[plate_text_index_key] = VEHICLE::GET_VEHICLE_NUMBER_PLATE_TEXT_INDEX(vehicle);
|
|
|
|
|
|
|
|
int pearlescent_color, wheel_color;
|
|
|
|
VEHICLE::GET_VEHICLE_EXTRA_COLOURS(vehicle, &pearlescent_color, &wheel_color);
|
|
|
|
|
|
|
|
vehicle_json[pearlescent_color_key] = pearlescent_color;
|
2023-03-01 21:27:15 +00:00
|
|
|
bool has_collision = ENTITY::GET_ENTITY_COLLISION_DISABLED(vehicle);
|
|
|
|
bool is_visible = ENTITY::IS_ENTITY_VISIBLE(vehicle);
|
2023-04-14 18:54:07 +02:00
|
|
|
CVehicle* cvehicle = (CVehicle*)g_pointers->m_gta.m_handle_to_ptr(vehicle);
|
2023-03-01 21:27:15 +00:00
|
|
|
bool is_invincible = misc::has_bit_set(&(int&)cvehicle->m_damage_bits, 8);
|
|
|
|
vehicle_json[has_collision_key] = !has_collision;
|
|
|
|
vehicle_json[is_visible_key] = is_visible;
|
|
|
|
vehicle_json[is_invincible_key] = is_invincible;
|
|
|
|
vehicle_json[wheel_color_key] = wheel_color;
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
std::map<int, bool> vehicle_extras;
|
2023-08-25 02:53:24 -04:00
|
|
|
for (int extra_iterator = 0; extra_iterator <= 14; extra_iterator++)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-08-25 02:53:24 -04:00
|
|
|
if (VEHICLE::DOES_EXTRA_EXIST(vehicle, extra_iterator))
|
|
|
|
{
|
|
|
|
vehicle_extras[extra_iterator] = !VEHICLE::IS_VEHICLE_EXTRA_TURNED_ON(vehicle, extra_iterator);
|
|
|
|
}
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
vehicle_json[vehicle_extras_key] = vehicle_extras;
|
|
|
|
|
|
|
|
if ((VEHICLE::GET_VEHICLE_LIVERY_COUNT(vehicle) > 1) && VEHICLE::GET_VEHICLE_LIVERY(vehicle) >= 0)
|
|
|
|
{
|
|
|
|
vehicle_json[vehicle_livery_key] = VEHICLE::GET_VEHICLE_LIVERY(vehicle);
|
|
|
|
}
|
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
if (VEHICLE::IS_THIS_MODEL_A_CAR(ENTITY::GET_ENTITY_MODEL(vehicle)) || VEHICLE::IS_THIS_MODEL_A_BIKE(ENTITY::GET_ENTITY_MODEL(vehicle)))
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
|
|
|
vehicle_json[wheel_type_key] = VEHICLE::GET_VEHICLE_WHEEL_TYPE(vehicle);
|
|
|
|
|
|
|
|
for (int i = MOD_SPOILERS; i <= MOD_LIVERY; i++)
|
|
|
|
{
|
|
|
|
const auto is_mod_on = VEHICLE::IS_TOGGLE_MOD_ON(vehicle, i);
|
|
|
|
if (is_mod_on)
|
|
|
|
{
|
|
|
|
if (i == MOD_TYRE_SMOKE)
|
|
|
|
{
|
|
|
|
int tire_smoke_color[3]{};
|
|
|
|
VEHICLE::GET_VEHICLE_TYRE_SMOKE_COLOR(vehicle, &tire_smoke_color[0], &tire_smoke_color[1], &tire_smoke_color[2]);
|
|
|
|
vehicle_json[tire_smoke_color_key] = tire_smoke_color;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vehicle_json[mod_names[i]] = "TOGGLE";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VEHICLE::GET_VEHICLE_MOD(vehicle, i) != -1)
|
|
|
|
{
|
2023-03-01 21:27:15 +00:00
|
|
|
int vehicle_mod[2] = {VEHICLE::GET_VEHICLE_MOD(vehicle, i), VEHICLE::GET_VEHICLE_MOD_VARIATION(vehicle, i)};
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[mod_names[i]] = vehicle_mod;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool neon_lights[4]{};
|
|
|
|
for (int i = NEON_LEFT; i <= NEON_BACK; i++)
|
2022-09-20 14:03:19 +01:00
|
|
|
neon_lights[i] = VEHICLE::GET_VEHICLE_NEON_ENABLED(vehicle, i);
|
2022-07-28 20:42:57 +02:00
|
|
|
|
|
|
|
int neon_color[3]{};
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::GET_VEHICLE_NEON_COLOUR(vehicle, &neon_color[0], &neon_color[1], &neon_color[2]);
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[neon_color_key] = neon_color;
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[neon_lights_key] = neon_lights;
|
|
|
|
|
|
|
|
if (VEHICLE::IS_VEHICLE_A_CONVERTIBLE(vehicle, 0))
|
|
|
|
vehicle_json[convertable_state_key] = VEHICLE::GET_CONVERTIBLE_ROOF_STATE(vehicle);
|
|
|
|
|
|
|
|
int interior_color, dashboard_color;
|
2022-09-20 14:03:19 +01:00
|
|
|
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_5(vehicle, &interior_color);
|
|
|
|
VEHICLE::GET_VEHICLE_EXTRA_COLOUR_6(vehicle, &dashboard_color);
|
2022-07-28 20:42:57 +02:00
|
|
|
vehicle_json[interior_color_key] = interior_color;
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[dash_color_key] = dashboard_color;
|
2022-07-28 20:42:57 +02:00
|
|
|
|
2023-03-01 21:27:15 +00:00
|
|
|
vehicle_json[clan_logo_key] = GRAPHICS::DOES_VEHICLE_HAVE_CREW_EMBLEM(vehicle, 0);
|
2022-09-20 14:03:19 +01:00
|
|
|
vehicle_json[headlight_color_key] = VEHICLE::GET_VEHICLE_XENON_LIGHT_COLOR_INDEX(vehicle);
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return vehicle_json;
|
|
|
|
}
|
|
|
|
|
2023-08-27 15:32:14 -04:00
|
|
|
big::folder persist_car_service::check_vehicle_folder(std::string folder_name)
|
2022-07-28 20:42:57 +02:00
|
|
|
{
|
2023-08-27 15:32:14 -04:00
|
|
|
return g_file_manager.get_project_folder("./saved_json_vehicles/" + folder_name);
|
2022-07-28 20:42:57 +02:00
|
|
|
}
|
|
|
|
}
|