diff --git a/Client/game_sa/CFileLoaderSA.cpp b/Client/game_sa/CFileLoaderSA.cpp index d5ce6c911e..8136a202a3 100644 --- a/Client/game_sa/CFileLoaderSA.cpp +++ b/Client/game_sa/CFileLoaderSA.cpp @@ -54,12 +54,16 @@ CEntitySAInterface* CFileLoaderSA::LoadObjectInstance(const char* szLine) return CFileLoader_LoadObjectInstance(szLine); } +class CDamagableModelInfo; + class CAtomicModelInfo { public: void DeleteRwObject() { ((void(__thiscall*)(CAtomicModelInfo*))(*(void***)this)[8])(this); } void SetAtomic(RpAtomic* atomic) { ((void(__thiscall*)(CAtomicModelInfo*, RpAtomic*))(*(void***)this)[15])(this, atomic); } + + CDamagableModelInfo* AsDamageAtomicModelInfoPtr() { return ((CDamagableModelInfo * (__thiscall*)(CAtomicModelInfo*))(*(void***)this)[2])(this); } }; class CDamagableModelInfo @@ -210,12 +214,19 @@ RpAtomic* CFileLoader_SetRelatedModelInfoCB(RpAtomic* atomic, SRelatedModelInfo* GetNameAndDamage(frameNodeName, name, bDamage); } + CDamagableModelInfo* pDamagableModelInfo = bDamage ? pAtomicModelInfo->AsDamageAtomicModelInfoPtr() : nullptr; + if (bDamage && !pDamagableModelInfo) + { + // Returning null would stop RpClumpForAllAtomics, so leave the atomic with the clump + pRelatedModelInfo->bAtomicNotConsumed = true; + return atomic; + } + CVisibilityPlugins_SetAtomicRenderCallback(atomic, 0); RpAtomic* pOldAtomic = reinterpret_cast(pBaseModelInfo->pRwObject); if (bDamage) { - auto pDamagableModelInfo = reinterpret_cast(pAtomicModelInfo); pDamagableModelInfo->SetDamagedAtomic(atomic); } else diff --git a/Client/game_sa/CFileLoaderSA.h b/Client/game_sa/CFileLoaderSA.h index 7819aebc92..534c8aa050 100644 --- a/Client/game_sa/CFileLoaderSA.h +++ b/Client/game_sa/CFileLoaderSA.h @@ -13,6 +13,7 @@ struct SRelatedModelInfo { RpClump* pClump; bool bDeleteOldRwObject; + bool bAtomicNotConsumed; }; struct SFileObjectInstance diff --git a/Client/game_sa/CRenderWareSA.cpp b/Client/game_sa/CRenderWareSA.cpp index 7de9737519..40d678bfc1 100644 --- a/Client/game_sa/CRenderWareSA.cpp +++ b/Client/game_sa/CRenderWareSA.cpp @@ -527,9 +527,11 @@ bool AtomicsReplacer(RpAtomic* pAtomic, void* data) relatedModelInfo.bDeleteOldRwObject = true; CFileLoader_SetRelatedModelInfoCB(pAtomic, &relatedModelInfo); - // The above function adds a reference to the model's TXD by either - // calling CAtomicModelInfo::SetAtomic or CDamagableModelInfo::SetDamagedAtomic. Remove it again. - CTxdStore_RemoveRef(pData->usTxdID); + // The above function adds a reference to the model's TXD when it calls + // CAtomicModelInfo::SetAtomic or CDamagableModelInfo::SetDamagedAtomic. It calls neither if the + // atomic was left with the clump, so only remove the reference when one was taken. + if (!relatedModelInfo.bAtomicNotConsumed) + CTxdStore_RemoveRef(pData->usTxdID); return true; }