r5sdk/r5dev/datacache/mdlcache.cpp
Kawe Mazidjatari 3cb4976c23 Start or 'mdl/error.rmdl' fallback implementation (see description)
In 'datacache/mdlcache.cpp' the function 'CMDLCache::FindMDL' attempts to find 'mdl/error.rmdl' and assigns the studiohdr and handle to the members of CMDLFallback.

In 'CMDLCache::FindUncachedMDL' we check if a model exists, if a model does not exist, we replace the studiohdr with the one of error.rmdl we stored in the CMDLFallback structure.

This does actually work (on the dedicated server it doesn't crash at all!), but on the client it crashes when trying to gather props (right before rendering), setting the ConVar* 'old_gather_props' does interesting things (check IDA around this ConVar*). setting this to 1 causes it to crash in another CMDLCache method when trying to deref something in the global cache pool.

This method is easy to rebuild. I will do this soon and attempt to return error.rmdl parts from here as well if results are null (this might actually just work).

Leaving 'old_gather_props' to 0 causes it to crash in the middle of the function which is supposed to gather the props the 'new' way.

The gather props functions are kind of daunting

NOTE: Currently only confirmed to work somewhat properly on the dedicated server for prop_static. prop_dynamic is unconfirmed. And (almost?) works on the client.
2022-04-29 05:30:06 +02:00

202 lines
6.4 KiB
C++

//=====================================================================================//
//
// model loading and caching
//
// $NoKeywords: $
//=====================================================================================//
#include "core/stdafx.h"
#include "datacache/mdlcache.h"
#include "datacache/imdlcache.h"
#include "engine/sys_utils.h"
#include "rtech/rtech_utils.h"
#include "public/include/studio.h"
//-----------------------------------------------------------------------------
// Purpose: finds an MDL
// Input : *this -
// handle -
// *a3 -
// Output : a pointer to the studiohdr_t object
//-----------------------------------------------------------------------------
studiohdr_t* CMDLCache::FindMDL(CMDLCache* pMDLCache, MDLHandle_t handle, void* a3)
{
__int64 v4; // rbp
__int64 v6; // rbx
__int64* v7; // rax
studiohdr_t* result; // rax
v4 = handle;
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
v6 = *(_QWORD*)(m_MDLDict.Deref().GetPtr() + 24 * v4 + 16);
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
if (!g_pMDLFallback->m_hErrorMDL || !g_pMDLFallback->m_hEmptyMDL)
{
studiohdr_t* pStudioHDR = **(studiohdr_t***)v6;
string svStudio = ConvertToUnixPath(string(pStudioHDR->name));
if (strcmp(svStudio.c_str(), ERROR_MODEL) == 0)
{
g_pMDLFallback->m_pErrorHDR = pStudioHDR;
g_pMDLFallback->m_hErrorMDL = handle;
}
if (strcmp(svStudio.c_str(), EMPTY_MODEL) == 0)
{
g_pMDLFallback->m_pEmptyHDR = pStudioHDR;
g_pMDLFallback->m_hEmptyMDL = handle;
}
}
if (!v6)
{
if (!g_pMDLFallback->m_hErrorMDL)
Error(eDLL_T::ENGINE, "Model with handle \"%hu\" not found and \"%s\" couldn't be loaded.\n", handle, ERROR_MODEL);
return g_pMDLFallback->m_pErrorHDR;
}
if ((*(_WORD*)(v6 + 18) & 0x600) != 0)
{
v7 = *(__int64**)v6;
if (*(_QWORD*)v6)
{
if (a3)
{
CMDLCache::FindCachedMDL(pMDLCache, (void*)v6, a3);
v7 = *(__int64**)v6;
}
LABEL_6:
result = (studiohdr_t*)*v7;
if (result)
return result;
return CMDLCache::FindUncachedMDL(pMDLCache, v4, (void*)v6, a3);
}
v7 = *(__int64**)(v6 + 8);
if (v7)
goto LABEL_6;
}
return CMDLCache::FindUncachedMDL(pMDLCache, v4, (void*)v6, a3);
}
//-----------------------------------------------------------------------------
// Purpose: finds an MDL cached
// Input : *this -
// *a2 -
// *a3 -
//-----------------------------------------------------------------------------
void CMDLCache::FindCachedMDL(CMDLCache* pMDLCache, void* a2, void* a3)
{
v_CMDLCache__FindCachedMDL(pMDLCache, a2, a3);
}
//-----------------------------------------------------------------------------
// Purpose: finds an MDL uncached
// Input : *this -
// handle -
// *a3 -
// *a4
// Output : a pointer to the studiohdr_t object
//-----------------------------------------------------------------------------
studiohdr_t* CMDLCache::FindUncachedMDL(CMDLCache* cache, MDLHandle_t handle, void* a3, void* a4)
{
const char* v8; // rdi
__int64 v9; // rax
int v10; // eax
const char* v11; // r11
int v12; // eax
const char* v13; // r11
int v14; // eax
bool v16; // zf
studiohdr_t* v17; // rdi
studiohdr_t** v18; // rax
//CThreadFastMutexSlow::WaitForLock(a3 + 0x80);
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
void* modelCache = cache->m_pModelCacheSection;
v8 = (const char*)(*(_QWORD*)((int64)modelCache + 24 * static_cast<int64>(handle) + 8));
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
v9 = -1i64;
do
++v9;
while (v8[v9]);
if (v9 < 5 ||
(_stricmp(&v8[v9 - 5], ".rmdl") != 0) &&
(_stricmp(&v8[v9 - 5], ".rrig") != 0) &&
(_stricmp(&v8[v9 - 5], ".rpak") != 0))
{
Error(eDLL_T::ENGINE, "Attempted to load old model \"%s\"; replace with rmdl.\n", v8);
goto LABEL_ERROR;
}
g_pRTech->StringToGuid(v8);
v16 = *(_QWORD*)a3 == 0i64;
*(_BYTE*)((int64)a3 + 152) = 0;
if (v16)
{
v18 = *(studiohdr_t***)((int64)a3 + 8);
if (v18)
{
v17 = *v18;
}
else
{
LABEL_ERROR:
if (g_pMDLFallback->m_hErrorMDL)
Error(eDLL_T::ENGINE, "Model \"%s\" not found; replacing with \"%s\".\n", v8, ERROR_MODEL);
else
Error(eDLL_T::ENGINE, "Model \"%s\" not found and \"%s\" couldn't be loaded.\n", v8, ERROR_MODEL);
v17 = g_pMDLFallback->m_pErrorHDR;
}
}
else
{
v_CMDLCache__FindCachedMDL(cache, a3, a4);
v17 = **(studiohdr_t***)a3;
}
//CThreadFastMutexSlow::ReleaseWaiter(a3 + 128);
return v17;
}
studiohdr_t* CMDLCache::GetStudioHdr(CMDLCache* pMDLCache, MDLHandle_t handle)
{
__int64 v2; // rbx
__int64 v3; // rbx
__int64 v4; // rdx
studiohdr_t* result; // rax
if (!handle)
{
if (!g_pMDLFallback->m_hErrorMDL)
Error(eDLL_T::ENGINE, "Model with handle \"%hu\" not found and \"%s\" couldn't be loaded.\n", handle, ERROR_MODEL);
return g_pMDLFallback->m_pErrorHDR;
}
v2 = handle;
EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
v3 = *(_QWORD*)(m_MDLDict.Deref().GetPtr() + 24 * v2 + 16);
LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(&*m_MDLMutex));
v4 = *(_QWORD*)(*(_QWORD*)(*(_QWORD*)v3 + 8i64) + 24i64);
result = (studiohdr_t*)(v4 + 16);
if (!v4)
result = nullptr;;
return result;
}
void MDLCache_Attach()
{
DetourAttach((LPVOID*)&v_CMDLCache__FindMDL, &CMDLCache::FindMDL);
DetourAttach((LPVOID*)&v_CMDLCache__FindUncachedMDL, &CMDLCache::FindUncachedMDL);
//DetourAttach((LPVOID*)&v_CMDLCache__GetStudioHdr, &CMDLCache::GetStudioHdr);
}
void MDLCache_Detach()
{
DetourDetach((LPVOID*)&v_CMDLCache__FindMDL, &CMDLCache::FindMDL);
DetourDetach((LPVOID*)&v_CMDLCache__FindUncachedMDL, &CMDLCache::FindUncachedMDL);
//DetourDetach((LPVOID*)&v_CMDLCache__GetStudioHdr, &CMDLCache::GetStudioHdr);
}