diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 07ac611c09..837c84415d 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -1051,6 +1051,33 @@ bool CGameSA::SetBuildingPoolSize(size_t size) return status; } +void CGameSA::UnloadUnusedModels() +{ + // Unload DFF's + // CJ should not be unloaded + const std::size_t baseIdForTxd = GetBaseIDforTXD(); + for (std::size_t id = 1; id < baseIdForTxd; id++) + { + CStreamingInfo* streamingInfo = m_pStreaming->GetStreamingInfo(id); + if (streamingInfo->loadState != eModelLoadState::LOADSTATE_NOT_LOADED && streamingInfo->sizeInBlocks > 0) + { + CModelInfoSA& model = ModelInfo[id]; + if (model.GetRefCount() == 0) + model.UnloadUnused(); + }; + } + // Unload TXD + for (std::size_t id = baseIdForTxd; id < GetBaseIDforCOL(); id++) + { + CStreamingInfo* streamingInfo = m_pStreaming->GetStreamingInfo(id); + std::size_t refsCount = GetPools()->GetTxdPool().GetRefsCount(id - baseIdForTxd); + if (streamingInfo->loadState != eModelLoadState::LOADSTATE_NOT_LOADED && streamingInfo->sizeInBlocks > 0 && refsCount == 0) + { + GetStreaming()->RemoveModel(id); + } + } +} + // Ensure models have the default lod distances void CGameSA::ResetModelLodDistances() { diff --git a/Client/game_sa/CGameSA.h b/Client/game_sa/CGameSA.h index cf4788d953..8124f99843 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -310,6 +310,8 @@ class CGameSA : public CGame bool SetBuildingPoolSize(size_t size); + void UnloadUnusedModels(); + private: CPools* m_pPools; CPlayerInfo* m_pPlayerInfo; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 4bf3146d7f..c8f37cf9a8 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -442,6 +442,8 @@ void CModelInfoSA::Remove() bool CModelInfoSA::UnloadUnused() { + m_pInterface = ppModelInfo[m_dwModelID]; + if (m_pInterface->usNumberOfRefs == 0 && !m_pCustomClump && !m_pCustomColModel) { pGame->GetStreaming()->RemoveModel(m_dwModelID); @@ -1077,11 +1079,6 @@ void CModelInfoSA::ModelAddRef(EModelRequestType requestType, const char* szTag) m_dwReferences++; } -int CModelInfoSA::GetRefCount() -{ - return static_cast(m_dwReferences); -} - void CModelInfoSA::RemoveRef(bool bRemoveExtraGTARef) { // Decrement the references diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index b261bcc04a..fdadc685b8 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -397,7 +397,7 @@ class CModelInfoSA : public CModelInfo static void StaticResetAlphaTransparencies(); void ModelAddRef(EModelRequestType requestType, const char* szTag); - int GetRefCount(); + int GetRefCount() const override { return static_cast(m_dwReferences); }; void RemoveRef(bool bRemoveExtraGTARef = false); bool ForceUnload(); diff --git a/Client/game_sa/CPoolSAInterface.h b/Client/game_sa/CPoolSAInterface.h index 9f48bc63d3..f879775b3b 100644 --- a/Client/game_sa/CPoolSAInterface.h +++ b/Client/game_sa/CPoolSAInterface.h @@ -122,7 +122,7 @@ class CPoolSAInterface return !IsEmpty(index); } - B* GetObject(std::int32_t objectIndex) { return &m_pObjects[objectIndex]; } + B* GetObject(std::int32_t objectIndex) const { return &m_pObjects[objectIndex]; } uint GetObjectIndex(B* pObject) { return ((DWORD)pObject - (DWORD)m_pObjects) / sizeof(B); } diff --git a/Client/game_sa/CTxdPoolSA.cpp b/Client/game_sa/CTxdPoolSA.cpp index 248f825836..36be04fce5 100644 --- a/Client/game_sa/CTxdPoolSA.cpp +++ b/Client/game_sa/CTxdPoolSA.cpp @@ -55,3 +55,12 @@ std::uint16_t CTxdPoolSA::GetFreeTextureDictonarySlot() { return (*m_ppTxdPoolInterface)->GetFreeSlot(); } + +std::uint16_t CTxdPoolSA::GetRefsCount(std::uint16_t slot) const +{ + CTextureDictonarySAInterface* pTxd = (*m_ppTxdPoolInterface)->GetObject(slot); + if (!pTxd) + return -1; + + return pTxd->usUsagesCount; +} diff --git a/Client/game_sa/CTxdPoolSA.h b/Client/game_sa/CTxdPoolSA.h index c1f0ed8ece..daaf3a1ccb 100644 --- a/Client/game_sa/CTxdPoolSA.h +++ b/Client/game_sa/CTxdPoolSA.h @@ -25,6 +25,7 @@ class CTxdPoolSA final : public CTxdPool bool IsFreeTextureDictonarySlot(std::uint32_t uiTxdId); std::uint16_t GetFreeTextureDictonarySlot(); + std::uint16_t GetRefsCount(std::uint16_t slot) const; private: CPoolSAInterface** m_ppTxdPoolInterface; diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index bc20947eac..87bf99f03d 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -6743,6 +6743,8 @@ void CClientGame::RestreamWorld() g_pGame->GetStreaming()->RemoveBigBuildings(); g_pGame->GetStreaming()->ReinitStreaming(); + + g_pGame->UnloadUnusedModels(); } void CClientGame::ReinitMarkers() diff --git a/Client/sdk/game/CGame.h b/Client/sdk/game/CGame.h index 2314fdad0e..b3da8af6e3 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -275,4 +275,5 @@ class __declspec(novtable) CGame virtual bool SetBuildingPoolSize(size_t size) = 0; + virtual void UnloadUnusedModels() = 0; }; diff --git a/Client/sdk/game/CModelInfo.h b/Client/sdk/game/CModelInfo.h index 08cb032e4c..1938fe4f7e 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -178,7 +178,7 @@ class CModelInfo virtual void ModelAddRef(EModelRequestType requestType, const char* szTag /* = NULL*/) = 0; virtual void RemoveRef(bool bRemoveExtraGTARef = false) = 0; - virtual int GetRefCount() = 0; + virtual int GetRefCount() const = 0; virtual bool ForceUnload() = 0; virtual bool UnloadUnused() = 0; virtual void DeallocateModel() = 0; diff --git a/Client/sdk/game/CTxdPool.h b/Client/sdk/game/CTxdPool.h index 1e4ff3493b..f186d8dff9 100644 --- a/Client/sdk/game/CTxdPool.h +++ b/Client/sdk/game/CTxdPool.h @@ -19,4 +19,5 @@ class CTxdPool virtual bool IsFreeTextureDictonarySlot(std::uint32_t uiTxdID) = 0; virtual std::uint16_t GetFreeTextureDictonarySlot() = 0; + virtual std::uint16_t GetRefsCount(std::uint16_t slot) const = 0; };