mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2024-12-22 20:17:24 +08:00
Redesigned the preview system entirely. (#2888)
This commit is contained in:
parent
1276c51c06
commit
d63f712e5e
@ -210,4 +210,6 @@ namespace big::functions
|
||||
using get_ped_seat = CGetPedSeatReturnClass*(*)(PVOID seat_info, CPed* ped);
|
||||
|
||||
using received_clone_remove = void (*)(CNetworkObjectMgr*, CNetGamePlayer*, CNetGamePlayer*, int16_t, uint32_t);
|
||||
|
||||
using can_create_vehicle = bool (*)();
|
||||
}
|
||||
|
@ -365,6 +365,8 @@ namespace big
|
||||
functions::received_clone_remove m_received_clone_remove;
|
||||
|
||||
CWeaponInfoManager* m_weapon_info_manager;
|
||||
|
||||
functions::can_create_vehicle m_can_create_vehicle;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned");
|
||||
|
@ -140,6 +140,8 @@ namespace big
|
||||
|
||||
detour_hook_helper::add<hooks::received_clone_remove>("RCR", g_pointers->m_gta.m_received_clone_remove);
|
||||
|
||||
detour_hook_helper::add<hooks::can_create_vehicle>("CCV", g_pointers->m_gta.m_can_create_vehicle);
|
||||
|
||||
g_hooking = this;
|
||||
}
|
||||
|
||||
|
@ -191,6 +191,8 @@ namespace big
|
||||
static bool sync_reader_serialize_vec3(void* _this, rage::fvector3* vec, float divisor, int size);
|
||||
static bool sync_reader_serialize_vec3_signed(void* _this, rage::fvector3* vec, float divisor, int size);
|
||||
static bool sync_reader_serialize_array(void* _this, void* array, int size);
|
||||
|
||||
static bool can_create_vehicle();
|
||||
};
|
||||
|
||||
class minhook_keepalive
|
||||
|
10
src/hooks/script/can_create_vehicle.cpp
Normal file
10
src/hooks/script/can_create_vehicle.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "gta/pools.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::can_create_vehicle()
|
||||
{
|
||||
return (**g_pointers->m_gta.m_vehicle_pool)->m_item_count < (**g_pointers->m_gta.m_vehicle_pool)->m_size;
|
||||
}
|
||||
}
|
@ -1772,6 +1772,15 @@ namespace big
|
||||
{
|
||||
g_pointers->m_gta.m_weapon_info_manager = ptr.add(3).rip().sub(72).as<CWeaponInfoManager*>();
|
||||
}
|
||||
},
|
||||
// Can Create Vehicle
|
||||
{
|
||||
"CCV",
|
||||
"8B 0D ? ? ? ? 39 0D ? ? ? ? 0F 9C C0",
|
||||
[](memory::handle ptr)
|
||||
{
|
||||
g_pointers->m_gta.m_can_create_vehicle = ptr.as<functions::can_create_vehicle>();
|
||||
}
|
||||
}
|
||||
>(); // don't leave a trailing comma at the end
|
||||
|
||||
|
@ -22,107 +22,92 @@ namespace big
|
||||
|
||||
void model_preview_service::show_ped(Hash hash)
|
||||
{
|
||||
m_ped_clone = 0;
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && m_ped_model_hash != hash)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ped_model_hash != hash)
|
||||
if (!m_running)
|
||||
{
|
||||
m_ped_model_hash = hash;
|
||||
|
||||
if (m_ped_model_hash != 0)
|
||||
{
|
||||
m_new_model = true;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::show_ped(Hash hash, Ped clone)
|
||||
{
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && (m_ped_model_hash != hash || m_ped_clone != clone ))
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ped_model_hash != hash || m_ped_clone != clone)
|
||||
if (!m_running)
|
||||
{
|
||||
m_ped_model_hash = hash;
|
||||
m_ped_clone = clone;
|
||||
|
||||
if (m_ped_model_hash != 0)
|
||||
{
|
||||
m_new_model = true;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle(Hash hash, bool spawn_max)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
if (m_running && m_veh_model_hash != hash)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_veh_model_hash != hash || m_veh_spawn_max != spawn_max)
|
||||
if (!m_running)
|
||||
{
|
||||
m_veh_model_hash = hash;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_model_hash != 0)
|
||||
{
|
||||
m_veh_spawn_max = spawn_max;
|
||||
m_new_model = true;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle(const std::map<int, int32_t>& owned_mods, bool spawn_max)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
|
||||
if (m_veh_spawn_max != spawn_max || m_veh_owned_mods.size() != owned_mods.size()
|
||||
|| !std::equal(m_veh_owned_mods.begin(), m_veh_owned_mods.end(), owned_mods.begin()))
|
||||
if (m_running && m_veh_model_hash != owned_mods.find(MOD_MODEL_HASH)->second)
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_running)
|
||||
{
|
||||
auto hash_item = owned_mods.find(MOD_MODEL_HASH);
|
||||
|
||||
m_veh_model_hash = hash_item->second;
|
||||
|
||||
if (m_veh_model_hash != 0)
|
||||
{
|
||||
m_veh_owned_mods.insert(owned_mods.begin(), owned_mods.end());
|
||||
m_veh_spawn_max = spawn_max;
|
||||
m_new_model = true;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::show_vehicle_persisted(std::string vehicle_name)
|
||||
{
|
||||
m_ped_model_hash = 0;
|
||||
m_ped_clone = 0;
|
||||
m_veh_model_hash = 0;
|
||||
if (m_running && m_current_persisted_vehicle_name != vehicle_name)
|
||||
{
|
||||
stop_preview();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_current_persisted_vehicle_name != vehicle_name)
|
||||
if (!m_running)
|
||||
{
|
||||
m_current_persisted_vehicle_name = vehicle_name;
|
||||
m_new_model = true;
|
||||
}
|
||||
|
||||
preview_loop();
|
||||
}
|
||||
}
|
||||
|
||||
void model_preview_service::preview_loop()
|
||||
{
|
||||
if (m_running || m_loop_running)
|
||||
if (m_running)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -130,28 +115,15 @@ namespace big
|
||||
m_running = true;
|
||||
|
||||
g_fiber_pool->queue_job([this] {
|
||||
m_loop_running = true;
|
||||
m_heading = 0;
|
||||
start_time = std::chrono::steady_clock::now();
|
||||
m_heading = 0.f;
|
||||
m_rotation_start_time = std::chrono::steady_clock::now();
|
||||
|
||||
while (g_running && m_running && g_gui->is_open() && (m_ped_model_hash || m_veh_model_hash || !m_current_persisted_vehicle_name.empty()))
|
||||
while (!m_shutdown_preview && g_running && g_gui->is_open() )
|
||||
{
|
||||
Vector3 location;
|
||||
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 5.f, -.5f);
|
||||
}
|
||||
else if (m_veh_model_hash || !m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f);
|
||||
}
|
||||
Vector3 location{};
|
||||
|
||||
if (m_current_ent == 0)
|
||||
{
|
||||
m_new_model = false;
|
||||
location.z = -10.f;
|
||||
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
m_current_ent = ped::spawn(ePedType::PED_TYPE_ARMY, m_ped_model_hash, m_ped_clone, location, 0.f, false);
|
||||
@ -174,7 +146,7 @@ namespace big
|
||||
}
|
||||
else if (!m_current_persisted_vehicle_name.empty())
|
||||
{
|
||||
m_current_ent = persist_car_service::load_vehicle(m_current_persisted_vehicle_name, g.persist_car.persist_vehicle_sub_folder, Vector3());
|
||||
m_current_ent = persist_car_service::preview_vehicle(m_current_persisted_vehicle_name, g.persist_car.persist_vehicle_sub_folder, location);
|
||||
}
|
||||
|
||||
if (m_current_ent)
|
||||
@ -191,23 +163,28 @@ namespace big
|
||||
OBJECT::SET_OBJECT_ALLOW_LOW_LOD_BUOYANCY(m_current_ent, false);
|
||||
}
|
||||
}
|
||||
else if (m_new_model)
|
||||
else
|
||||
{
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
if (m_ped_model_hash)
|
||||
{
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 5.f, -.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (const int alpha = ENTITY::GET_ENTITY_ALPHA(m_current_ent); alpha < 255)
|
||||
location = ENTITY::GET_OFFSET_FROM_ENTITY_IN_WORLD_COORDS(self::ped, 0.f, 10.f, .5f);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto alpha = ENTITY::GET_ENTITY_ALPHA(m_current_ent); alpha < 255)
|
||||
{
|
||||
ENTITY::SET_ENTITY_ALPHA(m_current_ent, std::min<int>(255, alpha + 20), false);
|
||||
}
|
||||
|
||||
ENTITY::SET_ENTITY_HEADING(m_current_ent, m_heading);
|
||||
ENTITY::SET_ENTITY_COORDS(m_current_ent, location.x, location.y, location.z, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time).count() / 1000.0; // Convert to seconds
|
||||
auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_rotation_start_time).count() / 1000.0; // Convert to seconds
|
||||
|
||||
m_heading = (elapsed_time / 10.0) * 360.0; // Rotate 360 degrees every 10 seconds
|
||||
m_heading = fmod(m_heading, 360.0); // Ensure rotation is always between 0 and 360
|
||||
@ -215,21 +192,27 @@ namespace big
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
entity::delete_entity(m_current_ent, true);
|
||||
ENTITY::DELETE_ENTITY(&m_current_ent);
|
||||
|
||||
m_current_ent = 0;
|
||||
m_ped_model_hash = 0;
|
||||
m_veh_model_hash = 0;
|
||||
m_veh_owned_mods.clear();
|
||||
m_current_persisted_vehicle_name.clear();
|
||||
m_running = false;
|
||||
m_loop_running = false;
|
||||
clear_data();
|
||||
});
|
||||
}
|
||||
|
||||
void model_preview_service::clear_data()
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
m_ped_model_hash = {};
|
||||
m_veh_model_hash = {};
|
||||
m_ped_clone = {};
|
||||
m_current_persisted_vehicle_name = {};
|
||||
m_shutdown_preview = false;
|
||||
m_running = false;
|
||||
m_current_ent = NULL;
|
||||
}
|
||||
|
||||
void model_preview_service::stop_preview()
|
||||
{
|
||||
m_veh_owned_mods.clear();
|
||||
m_running = false;
|
||||
if (m_running)
|
||||
m_shutdown_preview = true;
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,21 @@ namespace big
|
||||
{
|
||||
class model_preview_service
|
||||
{
|
||||
Entity m_current_ent = 0;
|
||||
Entity m_current_ent{};
|
||||
float m_heading{};
|
||||
|
||||
Hash m_ped_model_hash{};
|
||||
Hash m_veh_model_hash{};
|
||||
Ped m_ped_clone{};
|
||||
std::string m_current_persisted_vehicle_name;
|
||||
|
||||
Hash m_veh_model_hash = 0;
|
||||
std::map<int, int32_t> m_veh_owned_mods;
|
||||
bool m_veh_spawn_max = false;
|
||||
|
||||
Hash m_ped_model_hash = 0;
|
||||
Ped m_ped_clone = 0;
|
||||
|
||||
bool m_new_model = false;
|
||||
float m_heading = 0.f;
|
||||
bool m_loop_running = false;
|
||||
bool m_running = false;
|
||||
bool m_shutdown_preview = false;
|
||||
|
||||
std::string m_current_persisted_vehicle_name;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> start_time;
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_rotation_start_time;
|
||||
public:
|
||||
model_preview_service();
|
||||
~model_preview_service();
|
||||
@ -34,12 +31,11 @@ namespace big
|
||||
void show_vehicle(const std::map<int, int32_t>& owned_mods, bool spawn_max);
|
||||
void show_vehicle_persisted(std::string vehicle_name);
|
||||
void show_vehicle(Vehicle veh);
|
||||
void stop_preview();
|
||||
|
||||
private:
|
||||
void clear_data();
|
||||
void preview_loop();
|
||||
|
||||
public:
|
||||
void stop_preview();
|
||||
};
|
||||
|
||||
inline model_preview_service* g_model_preview_service{};
|
||||
|
@ -27,6 +27,28 @@ namespace big
|
||||
file_stream.close();
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::preview_vehicle(std::string_view file_name, std::string folder_name, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
||||
|
||||
std::ifstream file_stream(file.get_path());
|
||||
|
||||
nlohmann::json vehicle_json;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return spawn_vehicle_json(vehicle_json, self::ped, spawn_coords, true);
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::load_vehicle(std::string_view file_name, std::string folder_name, const std::optional<Vector3>& spawn_coords)
|
||||
{
|
||||
const auto file = check_vehicle_folder(folder_name).get_file(file_name);
|
||||
@ -188,16 +210,16 @@ namespace big
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords)
|
||||
Vehicle persist_car_service::spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords, bool is_preview)
|
||||
{
|
||||
const Hash vehicle_hash = vehicle_json[vehicle_model_hash_key];
|
||||
const Vector3& spawn_location = spawn_coords.has_value() ? spawn_coords.value() : vehicle::get_spawn_location(g.persist_car.spawn_inside, vehicle_hash);
|
||||
const float spawn_heading = ENTITY::GET_ENTITY_HEADING(self::ped);
|
||||
|
||||
Vehicle vehicle = self::veh;
|
||||
if (spawn_coords.has_value() || (!spawn_coords.has_value() && ENTITY::GET_ENTITY_MODEL(vehicle) != vehicle_hash))
|
||||
if (is_preview || (!is_preview && ENTITY::GET_ENTITY_MODEL(vehicle) != vehicle_hash))
|
||||
{
|
||||
vehicle = big::vehicle::spawn(vehicle_hash, spawn_location, spawn_heading);
|
||||
vehicle = big::vehicle::spawn(vehicle_hash, spawn_location, spawn_heading, !is_preview);
|
||||
|
||||
if (spawn_location.x + spawn_location.y + spawn_location.z != 0)
|
||||
script::get_current()->yield(); //This is needed to wait for the engine to instantiate things like the radio station so it won't overwrite it on the next frame.
|
||||
|
@ -13,6 +13,7 @@ namespace big
|
||||
static Vehicle clone_ped_car(Ped ped, Vehicle vehicle);
|
||||
static void save_vehicle(Vehicle vehicle, std::string_view file_name, std::string folder_name);
|
||||
static Vehicle load_vehicle(std::string_view file_name, std::string folder_name = "", const std::optional<Vector3>& = std::nullopt);
|
||||
static Vehicle preview_vehicle(std::string_view file_name, std::string folder_name = "", const std::optional<Vector3>& = std::nullopt);
|
||||
static void delete_vehicle(std::string_view file_name, std::string folder_name);
|
||||
|
||||
private:
|
||||
@ -68,7 +69,7 @@ namespace big
|
||||
|
||||
static Vehicle spawn_vehicle_full(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
static Vehicle spawn_vehicle(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt);
|
||||
static Vehicle spawn_vehicle_json(nlohmann::json vehicle_json, Ped ped, const std::optional<Vector3>& spawn_coords = std::nullopt, bool is_preview = false);
|
||||
|
||||
static nlohmann::json get_full_vehicle_json(Vehicle vehicle);
|
||||
|
||||
|
@ -26,7 +26,10 @@ namespace big::entity
|
||||
void delete_entity(Entity& ent, bool force)
|
||||
{
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(ent))
|
||||
{
|
||||
ent = NULL;
|
||||
return;
|
||||
}
|
||||
if (!force && !take_control_of(ent))
|
||||
{
|
||||
LOG(VERBOSE) << "Failed to take control of entity before deleting";
|
||||
|
@ -354,9 +354,9 @@ namespace big::vehicle
|
||||
}
|
||||
|
||||
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked)
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked, bool is_script_vehicle)
|
||||
{
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked);
|
||||
auto vehicle = spawn(owned_mods[MOD_MODEL_HASH], location, heading, is_networked, is_script_vehicle);
|
||||
if (vehicle == 0)
|
||||
{
|
||||
return 0;
|
||||
|
@ -29,7 +29,7 @@ namespace big::vehicle
|
||||
Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked = true, bool script_veh = false);
|
||||
Vehicle clone_from_vehicle_data(std::map<int, int32_t>& data, Vector3 location, float heading);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle_idx(script_global vehicle_idx);
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true);
|
||||
Vehicle clone_from_owned_mods(std::map<int, int32_t> owned_mods, Vector3 location, float heading, bool is_networked = true, bool is_script_vehicle = false);
|
||||
std::map<int, int32_t> get_owned_mods_from_vehicle(Vehicle vehicle);
|
||||
void teleport_into_vehicle(Vehicle veh);
|
||||
void max_vehicle(Vehicle veh);
|
||||
|
Loading…
Reference in New Issue
Block a user