From 0f3a40ee1f21d16876649f83f1ff13c589eda741 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Thu, 4 Jan 2024 21:19:32 +0100 Subject: [PATCH] DataCache: harden mdl error handling logic Rebuild 'CMDLCache::GetPhysicsGeometry()' and properly handle missing cache pointers. Also cleaned up various methods in CMDLCache and renamed 'studiophysicscache_t' to 'studiophysicsref_t'. The changes made the 'old_gather_props' convar hack redundant and has thus been removed. --- r5dev/datacache/mdlcache.cpp | 113 +++++++++++++++++++++++------------ r5dev/datacache/mdlcache.h | 77 ++++++++++++++---------- r5dev/engine/cmodel_bsp.cpp | 12 ---- 3 files changed, 121 insertions(+), 81 deletions(-) diff --git a/r5dev/datacache/mdlcache.cpp b/r5dev/datacache/mdlcache.cpp index 91936ca5..c94ea833 100644 --- a/r5dev/datacache/mdlcache.cpp +++ b/r5dev/datacache/mdlcache.cpp @@ -26,9 +26,9 @@ std::unordered_set g_vBadMDLHandles; // *a3 - // Output : a pointer to the studiohdr_t object //----------------------------------------------------------------------------- -studiohdr_t* CMDLCache::FindMDL(CMDLCache* cache, MDLHandle_t handle, void* a3) +studiohdr_t* CMDLCache::FindMDL(CMDLCache* const cache, const MDLHandle_t handle, void* a3) { - studiodata_t* pStudioData = cache->GetStudioData(handle); + studiodata_t* const pStudioData = cache->GetStudioData(handle); if (!pStudioData) { @@ -106,7 +106,7 @@ studiohdr_t* CMDLCache::FindMDL(CMDLCache* cache, MDLHandle_t handle, void* a3) // *pStudioData - // *a3 - //----------------------------------------------------------------------------- -void CMDLCache::FindCachedMDL(CMDLCache* cache, studiodata_t* pStudioData, void* a3) +void CMDLCache::FindCachedMDL(CMDLCache* const cache, studiodata_t* const pStudioData, void* a3) { if (a3) { @@ -130,7 +130,7 @@ void CMDLCache::FindCachedMDL(CMDLCache* cache, studiodata_t* pStudioData, void* // *a4 - // Output : a pointer to the studiohdr_t object //----------------------------------------------------------------------------- -studiohdr_t* CMDLCache::FindUncachedMDL(CMDLCache* cache, MDLHandle_t handle, studiodata_t* pStudioData, void* a4) +studiohdr_t* CMDLCache::FindUncachedMDL(CMDLCache* const cache, const MDLHandle_t handle, studiodata_t* pStudioData, void* a4) { AUTO_LOCK(pStudioData->m_Mutex); @@ -221,33 +221,75 @@ studiohdr_t* CMDLCache::FindUncachedMDL(CMDLCache* cache, MDLHandle_t handle, st } //----------------------------------------------------------------------------- -// Purpose: gets the studiohdr from cache pool by handle +// Purpose: gets the studio physics cache from cache pool by handle // Input : *this - // handle - -// Output : a pointer to the studiohdr_t object +// Output : a pointer to the studiophysicsref_t object //----------------------------------------------------------------------------- -vcollide_t* CMDLCache::GetVCollide(CMDLCache* cache, MDLHandle_t handle) +studiophysicsref_t* CMDLCache::GetStudioPhysicsCache(const MDLHandle_t handle) { - if (!handle) + if (handle == MDLHANDLE_INVALID) + return nullptr; + + const studiodata_t* const studioData = GetStudioData(handle); + + if (!studioData) { - Error(eDLL_T::ENGINE, NO_ERROR, "Attempted to get vcollide with no handle.\n"); + Warning(eDLL_T::ENGINE, "Attempted to load studio physics ref on model \"%s\" with no studio data!\n", GetModelName(handle)); return nullptr; } - const studiodata_t* const pStudioData = cache->GetStudioData(handle); - const studiocache_t* const dataCache = pStudioData->GetStudioCache(); + const studiocache_t* const studioCache = studioData->GetStudioCache(); - if (dataCache && dataCache != DC_INVALID_HANDLE) + if (!studioCache || studioCache == DC_INVALID_HANDLE) { - CStudioVCollide* const pVCollide = dataCache->GetPhysicsCache()->GetStudioVCollide(); - - if (pVCollide) - { - return pVCollide->GetVCollide(); - } + Warning(eDLL_T::ENGINE, "Attempted to load studio physics ref on model \"%s\" with invalid studio cache!\n", GetModelName(handle)); + return nullptr; } - return nullptr; + return studioCache->GetPhysicsCache(); +} + +//----------------------------------------------------------------------------- +// Purpose: gets the vcollide data from cache pool by handle +// Input : *this - +// handle - +// Output : a pointer to the vcollide_t object +//----------------------------------------------------------------------------- +vcollide_t* CMDLCache::GetVCollide(CMDLCache* const cache, const MDLHandle_t handle) +{ + studiophysicsref_t* const physicsCache = cache->GetStudioPhysicsCache(handle); + + if (!physicsCache) + return nullptr; + + CStudioVCollide* const pVCollide = physicsCache->GetStudioVCollide(); + + if (!pVCollide) + return nullptr; + + return pVCollide->GetVCollide(); +} + +//----------------------------------------------------------------------------- +// Purpose: gets the physics geometry data from cache pool by handle +// Input : *this - +// handle - +// Output : a pointer to the physics geometry descriptor +//----------------------------------------------------------------------------- +void* CMDLCache::GetPhysicsGeometry(CMDLCache* const cache, const MDLHandle_t handle) +{ + studiophysicsref_t* const physicsCache = cache->GetStudioPhysicsCache(handle); + + if (!physicsCache) + return nullptr; + + CStudioPhysicsGeoms* const physicsGeoms = physicsCache->GetPhysicsGeoms(); + + if (!physicsGeoms) + return nullptr; + + return physicsGeoms->GetGeometryData(); } //----------------------------------------------------------------------------- @@ -256,7 +298,7 @@ vcollide_t* CMDLCache::GetVCollide(CMDLCache* cache, MDLHandle_t handle) // handle - // Output : a pointer to the studiohwdata_t object //----------------------------------------------------------------------------- -studiohwdata_t* CMDLCache::GetHardwareData(CMDLCache* cache, MDLHandle_t handle) +studiohwdata_t* CMDLCache::GetHardwareData(CMDLCache* const cache, const MDLHandle_t handle) { const studiodata_t* pStudioData = cache->GetStudioData(handle); @@ -272,43 +314,39 @@ studiohwdata_t* CMDLCache::GetHardwareData(CMDLCache* cache, MDLHandle_t handle) const studiocache_t* const dataCache = pStudioData->GetStudioCache(); - if (dataCache) - { - if (dataCache == DC_INVALID_HANDLE) - return nullptr; + if (!dataCache || dataCache == DC_INVALID_HANDLE) + return nullptr; - studiophysicscache_t* const physicsCache = dataCache->GetPhysicsCache(); + studiophysicsref_t* const physicsCache = dataCache->GetPhysicsCache(); - AcquireSRWLockExclusive(g_pMDLLock); - CStudioHWDataRef__SetFlags(reinterpret_cast(physicsCache), 1i64); // !!! DECLARED INLINE IN < S3 !!! - ReleaseSRWLockExclusive(g_pMDLLock); - } + AcquireSRWLockExclusive(g_pMDLLock); + CMDLCache__CheckData(physicsCache, 1i64); // !!! DECLARED INLINE IN < S3 !!! + ReleaseSRWLockExclusive(g_pMDLLock); if ((pStudioData->m_nFlags & STUDIODATA_FLAGS_STUDIOMESH_LOADED)) return pStudioData->GetHardwareDataRef()->GetHardwareData(); - else - return nullptr; + + return nullptr; } //----------------------------------------------------------------------------- // Purpose: gets the error model -// Output : *studiohdr_t //----------------------------------------------------------------------------- studiohdr_t* CMDLCache::GetErrorModel(void) { - // !TODO [AMOS]: mdl/error.rmdl fallback is not supported (yet) in the new GatherProps solution! - if (!old_gather_props->GetBool()) - old_gather_props->SetValue(true); - return g_pMDLFallback->m_pErrorHDR; } +MDLHandle_t CMDLCache::GetErrorModelHandle(void) +{ + return g_pMDLFallback->m_hErrorMDL; +} //----------------------------------------------------------------------------- // Purpose: checks if this model handle is within the set of bad models // Input : handle - // Output : true if exist, false otherwise //----------------------------------------------------------------------------- -bool CMDLCache::IsKnownBadModel(MDLHandle_t handle) +bool CMDLCache::IsKnownBadModel(const MDLHandle_t handle) { auto p = g_vBadMDLHandles.insert(handle); return !p.second; @@ -321,4 +359,5 @@ void VMDLCache::Detour(const bool bAttach) const DetourSetup(&CMDLCache__FindUncachedMDL, &CMDLCache::FindUncachedMDL, bAttach); DetourSetup(&CMDLCache__GetHardwareData, &CMDLCache::GetHardwareData, bAttach); DetourSetup(&CMDLCache__GetVCollide, &CMDLCache::GetVCollide, bAttach); + DetourSetup(&CMDLCache__GetPhysicsGeometry, &CMDLCache::GetPhysicsGeometry, bAttach); } diff --git a/r5dev/datacache/mdlcache.h b/r5dev/datacache/mdlcache.h index cd22535a..b490f23c 100644 --- a/r5dev/datacache/mdlcache.h +++ b/r5dev/datacache/mdlcache.h @@ -52,14 +52,18 @@ private: class CStudioPhysicsGeoms : public CRefCounted<> { - int unk1; +public: + void* GetGeometryData() { return m_pGeomDataDesc; } + +private: + // TODO: ptr to another ptr to geometry data; requires reversing. void* m_pGeomDataDesc; int unk2; - __int16 unk3; - __int16 unk4; + short unk3; + short unk4; }; -struct studiophysicscache_t +struct studiophysicsref_t { inline CStudioVCollide* GetStudioVCollide() const { return m_pVCollide; } inline CStudioPhysicsGeoms* GetPhysicsGeoms() const { return m_pPhysicsGeoms; } @@ -77,10 +81,10 @@ struct studiophysicscache_t struct studiocache_t { inline studiohdr_t* GetStudioHdr() const { return m_pStudioHdr; } - inline studiophysicscache_t* GetPhysicsCache() const { return m_pPhysicsCache; } + inline studiophysicsref_t* GetPhysicsCache() const { return m_pPhysicsCache; } studiohdr_t* m_pStudioHdr; - studiophysicscache_t* m_pPhysicsCache; + studiophysicsref_t* m_pPhysicsCache; const char* m_szPropName; uint8_t m_pUnknown[98]; }; @@ -122,44 +126,50 @@ struct studiodata_t extern RMDLFallBack_t* g_pMDLFallback; extern std::unordered_set g_vBadMDLHandles; -class CMDLCache : public IMDLCache +class CMDLCache : public CTier1AppSystem { public: - static studiohdr_t* FindMDL(CMDLCache* cache, MDLHandle_t handle, void* a3); - static void FindCachedMDL(CMDLCache* cache, studiodata_t* pStudioData, void* a3); - static studiohdr_t* FindUncachedMDL(CMDLCache* cache, MDLHandle_t handle, studiodata_t* pStudioData, void* a4); + static studiohdr_t* FindMDL(CMDLCache* const cache, const MDLHandle_t handle, void* a3); + static void FindCachedMDL(CMDLCache* const cache, studiodata_t* const pStudioData, void* a3); + static studiohdr_t* FindUncachedMDL(CMDLCache* const cache, const MDLHandle_t handle, studiodata_t* const pStudioData, void* a4); + + studiophysicsref_t* GetStudioPhysicsCache(const MDLHandle_t handle); + + static vcollide_t* GetVCollide(CMDLCache* const cache, const MDLHandle_t handle); + static void* GetPhysicsGeometry(CMDLCache* const cache, const MDLHandle_t handle); + + static studiohwdata_t* GetHardwareData(CMDLCache* const cache, const MDLHandle_t handle); - static vcollide_t* GetVCollide(CMDLCache* cache, MDLHandle_t handle); - static studiohwdata_t* GetHardwareData(CMDLCache* cache, MDLHandle_t handle); static studiohdr_t* GetErrorModel(void); - static bool IsKnownBadModel(MDLHandle_t handle); + static MDLHandle_t GetErrorModelHandle(void); + static bool IsKnownBadModel(const MDLHandle_t handle); - inline studiodata_t* GetStudioData(MDLHandle_t handle) + inline studiodata_t* GetStudioData(const MDLHandle_t handle) { EnterCriticalSection(&m_MDLMutex); - studiodata_t* pStudioData = m_MDLDict.Element(handle); + studiodata_t* const studioData = m_MDLDict.Element(handle); LeaveCriticalSection(&m_MDLMutex); - return pStudioData; + return studioData; } - inline const char* GetModelName(MDLHandle_t handle) + inline const char* GetModelName(const MDLHandle_t handle) { EnterCriticalSection(&m_MDLMutex); - const char* szModelName = m_MDLDict.GetElementName(handle); + const char* const modelName = m_MDLDict.GetElementName(handle); LeaveCriticalSection(&m_MDLMutex); - return szModelName; + return modelName; } - inline void* GetMaterialTable(MDLHandle_t handle) + inline void* GetMaterialTable(const MDLHandle_t handle) { EnterCriticalSection(&m_MDLMutex); - studiodata_t* pStudioData = m_MDLDict.Element(handle); + studiodata_t* const studioData = m_MDLDict.Element(handle); LeaveCriticalSection(&m_MDLMutex); - return &pStudioData->m_pMaterialTable; + return &studioData->m_pMaterialTable; } private: @@ -168,14 +178,15 @@ private: // !TODO: reverse the rest }; -inline studiohdr_t*(*CMDLCache__FindMDL)(CMDLCache* pCache, MDLHandle_t handle, void* a3); -inline void(*CMDLCache__FindCachedMDL)(CMDLCache* pCache, studiodata_t* pStudioData, void* a3); +inline studiohdr_t*(*CMDLCache__FindMDL)(CMDLCache* const pCache, const MDLHandle_t handle, void* a3); +inline void(*CMDLCache__FindCachedMDL)(CMDLCache* const pCache, studiodata_t* const pStudioData, void* a3); +inline studiohdr_t*(*CMDLCache__FindUncachedMDL)(CMDLCache* const pCache, MDLHandle_t handle, studiodata_t* const pStudioData, void* a4); -inline studiohdr_t*(*CMDLCache__FindUncachedMDL)(CMDLCache* pCache, MDLHandle_t handle, studiodata_t* pStudioData, void* a4); -inline vcollide_t*(*CMDLCache__GetVCollide)(CMDLCache* pCache, MDLHandle_t handle); +inline studiohwdata_t* (*CMDLCache__GetHardwareData)(CMDLCache* const pCache, const MDLHandle_t handle); +inline vcollide_t*(*CMDLCache__GetVCollide)(CMDLCache* const pCache, const MDLHandle_t handle); +inline void* (*CMDLCache__GetPhysicsGeometry)(CMDLCache* const pCache, const MDLHandle_t handle); -inline studiohwdata_t*(*CMDLCache__GetHardwareData)(CMDLCache* pCache, MDLHandle_t handle); -inline bool(*CStudioHWDataRef__SetFlags)(CStudioHWDataRef* ref, int64_t flags); // Probably incorrect name. +inline bool(*CMDLCache__CheckData)(void* const ref, const int64_t type); // Probably incorrect name. inline CMDLCache* g_pMDLCache = nullptr; inline PSRWLOCK g_pMDLLock = nullptr; // Possibly a member? research required. @@ -188,9 +199,10 @@ class VMDLCache : public IDetour LogFunAdr("CMDLCache::FindMDL", CMDLCache__FindMDL); LogFunAdr("CMDLCache::FindCachedMDL", CMDLCache__FindCachedMDL); LogFunAdr("CMDLCache::FindUncachedMDL", CMDLCache__FindUncachedMDL); - LogFunAdr("CMDLCache::GetVCollide", CMDLCache__GetVCollide); LogFunAdr("CMDLCache::GetHardwareData", CMDLCache__GetHardwareData); - LogFunAdr("CStudioHWDataRef::SetFlags", CStudioHWDataRef__SetFlags); + LogFunAdr("CMDLCache::GetVCollide", CMDLCache__GetVCollide); + LogFunAdr("CMDLCache::GetPhysicsGeometry", CMDLCache__GetPhysicsGeometry); + LogFunAdr("CMDLCache::CheckData", CMDLCache__CheckData); LogVarAdr("g_MDLCache", g_pMDLCache); LogVarAdr("g_MDLLock", g_pMDLLock); @@ -200,9 +212,10 @@ class VMDLCache : public IDetour g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F1 0F B7 EA").GetPtr(CMDLCache__FindMDL); g_GameDll.FindPatternSIMD("4D 85 C0 74 7A 48 89 6C 24 ??").GetPtr(CMDLCache__FindCachedMDL); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 48 8B E9 0F B7 FA").GetPtr(CMDLCache__FindUncachedMDL); - g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 0F B7 DA FF 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 8D 14 5B 48 8D 0D ?? ?? ?? ?? 48 8B 5C D0 ?? FF 15 ?? ?? ?? ?? 48 8B 03 48 8B 48 08").GetPtr(CMDLCache__GetVCollide); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 0F B7 DA FF 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 8D 14 5B 48 8D 0D ?? ?? ?? ?? 48 8B 7C D0 ?? FF 15 ?? ?? ?? ?? 48 8B 1F").GetPtr(CMDLCache__GetHardwareData); - g_GameDll.FindPatternSIMD("48 83 EC 08 4C 8D 14 12").GetPtr(CStudioHWDataRef__SetFlags); + g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 48 8D 0D ?? ?? ?? ?? 0F B7 DA FF 15 ?? ?? ?? ?? 48 8B 05 ?? ?? ?? ?? 48 8D 14 5B 48 8D 0D ?? ?? ?? ?? 48 8B 5C D0 ?? FF 15 ?? ?? ?? ?? 48 8B 03 48 8B 48 08").GetPtr(CMDLCache__GetVCollide); + g_GameDll.FindPatternSIMD("40 53 48 83 EC 20 B8 ?? ?? ?? ?? 0F B7 DA").GetPtr(CMDLCache__GetPhysicsGeometry); + g_GameDll.FindPatternSIMD("48 83 EC 08 4C 8D 14 12").GetPtr(CMDLCache__CheckData); } virtual void GetVar(void) const { diff --git a/r5dev/engine/cmodel_bsp.cpp b/r5dev/engine/cmodel_bsp.cpp index 395ff4da..9422d114 100644 --- a/r5dev/engine/cmodel_bsp.cpp +++ b/r5dev/engine/cmodel_bsp.cpp @@ -266,18 +266,6 @@ void Mod_ProcessPakQueue() #endif // !DEDICATED } - // The old gather props is set if a model couldn't be - // loaded properly. If we unload level assets, we just - // enable the new implementation again and re-evaluate - // on the next level load. If we load a missing/bad - // model again, we toggle the old implementation as - // the helper functions for this implementation have - // been restored in the SDK, and modified to support - // stubbing missing model assets. See the function - // 'CMDLCache::GetErrorModel' for more information. - if (old_gather_props->GetBool()) - old_gather_props->SetValue(false); - g_pakLoadApi->UnloadPak(*(PakHandle_t*)v10); Mod_UnloadPakFile(); // Unload mod pak files.