diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 49343f0c9e2..95aae046f1d 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -6748,47 +6748,54 @@ bool CClientGame::TriggerBrowserRequestResultEvent(const std::unordered_setCallEvent("onClientBrowserWhitelistChange", Arguments, false); } -void CClientGame::RestreamModel(unsigned short usModel) +bool CClientGame::RestreamModel(std::uint16_t model) { // Is this a vehicle ID? - if (CClientVehicleManager::IsValidModel(usModel)) + if (CClientVehicleManager::IsValidModel(model)) { // Stream the vehicles of that model out so we have no // loaded when we do the restore. The streamer will // eventually stream them back in with async loading. - m_pManager->GetVehicleManager()->RestreamVehicles(usModel); - } + m_pManager->GetVehicleManager()->RestreamVehicles(model); + return true; + } // Is this an object ID? - else if (CClientObjectManager::IsValidModel(usModel)) + else if (CClientObjectManager::IsValidModel(model)) { - if (CClientPedManager::IsValidWeaponModel(usModel)) + if (CClientPedManager::IsValidWeaponModel(model)) { // Stream the weapon of that model out so we have no // loaded when we do the restore. The streamer will // eventually stream them back in with async loading. - m_pManager->GetPedManager()->RestreamWeapon(usModel); - m_pManager->GetPickupManager()->RestreamPickups(usModel); + m_pManager->GetPedManager()->RestreamWeapon(model); + m_pManager->GetPickupManager()->RestreamPickups(model); } // Stream the objects of that model out so we have no // loaded when we do the restore. The streamer will // eventually stream them back in with async loading. - m_pManager->GetObjectManager()->RestreamObjects(usModel); - g_pGame->GetModelInfo(usModel)->RestreamIPL(); + m_pManager->GetObjectManager()->RestreamObjects(model); + g_pGame->GetModelInfo(model)->RestreamIPL(); + + return true; } // Is this an ped ID? - else if (CClientPlayerManager::IsValidModel(usModel)) + else if (CClientPlayerManager::IsValidModel(model)) { // Stream the ped of that model out so we have no // loaded when we do the restore. The streamer will // eventually stream them back in with async loading. - m_pManager->GetPedManager()->RestreamPeds(usModel); - } - else + m_pManager->GetPedManager()->RestreamPeds(model); - // 'Restream' upgrades after model replacement to propagate visual changes with immediate effect - if (CClientObjectManager::IsValidModel(usModel) && CVehicleUpgrades::IsUpgrade(usModel)) - m_pManager->GetVehicleManager()->RestreamVehicleUpgrades(usModel); + return true; + } + // 'Restream' upgrades after model replacement to propagate visual changes with immediate effect + else if (CClientObjectManager::IsValidModel(model) && CVehicleUpgrades::IsUpgrade(model)) + { + m_pManager->GetVehicleManager()->RestreamVehicleUpgrades(model); + return true; + } + return false; } void CClientGame::RestreamWorld() @@ -6808,6 +6815,55 @@ void CClientGame::RestreamWorld() g_pGame->GetStreaming()->ReinitStreaming(); } +void CClientGame::Restream(std::optional option) +{ + if (!option.has_value()) + option = RestreamOption::ALL; + + if (option == RestreamOption::ALL || option == RestreamOption::VEHICLES) + { + for (const auto& model : m_pManager->GetModelManager()->GetModelsByType(eClientModelType::VEHICLE)) + { + g_pClientGame->GetModelCacheManager()->OnRestreamModel(model->GetModelID()); + } + + m_pManager->GetVehicleManager()->RestreamAllVehicles(); + } + + if (option == RestreamOption::ALL || option == RestreamOption::PEDS) + { + for (const auto& model : m_pManager->GetModelManager()->GetModelsByType(eClientModelType::PED)) + { + g_pClientGame->GetModelCacheManager()->OnRestreamModel(model->GetModelID()); + } + + m_pManager->GetPedManager()->RestreamAllPeds(); + } + + if (option == RestreamOption::ALL || option == RestreamOption::OBJECTS) + { + static constexpr eClientModelType restreamTypes[] = {eClientModelType::OBJECT, eClientModelType::OBJECT_DAMAGEABLE, eClientModelType::TIMED_OBJECT, + eClientModelType::CLUMP}; + + for (eClientModelType type : restreamTypes) + { + for (const auto& model : m_pManager->GetModelManager()->GetModelsByType(type)) + { + g_pClientGame->GetModelCacheManager()->OnRestreamModel(model->GetModelID()); + } + } + + m_pManager->GetObjectManager()->RestreamAllObjects(); + m_pManager->GetPickupManager()->RestreamAllPickups(); + } + + if (option == RestreamOption::ALL) + { + g_pGame->GetStreaming()->RemoveBigBuildings(); + g_pGame->GetStreaming()->ReinitStreaming(); + } +} + void CClientGame::ReinitMarkers() { g_pGame->Get3DMarkers()->ReinitMarkers(); diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index 0c33091763b..c5470b875ed 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -465,8 +465,9 @@ class CClientGame bool IsHighFloatPrecision() const; bool TriggerBrowserRequestResultEvent(const std::unordered_set& newPages); - void RestreamModel(unsigned short usModel); + bool RestreamModel(std::uint16_t model); void RestreamWorld(); + void Restream(std::optional option); void ReinitMarkers(); void OnWindowFocusChange(bool state); diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp index 7f7521452c7..c7eee93f848 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.cpp @@ -946,6 +946,13 @@ ADD_ENUM(PreloadAreaOption::COLLISIONS, "collisions") ADD_ENUM(PreloadAreaOption::ALL, "all") IMPLEMENT_ENUM_CLASS_END("preload-area-option") +IMPLEMENT_ENUM_CLASS_BEGIN(RestreamOption) +ADD_ENUM(RestreamOption::ALL, "world") +ADD_ENUM(RestreamOption::VEHICLES, "vehicles") +ADD_ENUM(RestreamOption::PEDS, "peds") +ADD_ENUM(RestreamOption::OBJECTS, "objects") +IMPLEMENT_ENUM_CLASS_END("restream-option") + IMPLEMENT_ENUM_CLASS_BEGIN(taskType) ADD_ENUM(taskType::PRIMARY_TASK, "primary") diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h index da35c0d1cc2..399cdbf2101 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionParseHelpers.h @@ -98,6 +98,7 @@ DECLARE_ENUM(ePools); DECLARE_ENUM_CLASS(WorldProperty); DECLARE_ENUM_CLASS(eModelLoadState); DECLARE_ENUM_CLASS(PreloadAreaOption); +DECLARE_ENUM_CLASS(RestreamOption); DECLARE_ENUM_CLASS(taskType); DECLARE_ENUM(eEntityType); DECLARE_ENUM_CLASS(VehicleAudioSettingProperty); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 3de38bbf76a..7803aae8efb 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -150,6 +150,9 @@ void CLuaEngineDefs::LoadFunctions() {"engineGetPoolUsedCapacity", ArgumentParser}, {"engineSetPoolCapacity", ArgumentParser}, {"enginePreloadWorldArea", ArgumentParser}, + {"engineRestreamModel", ArgumentParser}, + {"engineRestream", ArgumentParser}, + // CLuaCFunctions::AddFunction ( "engineReplaceMatchingAtomics", EngineReplaceMatchingAtomics ); // CLuaCFunctions::AddFunction ( "engineReplaceWheelAtomics", EngineReplaceWheelAtomics ); @@ -2593,3 +2596,13 @@ void CLuaEngineDefs::EnginePreloadWorldArea(CVector position, std::optionalGetStreaming()->LoadSceneCollision(&position); } + +bool CLuaEngineDefs::EngineRestreamModel(std::uint16_t modelId) +{ + return g_pClientGame->RestreamModel(modelId); +} + +void CLuaEngineDefs::EngineRestream(std::optional option) +{ + g_pClientGame->Restream(option); +} diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h index 48fa2706a41..6a107c0ded0 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h @@ -96,6 +96,8 @@ class CLuaEngineDefs : public CLuaDefs static eModelLoadState EngineStreamingGetModelLoadState(std::uint16_t modelId); static void EnginePreloadWorldArea(CVector position, std::optional option); + static bool EngineRestreamModel(std::uint16_t modelId); + static void EngineRestream(std::optional option); private: static void AddEngineColClass(lua_State* luaVM); diff --git a/Client/sdk/core/CClientBase.h b/Client/sdk/core/CClientBase.h index c4ac679ec8c..bbd8307e086 100644 --- a/Client/sdk/core/CClientBase.h +++ b/Client/sdk/core/CClientBase.h @@ -24,7 +24,7 @@ class CClientBase virtual void PreHUDRenderExecutionHandler(bool bDidUnminimize, bool bDidRecreateRenderTargets) = 0; virtual void PostFrameExecutionHandler() = 0; virtual void IdleHandler() = 0; - virtual void RestreamModel(unsigned short usModel) = 0; + virtual void RestreamModel(std::uint16_t model) = 0; virtual bool WebsiteRequestResultHandler(const std::unordered_set& newPages) = 0; diff --git a/Client/sdk/game/CStreaming.h b/Client/sdk/game/CStreaming.h index c463fb22b6f..765bfc1febf 100644 --- a/Client/sdk/game/CStreaming.h +++ b/Client/sdk/game/CStreaming.h @@ -44,6 +44,14 @@ enum class PreloadAreaOption ALL }; +enum class RestreamOption +{ + ALL = 0, + VEHICLES, + PEDS, + OBJECTS +}; + struct CStreamingInfo { uint16_t prevId = (uint16_t)-1;