diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 7632881badd..1b5f910ed52 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -3482,6 +3482,7 @@ void CClientGame::Event_OnIngame() g_pGame->GetWaterManager()->Reset(); // Deletes all custom water elements, ResetMapInfo only reverts changes to water level g_pGame->GetWaterManager()->SetWaterDrawnLast(true); m_pCamera->SetCameraClip(true, true); + g_pMultiplayer->ResetClothingCacheTime(); // Deallocate all custom models m_pManager->GetModelManager()->RemoveAll(); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp index 04a361d8a9f..a17da114cac 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.cpp @@ -86,6 +86,7 @@ void CLuaEngineDefs::LoadFunctions() {"engineRestoreCOL", EngineRestoreCOL}, {"engineReplaceModel", EngineReplaceModel}, {"engineAddClothingModel", ArgumentParser}, + {"engineSetClothingCacheTime", ArgumentParser}, {"engineRestoreModel", EngineRestoreModel}, {"engineReplaceAnimation", EngineReplaceAnimation}, {"engineRestoreAnimation", EngineRestoreAnimation}, @@ -864,6 +865,11 @@ bool CLuaEngineDefs::EngineAddClothingModel(CClientDFF* pDFF, std::string strMod return true; } +bool CLuaEngineDefs::EngineSetClothingCacheTime(std::uint32_t timeInMs) +{ + return g_pMultiplayer->SetClothingCacheTime(timeInMs); +} + int CLuaEngineDefs::EngineRestoreModel(lua_State* luaVM) { // Grab the model ID diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h index 6a107c0ded0..6160fc3a40e 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaEngineDefs.h @@ -60,6 +60,7 @@ class CLuaEngineDefs : public CLuaDefs LUA_DECLARE(EngineRestoreObjectGroupPhysicalProperties) static bool EngineAddClothingModel(CClientDFF* pDff, std::string strModelName); + static bool EngineSetClothingCacheTime(std::uint32_t timeInMs); static bool EngineAddClothingTXD(CClientTXD* pTxd, std::string strModelName); static uint EngineGetModelFlags(uint uiModelID); static bool EngineSetModelFlags(uint uiModelID, uint uiFlags, std::optional bIdeFlags); diff --git a/Client/multiplayer_sa/CMultiplayerSA.h b/Client/multiplayer_sa/CMultiplayerSA.h index e34cd0dfad0..a4e73d48332 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.h +++ b/Client/multiplayer_sa/CMultiplayerSA.h @@ -347,6 +347,8 @@ class CMultiplayerSA : public CMultiplayer virtual void GetRwResourceStats(SRwResourceStats& outStats); virtual void GetClothesCacheStats(SClothesCacheStats& outStats); + virtual void ResetClothingCacheTime(); + virtual bool SetClothingCacheTime(std::uint32_t timeInMs); virtual void SetIsMinimizedAndNotConnected(bool bIsMinimizedAndNotConnected); virtual void SetMirrorsEnabled(bool bEnabled); diff --git a/Client/multiplayer_sa/CMultiplayerSA_ClothesCache.cpp b/Client/multiplayer_sa/CMultiplayerSA_ClothesCache.cpp index 48d5f8381f5..013963c0467 100644 --- a/Client/multiplayer_sa/CMultiplayerSA_ClothesCache.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA_ClothesCache.cpp @@ -1,4 +1,4 @@ -/***************************************************************************** +/***************************************************************************** * * PROJECT: Multi Theft Auto v1.0 * LICENSE: See LICENSE in the top level directory @@ -16,6 +16,8 @@ #define CLOTHES_REF_TEST 1 // Debug clothes geometry refs +static constexpr std::uint32_t DEFAULT_CACHE_TIME = 1000; + //////////////////////////////////////////////// // // class CPedClothesDesc @@ -113,7 +115,7 @@ class CClumpStore std::vector savedClumpList; uint m_uiMaxSize; - uint m_uiMinCacheTime; + std::uint32_t m_minCacheTime; SClothesCacheStats m_Stats; int m_iCacheRevision; @@ -126,7 +128,7 @@ class CClumpStore { memset(&m_Stats, 0, sizeof(m_Stats)); m_uiMaxSize = 4; - m_uiMinCacheTime = 1000; + m_minCacheTime = DEFAULT_CACHE_TIME; m_iCacheRevision = 1; } @@ -138,30 +140,34 @@ class CClumpStore uint GetNumCached() { uint uiNumCached = 0; - for (std::vector::iterator iter = savedClumpList.begin(); iter != savedClumpList.end(); ++iter) + + if (m_minCacheTime > 0) { - SSavedClumpInfo& info = *iter; - RpGeometry* pGeometry = ((RpAtomic*)((info.pClump->atomics.root.next) - 0x8))->geometry; -#ifdef CLOTHES_REF_TEST - if (pGeometry->refs < 21) + for (std::vector::iterator iter = savedClumpList.begin(); iter != savedClumpList.end(); ++iter) { - AddReportLog(7521, SString("Clothes geometry refs below expected value: %d", pGeometry->refs)); - pGeometry->refs = 21; - } - if (pGeometry->refs == 21) + SSavedClumpInfo& info = *iter; + RpGeometry* pGeometry = ((RpAtomic*)((info.pClump->atomics.root.next) - 0x8))->geometry; +#ifdef CLOTHES_REF_TEST + if (pGeometry->refs < 21) + { + AddReportLog(7521, SString("Clothes geometry refs below expected value: %d", pGeometry->refs)); + pGeometry->refs = 21; + } + if (pGeometry->refs == 21) #else - if (pGeometry->refs == 1) + if (pGeometry->refs == 1) #endif - { - uiNumCached++; - if (!info.bUnused) { - info.timeUnused = CTickCount::Now(); - info.bUnused = true; + uiNumCached++; + if (!info.bUnused) + { + info.timeUnused = CTickCount::Now(); + info.bUnused = true; + } } + else + info.bUnused = false; } - else - info.bUnused = false; } m_Stats.uiNumTotal = savedClumpList.size(); @@ -236,7 +242,7 @@ class CClumpStore if (info.bUnused) { uint uiAge = (timeNow - info.timeUnused).ToInt(); - if (uiAge > m_uiMinCacheTime) + if (uiAge > m_minCacheTime) { if (uiAge > uiBestAge || uiBestAge == -1) { @@ -404,6 +410,52 @@ void CMultiplayerSA::GetClothesCacheStats(SClothesCacheStats& outStats) outStats = ms_clumpStore.m_Stats; } +////////////////////////////////////////////////////////////////////////////////////////// +// +// CMultiplayerSA::SetClothingCacheTime +// +// +////////////////////////////////////////////////////////////////////////////////////////// +bool CMultiplayerSA::SetClothingCacheTime(std::uint32_t timeInMs) +{ + if (timeInMs == ms_clumpStore.m_minCacheTime) + return false; + + for (auto it = ms_clumpStore.savedClumpList.begin(); it != ms_clumpStore.savedClumpList.end();) + { + CClumpStore::SSavedClumpInfo& info = *it; + +#ifdef CLOTHES_REF_TEST + RpGeometry* pGeometry = ((RpAtomic*)((info.pClump->atomics.root.next) - 0x8))->geometry; + pGeometry->refs -= 20; +#endif + RpClumpDestroy(info.pClump); + + if (info.bUnused) + ms_clumpStore.m_Stats.uiNumUnused--; + + ms_clumpStore.m_Stats.uiNumRemoved++; + + it = ms_clumpStore.savedClumpList.erase(it); + } + + ms_clumpStore.m_minCacheTime = timeInMs; + ms_clumpStore.m_Stats.uiNumTotal = ms_clumpStore.savedClumpList.size(); + + return true; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// +// CMultiplayerSA::ResetClothingCacheTime +// +// +////////////////////////////////////////////////////////////////////////////////////////// +void CMultiplayerSA::ResetClothingCacheTime() +{ + SetClothingCacheTime(DEFAULT_CACHE_TIME); +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CMultiplayerSA::InitHooks_ClothesCache diff --git a/Client/sdk/multiplayer/CMultiplayer.h b/Client/sdk/multiplayer/CMultiplayer.h index e5e591ad5d3..83eb39da8f9 100644 --- a/Client/sdk/multiplayer/CMultiplayer.h +++ b/Client/sdk/multiplayer/CMultiplayer.h @@ -455,6 +455,8 @@ class CMultiplayer virtual void GetRwResourceStats(SRwResourceStats& outStats) = 0; virtual void GetClothesCacheStats(SClothesCacheStats& outStats) = 0; + virtual void ResetClothingCacheTime() = 0; + virtual bool SetClothingCacheTime(std::uint32_t timeInMs) = 0; virtual void SetIsMinimizedAndNotConnected(bool bIsMinimizedAndNotConnected) = 0; virtual void SetMirrorsEnabled(bool bEnabled) = 0;