From 5dd0aa0f707ed41fb041e3185e131fe4a031b360 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Mon, 22 Jul 2024 22:19:30 +0300 Subject: [PATCH 1/4] Make engineRestreamWorld more aggressive --- Client/game_sa/CGameSA.cpp | 15 +++++++++++++++ Client/game_sa/CGameSA.h | 2 ++ Client/game_sa/CModelInfoSA.cpp | 5 ----- Client/game_sa/CModelInfoSA.h | 2 +- Client/mods/deathmatch/logic/CClientGame.cpp | 2 ++ Client/sdk/game/CGame.h | 1 + Client/sdk/game/CModelInfo.h | 2 +- 7 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index abfb822816..572d4bcbd0 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -1053,6 +1053,21 @@ bool CGameSA::SetBuildingPoolSize(size_t size) return status; } +void CGameSA::UnloadUnusedModels() +{ + for (size_t id = 0; id < GetBaseIDforCOL(); id++) + { + CStreamingInfo* streamingInfo = m_pStreaming->GetStreamingInfo(id); + if (streamingInfo->loadState != 0 && streamingInfo->sizeInBlocks > 0) + { + if (ModelInfo[id].GetRefCount() == 0) + { + m_pStreaming->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 f22b5748f7..21a097cfc8 100644 --- a/Client/game_sa/CGameSA.h +++ b/Client/game_sa/CGameSA.h @@ -308,6 +308,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 5dc00712da..27172ab58e 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -1067,11 +1067,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 329d2e3e50..5d91087bf6 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -396,7 +396,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/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index eea07ffd33..e948645825 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -6829,6 +6829,8 @@ void CClientGame::RestreamWorld(bool removeBigBuildings) 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 215141ee23..dfc908cfb5 100644 --- a/Client/sdk/game/CGame.h +++ b/Client/sdk/game/CGame.h @@ -273,4 +273,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 440f079be6..e5d57216a8 100644 --- a/Client/sdk/game/CModelInfo.h +++ b/Client/sdk/game/CModelInfo.h @@ -177,7 +177,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 void DeallocateModel() = 0; From c171223529beabfde72d88c2347339e882f96e93 Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Wed, 21 Aug 2024 21:01:24 +0300 Subject: [PATCH 2/4] small fix --- Client/game_sa/CGameSA.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 2c05011c38..7222c8db1d 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -1051,10 +1051,10 @@ bool CGameSA::SetBuildingPoolSize(size_t size) void CGameSA::UnloadUnusedModels() { - for (size_t id = 0; id < GetBaseIDforCOL(); id++) + for (std::size_t id = 0; id < GetBaseIDforCOL(); id++) { CStreamingInfo* streamingInfo = m_pStreaming->GetStreamingInfo(id); - if (streamingInfo->loadState != 0 && streamingInfo->sizeInBlocks > 0) + if (streamingInfo->loadState != eModelLoadState::LOADSTATE_NOT_LOADED && streamingInfo->sizeInBlocks > 0) { if (ModelInfo[id].GetRefCount() == 0) { From 58247b877d0df0889dc4536965ed918e864ef24c Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Tue, 27 Aug 2024 21:06:36 +0300 Subject: [PATCH 3/4] Extract TXD pool class --- Client/game_sa/CModelInfoSA.cpp | 2 +- Client/game_sa/CPoolsSA.cpp | 41 ------------- Client/game_sa/CPoolsSA.h | 11 +--- Client/game_sa/CTxdPoolSA.cpp | 57 +++++++++++++++++++ Client/game_sa/CTxdPoolSA.h | 31 ++++++++++ Client/mods/deathmatch/logic/CClientModel.cpp | 4 +- .../deathmatch/logic/CClientModelManager.cpp | 2 +- Client/sdk/game/CPools.h | 10 +--- Client/sdk/game/CTxdPool.h | 22 +++++++ 9 files changed, 120 insertions(+), 60 deletions(-) create mode 100644 Client/game_sa/CTxdPoolSA.cpp create mode 100644 Client/game_sa/CTxdPoolSA.h create mode 100644 Client/sdk/game/CTxdPool.h diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 62e3cc4440..cf775a55ee 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -743,7 +743,7 @@ CBoundingBox* CModelInfoSA::GetBoundingBox() bool CModelInfoSA::IsValid() { if (m_dwModelID >= MODELINFO_DFF_MAX && m_dwModelID < MODELINFO_TXD_MAX) - return !pGame->GetPools()->IsFreeTextureDictonarySlot(m_dwModelID - MODELINFO_DFF_MAX); + return !pGame->GetPools()->GetTxdPool().IsFreeTextureDictonarySlot(m_dwModelID - MODELINFO_DFF_MAX); if (m_dwModelID >= pGame->GetBaseIDforTXD() && m_dwModelID < pGame->GetCountOfAllFileIDs()) return true; diff --git a/Client/game_sa/CPoolsSA.cpp b/Client/game_sa/CPoolsSA.cpp index 42c534dcaa..1aaac0b40d 100644 --- a/Client/game_sa/CPoolsSA.cpp +++ b/Client/game_sa/CPoolsSA.cpp @@ -24,9 +24,6 @@ #include "CTrailerSA.h" #include "CTrainSA.h" #include "CWorldSA.h" -#include "CKeyGenSA.h" -#include "CFileLoaderSA.h" -#include "CPtrNodeSingleListSA.h" extern CGameSA* pGame; @@ -35,7 +32,6 @@ CPoolsSA::CPoolsSA() m_ppPedPoolInterface = (CPoolSAInterface**)0xB74490; m_ppObjectPoolInterface = (CPoolSAInterface**)0xB7449C; m_ppVehiclePoolInterface = (CPoolSAInterface**)0xB74494; - m_ppTxdPoolInterface = (CPoolSAInterface**)0xC8800C; m_bGetVehicleEnabled = true; } @@ -1107,40 +1103,3 @@ void CPoolsSA::InvalidateLocalPlayerClientEntity() { m_pedPool.arrayOfClientEntities[0] = {m_pedPool.arrayOfClientEntities[0].pEntity, nullptr}; } - -unsigned int CPoolsSA::AllocateTextureDictonarySlot(uint uiSlotId, std::string& strTxdName) -{ - CTextureDictonarySAInterface* pTxd = (*m_ppTxdPoolInterface)->AllocateAt(uiSlotId); - if (!pTxd) - return -1; - - strTxdName.resize(24); - - pTxd->usUsagesCount = 0; - pTxd->hash = pGame->GetKeyGen()->GetUppercaseKey(strTxdName.c_str()); - pTxd->rwTexDictonary = nullptr; - pTxd->usParentIndex = -1; - - return (*m_ppTxdPoolInterface)->GetObjectIndex(pTxd); -} - -void CPoolsSA::RemoveTextureDictonarySlot(uint uiTxdId) -{ - if (!(*m_ppTxdPoolInterface)->IsContains(uiTxdId)) - return; - - typedef uint(__cdecl * Function_TxdReleaseSlot)(uint uiTxdId); - ((Function_TxdReleaseSlot)(0x731E90))(uiTxdId); - - (*m_ppTxdPoolInterface)->Release(uiTxdId); -} - -bool CPoolsSA::IsFreeTextureDictonarySlot(uint uiTxdId) -{ - return (*m_ppTxdPoolInterface)->IsEmpty(uiTxdId); -} - -ushort CPoolsSA::GetFreeTextureDictonarySlot() -{ - return (*m_ppTxdPoolInterface)->GetFreeSlot(); -} diff --git a/Client/game_sa/CPoolsSA.h b/Client/game_sa/CPoolsSA.h index 0e6d3d9634..5718421d6c 100644 --- a/Client/game_sa/CPoolsSA.h +++ b/Client/game_sa/CPoolsSA.h @@ -15,9 +15,9 @@ #include "CVehicleSA.h" #include "CObjectSA.h" #include "CBuildingSA.h" -#include "CTextureDictonarySA.h" #include "CBuildingsPoolSA.h" #include "CDummyPoolSA.h" +#include "CTxdPoolSA.h" #define INVALID_POOL_ARRAY_ID 0xFFFFFFFF @@ -91,14 +91,9 @@ class CPoolsSA : public CPools void ResetPedPoolCount() { m_pedPool.ulCount = 0; } void InvalidateLocalPlayerClientEntity(); - uint AllocateTextureDictonarySlot(uint uiSlotID, std::string& strTxdName); - void RemoveTextureDictonarySlot(uint uiTxdId); - bool IsFreeTextureDictonarySlot(uint uiTxdId); - - ushort GetFreeTextureDictonarySlot(); - CBuildingsPool& GetBuildingsPool() noexcept override { return m_BuildingsPool; }; CDummyPool& GetDummyPool() noexcept { return m_DummyPool; }; + CTxdPool& GetTxdPool() noexcept { return m_TxdPool; }; private: // Pools @@ -109,10 +104,10 @@ class CPoolsSA : public CPools CPoolSAInterface** m_ppPedPoolInterface; CPoolSAInterface** m_ppObjectPoolInterface; CPoolSAInterface** m_ppVehiclePoolInterface; - CPoolSAInterface** m_ppTxdPoolInterface; CBuildingsPoolSA m_BuildingsPool; CDummyPoolSA m_DummyPool; + CTxdPoolSA m_TxdPool; bool m_bGetVehicleEnabled; }; diff --git a/Client/game_sa/CTxdPoolSA.cpp b/Client/game_sa/CTxdPoolSA.cpp new file mode 100644 index 0000000000..248f825836 --- /dev/null +++ b/Client/game_sa/CTxdPoolSA.cpp @@ -0,0 +1,57 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CTxdPoolSA.h" +#include "CGameSA.h" +#include "CKeyGenSA.h" + +extern CGameSA* pGame; + +CTxdPoolSA::CTxdPoolSA() +{ + m_ppTxdPoolInterface = (CPoolSAInterface**)0xC8800C; +} + +std::uint32_t CTxdPoolSA::AllocateTextureDictonarySlot(std::uint32_t uiSlotId, std::string& strTxdName) +{ + CTextureDictonarySAInterface* pTxd = (*m_ppTxdPoolInterface)->AllocateAt(uiSlotId); + if (!pTxd) + return -1; + + strTxdName.resize(24); + + pTxd->usUsagesCount = 0; + pTxd->hash = pGame->GetKeyGen()->GetUppercaseKey(strTxdName.c_str()); + pTxd->rwTexDictonary = nullptr; + pTxd->usParentIndex = -1; + + return (*m_ppTxdPoolInterface)->GetObjectIndex(pTxd); +} + +void CTxdPoolSA::RemoveTextureDictonarySlot(std::uint32_t uiTxdId) +{ + if (!(*m_ppTxdPoolInterface)->IsContains(uiTxdId)) + return; + + typedef std::uint32_t(__cdecl * Function_TxdReleaseSlot)(std::uint32_t uiTxdId); + ((Function_TxdReleaseSlot)(0x731E90))(uiTxdId); + + (*m_ppTxdPoolInterface)->Release(uiTxdId); +} + +bool CTxdPoolSA::IsFreeTextureDictonarySlot(std::uint32_t uiTxdId) +{ + return (*m_ppTxdPoolInterface)->IsEmpty(uiTxdId); +} + +std::uint16_t CTxdPoolSA::GetFreeTextureDictonarySlot() +{ + return (*m_ppTxdPoolInterface)->GetFreeSlot(); +} diff --git a/Client/game_sa/CTxdPoolSA.h b/Client/game_sa/CTxdPoolSA.h new file mode 100644 index 0000000000..c1f0ed8ece --- /dev/null +++ b/Client/game_sa/CTxdPoolSA.h @@ -0,0 +1,31 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include +#include "CPoolSAInterface.h" +#include "CBuildingSA.h" +#include "CTextureDictonarySA.h" + +class CTxdPoolSA final : public CTxdPool +{ +public: + CTxdPoolSA(); + ~CTxdPoolSA() = default; + + std::uint32_t AllocateTextureDictonarySlot(std::uint32_t uiSlotID, std::string& strTxdName); + void RemoveTextureDictonarySlot(std::uint32_t uiTxdId); + bool IsFreeTextureDictonarySlot(std::uint32_t uiTxdId); + + std::uint16_t GetFreeTextureDictonarySlot(); + +private: + CPoolSAInterface** m_ppTxdPoolInterface; +}; diff --git a/Client/mods/deathmatch/logic/CClientModel.cpp b/Client/mods/deathmatch/logic/CClientModel.cpp index 2a9eeb0c8d..75d6bbfd12 100644 --- a/Client/mods/deathmatch/logic/CClientModel.cpp +++ b/Client/mods/deathmatch/logic/CClientModel.cpp @@ -216,7 +216,7 @@ void CClientModel::RestoreDFF(CModelInfo* pModelInfo) bool CClientModel::AllocateTXD(std::string &strTxdName) { - uint uiSlotID = g_pGame->GetPools()->AllocateTextureDictonarySlot(m_iModelID - MAX_MODEL_DFF_ID, strTxdName); + uint uiSlotID = g_pGame->GetPools()->GetTxdPool().AllocateTextureDictonarySlot(m_iModelID - MAX_MODEL_DFF_ID, strTxdName); if (uiSlotID != -1) { m_bAllocatedByUs = true; @@ -237,6 +237,6 @@ void CClientModel::RestoreTXD(CModelInfo* pModelInfo) pModelInfo->SetTextureDictionaryID(0); } - g_pGame->GetPools()->RemoveTextureDictonarySlot(uiTextureDictonarySlotID); + g_pGame->GetPools()->GetTxdPool().RemoveTextureDictonarySlot(uiTextureDictonarySlotID); g_pGame->GetStreaming()->SetStreamingInfo(pModelInfo->GetModel(), 0, 0, 0, -1); } diff --git a/Client/mods/deathmatch/logic/CClientModelManager.cpp b/Client/mods/deathmatch/logic/CClientModelManager.cpp index 21d795e964..05c80ae26f 100644 --- a/Client/mods/deathmatch/logic/CClientModelManager.cpp +++ b/Client/mods/deathmatch/logic/CClientModelManager.cpp @@ -73,7 +73,7 @@ int CClientModelManager::GetFirstFreeModelID(void) int CClientModelManager::GetFreeTxdModelID() { - ushort usTxdId = g_pGame->GetPools()->GetFreeTextureDictonarySlot(); + ushort usTxdId = g_pGame->GetPools()->GetTxdPool().GetFreeTextureDictonarySlot(); if (usTxdId == -1) return INVALID_MODEL_ID; return MAX_MODEL_DFF_ID + usTxdId; diff --git a/Client/sdk/game/CPools.h b/Client/sdk/game/CPools.h index a5250fb657..5b7dd0bd2b 100644 --- a/Client/sdk/game/CPools.h +++ b/Client/sdk/game/CPools.h @@ -14,6 +14,7 @@ #include "Common.h" #include "CBuildingsPool.h" #include "CDummyPool.h" +#include "CTxdPool.h" class CClientEntity; class CEntity; @@ -107,12 +108,7 @@ class CPools virtual void ResetPedPoolCount() = 0; virtual void InvalidateLocalPlayerClientEntity() = 0; - virtual uint AllocateTextureDictonarySlot(uint uiSlotID, std::string& strTxdName) = 0; - virtual void RemoveTextureDictonarySlot(uint uiTxdID) = 0; - virtual bool IsFreeTextureDictonarySlot(uint uiTxdID) = 0; - - virtual ushort GetFreeTextureDictonarySlot() = 0; - virtual CBuildingsPool& GetBuildingsPool() noexcept = 0; - virtual CDummyPool& GetDummyPool() noexcept = 0; + virtual CDummyPool& GetDummyPool() noexcept = 0; + virtual CTxdPool& GetTxdPool() noexcept = 0; }; diff --git a/Client/sdk/game/CTxdPool.h b/Client/sdk/game/CTxdPool.h new file mode 100644 index 0000000000..1e4ff3493b --- /dev/null +++ b/Client/sdk/game/CTxdPool.h @@ -0,0 +1,22 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include "Common.h" + +class CTxdPool +{ +public: + virtual std::uint32_t AllocateTextureDictonarySlot(std::uint32_t uiSlotID, std::string& strTxdName) = 0; + virtual void RemoveTextureDictonarySlot(std::uint32_t uiTxdID) = 0; + virtual bool IsFreeTextureDictonarySlot(std::uint32_t uiTxdID) = 0; + + virtual std::uint16_t GetFreeTextureDictonarySlot() = 0; +}; From a4d7aaccdc8555d08babbd0256baf361296dc10e Mon Sep 17 00:00:00 2001 From: Uladzislau Nikalayevich Date: Tue, 27 Aug 2024 22:20:43 +0300 Subject: [PATCH 4/4] Better checks --- Client/game_sa/CGameSA.cpp | 22 +++++++++++++++++----- Client/game_sa/CModelInfoSA.cpp | 2 ++ Client/game_sa/CPoolSAInterface.h | 2 +- Client/game_sa/CTxdPoolSA.cpp | 9 +++++++++ Client/game_sa/CTxdPoolSA.h | 1 + Client/sdk/game/CTxdPool.h | 1 + 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/Client/game_sa/CGameSA.cpp b/Client/game_sa/CGameSA.cpp index 7222c8db1d..482a283ac0 100644 --- a/Client/game_sa/CGameSA.cpp +++ b/Client/game_sa/CGameSA.cpp @@ -1051,17 +1051,29 @@ bool CGameSA::SetBuildingPoolSize(size_t size) void CGameSA::UnloadUnusedModels() { - for (std::size_t id = 0; id < GetBaseIDforCOL(); id++) + // 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) { - if (ModelInfo[id].GetRefCount() == 0) - { - m_pStreaming->RemoveModel(id); - } + 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 diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index cf775a55ee..72b2c92b74 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); 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/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; };