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.
This commit is contained in:
Kawe Mazidjatari 2024-01-04 21:19:32 +01:00
parent ad4e8c241b
commit 0f3a40ee1f
3 changed files with 121 additions and 81 deletions

View File

@ -26,9 +26,9 @@ std::unordered_set<MDLHandle_t> 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<CStudioHWDataRef*>(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);
}

View File

@ -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<MDLHandle_t> g_vBadMDLHandles;
class CMDLCache : public IMDLCache
class CMDLCache : public CTier1AppSystem<IMDLCache>
{
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
{

View File

@ -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.