diff --git a/src/backend/commands/spawn/spawn_vehicle.cpp b/src/backend/commands/spawn/spawn_vehicle.cpp index 03dd0584..f7ec4755 100644 --- a/src/backend/commands/spawn/spawn_vehicle.cpp +++ b/src/backend/commands/spawn/spawn_vehicle.cpp @@ -25,8 +25,8 @@ namespace big virtual void execute(const command_arguments& args, const std::shared_ptr ctx) override { - const auto hash = args.get(0); - if (!STREAMING::IS_MODEL_IN_CDIMAGE(hash) || !STREAMING::IS_MODEL_A_VEHICLE(hash)) + const auto hash = args.get(0); + if (!entity::request_model(hash)) { ctx->report_error("BACKEND_SPAWN_VEHICLE_INVALID_MODEL"_T.data()); return; @@ -61,8 +61,6 @@ namespace big }; spawn_vehicle g_spawn_vehicle("spawn", "GUI_TAB_SPAWN_VEHICLE", "BACKEND_SPAWN_VEHICLE_DESC", 1); - bool_command g_spawn_maxed("spawnmaxed", "SPAWN_MAXED", "SPAWN_MAXED_DESC", - g.spawn_vehicle.spawn_maxed); - bool_command g_spawn_inside("spawnin", "SPAWN_IN", "SPAWN_IN_DESC", - g.spawn_vehicle.spawn_inside); + bool_command g_spawn_maxed("spawnmaxed", "SPAWN_MAXED", "SPAWN_MAXED_DESC", g.spawn_vehicle.spawn_maxed); + bool_command g_spawn_inside("spawnin", "SPAWN_IN", "SPAWN_IN_DESC", g.spawn_vehicle.spawn_inside); } diff --git a/src/byte_patch_manager.cpp b/src/byte_patch_manager.cpp index e64bb042..a92fe865 100644 --- a/src/byte_patch_manager.cpp +++ b/src/byte_patch_manager.cpp @@ -7,6 +7,7 @@ #include "util/explosion_anti_cheat_bypass.hpp" #include "util/police.hpp" #include "util/vehicle.hpp" +#include "util/world_model.hpp" extern "C" void sound_overload_detour(); uint64_t g_sound_overload_ret_addr; @@ -21,6 +22,10 @@ namespace big police::m_max_wanted_level_2 = memory::byte_patch::make(g_pointers->m_gta.m_max_wanted_level.add(14).rip().as(), 0).get(); + // Patch World Model Spawn Bypass + world_model_bypass::m_world_model_spawn_bypass = + memory::byte_patch::make(g_pointers->m_gta.m_world_model_spawn_bypass.as(), 0).get(); + // Patch blocked explosions explosion_anti_cheat_bypass::m_can_blame_others = memory::byte_patch::make(g_pointers->m_gta.m_blame_explode.as(), 0xE990).get(); @@ -98,4 +103,4 @@ namespace big g_byte_patch_manager = nullptr; } -} \ No newline at end of file +} diff --git a/src/gta_pointers.hpp b/src/gta_pointers.hpp index 1eaa42f8..37dac3f1 100644 --- a/src/gta_pointers.hpp +++ b/src/gta_pointers.hpp @@ -42,6 +42,8 @@ namespace big { memory::handle m_max_wanted_level; + memory::handle m_world_model_spawn_bypass; + memory::handle m_blame_explode; memory::handle m_explosion_patch; @@ -100,7 +102,6 @@ namespace big float* m_gravity_level; functions::set_gravity_level m_set_gravity_level; - PVOID m_world_model_spawn_bypass; PVOID m_native_return; PVOID m_get_label_text; functions::check_chat_profanity* m_check_chat_profanity; @@ -363,4 +364,4 @@ namespace big }; #pragma pack(pop) static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned"); -} \ No newline at end of file +} diff --git a/src/pointers.cpp b/src/pointers.cpp index 202f97f3..d5ec644e 100644 --- a/src/pointers.cpp +++ b/src/pointers.cpp @@ -1,8 +1,8 @@ #include "pointers.hpp" #include "gta_pointers_layout_info.hpp" -#include "sc_pointers_layout_info.hpp" #include "memory/all.hpp" +#include "sc_pointers_layout_info.hpp" namespace big { @@ -159,15 +159,6 @@ namespace big g_pointers->m_gta.m_swapchain = ptr.add(3).rip().as(); } }, - // World Model Spawn Bypass - { - "WMSB", - "48 85 C0 0F 84 ? ? ? ? 8B 48 50", - [](memory::handle ptr) - { - g_pointers->m_gta.m_world_model_spawn_bypass = ptr.as(); - } - }, // Native Return Spoofer { "NRF", @@ -1517,6 +1508,15 @@ namespace big g_pointers->m_gta.m_max_wanted_level = ptr; } }, + // World Model Spawn Bypass + { + "WMSB", + "48 85 C0 0F 84 ? ? ? ? 8B 48 50", + [](memory::handle ptr) + { + g_pointers->m_gta.m_world_model_spawn_bypass = ptr; + } + }, // Blame Explode { "BE", diff --git a/src/util/entity.cpp b/src/util/entity.cpp index 8586b066..ec74bbe8 100644 --- a/src/util/entity.cpp +++ b/src/util/entity.cpp @@ -56,7 +56,7 @@ namespace big::entity ENTITY::DELETE_ENTITY(&vehicle); } } - + ENTITY::DETACH_ENTITY(ent, 1, 1); ENTITY::SET_ENTITY_COORDS_NO_OFFSET(ent, 7000.f, 7000.f, 15.f, 0, 0, 0); if (!ENTITY::IS_ENTITY_A_MISSION_ENTITY(ent)) @@ -193,33 +193,71 @@ namespace big::entity bool load_ground_at_3dcoord(Vector3& location) { - constexpr float max_ground_check = 1000.f; - constexpr int max_attempts = 300; - float ground_z = location.z; - int current_attempts = 0; - bool found_ground; + constexpr float max_ground_check = 1000.f; + constexpr int max_attempts = 300; + float ground_z = location.z; + int current_attempts = 0; + bool found_ground; + float height; - do { - found_ground = MISC::GET_GROUND_Z_FOR_3D_COORD(location.x, location.y, max_ground_check, &ground_z, FALSE, FALSE); - STREAMING::REQUEST_COLLISION_AT_COORD(location.x, location.y, location.z); + do + { + found_ground = MISC::GET_GROUND_Z_FOR_3D_COORD(location.x, location.y, max_ground_check, &ground_z, FALSE, FALSE); + STREAMING::REQUEST_COLLISION_AT_COORD(location.x, location.y, location.z); - if (current_attempts % 10 == 0) - { - location.z += 25.f; - } + if (current_attempts % 10 == 0) + { + location.z += 25.f; + } - ++current_attempts; + ++current_attempts; - script::get_current()->yield(); - } while (!found_ground && current_attempts < max_attempts); + script::get_current()->yield(); + } while (!found_ground && current_attempts < max_attempts); - if (!found_ground) - { - return false; - } + if (!found_ground) + { + return false; + } - location.z = ground_z + 1.f; - return true; + if (WATER::GET_WATER_HEIGHT(location.x, location.y, location.z, &height)) + { + location.z = height; + } + else + { + location.z = ground_z + 1.f; + } + + return true; + } + + bool request_model(rage::joaat_t hash) + { + if (STREAMING::HAS_MODEL_LOADED(hash)) + { + return true; + } + + bool has_loaded; + + if (STREAMING::IS_MODEL_VALID(hash) && STREAMING::IS_MODEL_IN_CDIMAGE(hash)) + { + do + { + has_loaded = STREAMING::HAS_MODEL_LOADED(hash); + if (has_loaded) + break; + + STREAMING::REQUEST_MODEL(hash); + + script::get_current()->yield(); + } while (!has_loaded); + + return true; + } + + return false; } double distance_to_middle_of_screen(const rage::fvector2& screen_pos) @@ -303,4 +341,4 @@ namespace big::entity return closest_entity; } -} \ No newline at end of file +} diff --git a/src/util/entity.hpp b/src/util/entity.hpp index 42279cd5..81f44513 100644 --- a/src/util/entity.hpp +++ b/src/util/entity.hpp @@ -18,6 +18,7 @@ namespace big::entity bool network_has_control_of_entity(rage::netObject* net_object); std::vector get_entities(bool vehicles, bool peds, bool props = false, bool include_self_veh = false); bool load_ground_at_3dcoord(Vector3& location); + bool request_model(rage::joaat_t hash); double distance_to_middle_of_screen(const rage::fvector2& screen_pos); Entity get_entity_closest_to_middle_of_screen(rage::fwEntity** pointer = nullptr, std::vector ignore_entities = {}, bool include_veh = true, bool include_ped = true, bool include_prop = true, bool include_players = true); } diff --git a/src/util/ped.hpp b/src/util/ped.hpp index 95b63136..d35502c8 100644 --- a/src/util/ped.hpp +++ b/src/util/ped.hpp @@ -446,24 +446,19 @@ namespace big::ped inline bool change_player_model(const Hash hash) { - for (uint8_t i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) + if (entity::request_model(hash)) { - STREAMING::REQUEST_MODEL(hash); + self::ped = PLAYER::PLAYER_PED_ID(); + PLAYER::SET_PLAYER_MODEL(self::id, hash); script::get_current()->yield(); + STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); + for (int i = 0; i < 12; i++) + { + PED::SET_PED_COMPONENT_VARIATION(self::ped, i, PED::GET_PED_DRAWABLE_VARIATION(self::ped, i), PED::GET_PED_TEXTURE_VARIATION(self::ped, i), PED::GET_PED_PALETTE_VARIATION(self::ped, i)); + } + return true; } - if (!STREAMING::HAS_MODEL_LOADED(hash)) - { - return false; - } - PLAYER::SET_PLAYER_MODEL(self::id, hash); - self::ped = PLAYER::PLAYER_PED_ID(); - script::get_current()->yield(); - STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); - for (int i = 0; i < 12; i++) - { - PED::SET_PED_COMPONENT_VARIATION(self::ped, i, PED::GET_PED_DRAWABLE_VARIATION(self::ped, i), PED::GET_PED_TEXTURE_VARIATION(self::ped, i), PED::GET_PED_PALETTE_VARIATION(self::ped, i)); - } - return true; + return false; } inline bool steal_outfit(const Ped target) @@ -512,29 +507,22 @@ namespace big::ped inline Ped spawn(ePedType pedType, Hash hash, Hash clone, Vector3 location, float heading, bool is_networked = true) { - for (uint8_t i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) + if (entity::request_model(hash)) { - STREAMING::REQUEST_MODEL(hash); - script::get_current()->yield(); + Ped ped = PED::CREATE_PED(pedType, hash, location.x, location.y, location.z, heading, is_networked, false); + + script::get_current()->yield(); + + if (clone) + { + PED::CLONE_PED_TO_TARGET(clone, ped); + } + + STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); + + return ped; } - - if (!STREAMING::HAS_MODEL_LOADED(hash)) - { - return 0; - } - - auto ped = PED::CREATE_PED(pedType, hash, location.x, location.y, location.z, heading, is_networked, false); - - script::get_current()->yield(); - - if (clone) - { - PED::CLONE_PED_TO_TARGET(clone, ped); - } - - STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); - - return ped; + return 0; } inline void set_ped_random_component_variation(Ped ped) diff --git a/src/util/vehicle.cpp b/src/util/vehicle.cpp index 50aabeac..15216851 100644 --- a/src/util/vehicle.cpp +++ b/src/util/vehicle.cpp @@ -6,8 +6,8 @@ namespace big::vehicle { switch (speed_unit) { - case SpeedUnit::KMPH: return mps * 3.6f; break; - case SpeedUnit::MIPH: return mps * 2.2369f; break; + case SpeedUnit::KMPH: return mps * 3.6f; + case SpeedUnit::MIPH: return mps * 2.2369f; } return mps; @@ -17,8 +17,8 @@ namespace big::vehicle { switch (speed_unit) { - case SpeedUnit::KMPH: return speed / 3.6f; break; - case SpeedUnit::MIPH: return speed / 2.2369f; break; + case SpeedUnit::KMPH: return speed / 3.6f; + case SpeedUnit::MIPH: return speed / 2.2369f; } return speed; @@ -77,7 +77,7 @@ namespace big::vehicle if (driver_ped != 0) { - if (PED::GET_PED_TYPE(driver_ped) == ePedType::PED_TYPE_NETWORK_PLAYER) + if (PED::GET_PED_TYPE(driver_ped) == PED_TYPE_NETWORK_PLAYER) { TASK::CLEAR_PED_TASKS_IMMEDIATELY(driver_ped); } @@ -152,27 +152,20 @@ namespace big::vehicle Vehicle spawn(Hash hash, Vector3 location, float heading, bool is_networked, bool script_veh) { - for (int i = 0; !STREAMING::HAS_MODEL_LOADED(hash) && i < 100; i++) + if (entity::request_model(hash)) { - STREAMING::REQUEST_MODEL(hash); - script::get_current()->yield(); + auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, script_veh, false); + + STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); + + if (*g_pointers->m_gta.m_is_session_started) + { + set_mp_bitset(veh); + } + + return veh; } - - if (!STREAMING::HAS_MODEL_LOADED(hash)) - { - return 0; - } - - auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, script_veh, false); - - STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); - - if (*g_pointers->m_gta.m_is_session_started) - { - set_mp_bitset(veh); - } - - return veh; + return 0; } Vehicle clone_from_vehicle_data(std::map& data, Vector3 location, float heading) @@ -226,7 +219,7 @@ namespace big::vehicle return 0; } - auto veh = vehicle::get_closest_to_location(tmpLocation, 200); + auto veh = get_closest_to_location(tmpLocation, 200); if (veh == 0) { return 0; @@ -551,8 +544,6 @@ namespace big::vehicle void max_vehicle(Vehicle veh) { - Hash model = ENTITY::GET_ENTITY_MODEL(veh); - VEHICLE::SET_VEHICLE_MOD_KIT(veh, 0); VEHICLE::TOGGLE_VEHICLE_MOD(veh, MOD_TURBO, TRUE); @@ -688,13 +679,10 @@ namespace big::vehicle VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, i, (int)state); return VEHICLE::GET_VEHICLE_DOOR_LOCK_STATUS(veh) == (int)state; } - else - { - if (VEHICLE::GET_IS_DOOR_VALID(veh, (int)doorId)) - VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, (int)doorId, (int)state); + if (VEHICLE::GET_IS_DOOR_VALID(veh, (int)doorId)) + VEHICLE::SET_VEHICLE_INDIVIDUAL_DOORS_LOCKED(veh, (int)doorId, (int)state); - return VEHICLE::GET_VEHICLE_INDIVIDUAL_DOOR_LOCK_STATUS(veh, (int)doorId) == (int)state; - } + return VEHICLE::GET_VEHICLE_INDIVIDUAL_DOOR_LOCK_STATUS(veh, (int)doorId) == (int)state; } return false; diff --git a/src/util/world_model.hpp b/src/util/world_model.hpp index 643ed7f3..76a79254 100644 --- a/src/util/world_model.hpp +++ b/src/util/world_model.hpp @@ -3,38 +3,29 @@ #include "pointers.hpp" #include "script.hpp" +struct world_model_bypass +{ + inline static memory::byte_patch* m_world_model_spawn_bypass; +}; + namespace big::world_model { - constexpr size_t patch_size = 24; - static inline std::once_flag once_flag; - static inline std::array backup; - static inline void setup_backup() - { - memcpy(backup.data(), g_pointers->m_gta.m_world_model_spawn_bypass, patch_size); - } - inline Object spawn(Hash hash, Vector3 location = Vector3(), bool is_networked = true) { - STREAMING::REQUEST_MODEL(hash); - for (int i = 0; i < 100 && !STREAMING::HAS_MODEL_LOADED(hash); i++) + if (entity::request_model(hash)) { - script::get_current()->yield(); - } - if (!STREAMING::HAS_MODEL_LOADED(hash)) - { - LOG(WARNING) << "Failed to load model " << HEX_TO_UPPER(hash); - return 0; + world_model_bypass::m_world_model_spawn_bypass->apply(); + + const auto object = OBJECT::CREATE_OBJECT(hash, location.x, location.y, location.z, is_networked, false, false); + + world_model_bypass::m_world_model_spawn_bypass->restore(); + + STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); + + return object; } - std::call_once(once_flag, setup_backup); - memset(g_pointers->m_gta.m_world_model_spawn_bypass, 0x90, patch_size); - - const auto object = OBJECT::CREATE_OBJECT(hash, location.x, location.y, location.z, is_networked, false, false); - - memcpy(g_pointers->m_gta.m_world_model_spawn_bypass, backup.data(), patch_size); - - STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); - - return object; + LOG(WARNING) << "Failed to load model " << HEX_TO_UPPER(hash); + return 0; } }