r5sdk/r5dev/datacache/mdlcache.cpp
Kawe Mazidjatari c3f31d694a Improved mod RPak loading between changelevel
Note: this does not work reliably still.

The only way we could make this work 100% reliable would be to fully rebuild '0x140341D40' in the SDK and load our pak files among with the pre-existing g_pakLoadApi->AsyncLoad() call in this function, as this will ensure everything will be ran synchronously.

The current approach by taking some JT fifolock wrapper will only work reliably between one level change, unsure why the second and up fail.
2022-05-04 02:25:27 +02:00

317 lines
11 KiB
C++

//=====================================================================================//
//
// model loading and caching
//
// $NoKeywords: $
//=====================================================================================//
#include "core/stdafx.h"
#include "tier0/threadtools.h"
#include "tier1/cvar.h"
#include "datacache/mdlcache.h"
#include "datacache/imdlcache.h"
#include "engine/sys_utils.h"
#include "rtech/rtech_utils.h"
#include "public/include/studio.h"
#include "tier1/utldict.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));
// Example usage.
// auto mdlDict = CUtlDict<__int64, MDLHandle_t>(m_MDLDict.Deref().GetPtr()); // __int64 is studiodata_t*
// v6 = mdlDict.Find(v4);
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)
{
FindCachedMDL(pMDLCache, (void*)v6, a3);
v7 = *(__int64**)v6;
}
LABEL_6:
result = (studiohdr_t*)*v7;
if (result)
return result;
return FindUncachedMDL(pMDLCache, v4, (void*)v6, a3);
}
v7 = *(__int64**)(v6 + 8);
if (v7)
goto LABEL_6;
}
return FindUncachedMDL(pMDLCache, v4, (void*)v6, a3);
}
//-----------------------------------------------------------------------------
// Purpose: finds an MDL cached
// Input : *this -
// *a2 -
// *a3 -
//-----------------------------------------------------------------------------
void CMDLCache::FindCachedMDL(CMDLCache* cache, void* a2, void* a3)
{
__int64 v6; // rax
if (a3)
{
CThreadFastMutex::WaitForLock((CThreadFastMutex*)a2 + 128);
*(_QWORD*)((int64_t)a3 + 2176) = *(_QWORD*)((int64_t)a2 + 88);
v6 = *(_QWORD*)((int64_t)a2 + 88);
if (v6)
*(_QWORD*)(v6 + 2168) = (int64_t)a3;
*(_QWORD*)((int64_t)a2 + 88) = (int64_t)a3;
*(_QWORD*)((int64_t)a3 + 2160) = (int64_t)cache;
*(_WORD*)((int64_t)a3 + 2184) = *(_WORD*)((int64_t)a2 + 20);
CThreadFastMutex::ReleaseWaiter((CThreadFastMutex*)a2 + 128);
}
}
//-----------------------------------------------------------------------------
// 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
bool bOldModel {};
bool bInvalidHandle{};
CThreadFastMutex::WaitForLock((CThreadFastMutex*)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));
if (IsBadReadPtrV2((void*)v8))
{
bInvalidHandle = true;
goto LABEL_ERROR;
}
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))
{
bOldModel = true;
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 (std::find(g_BadMDLHandles.begin(), g_BadMDLHandles.end(), handle) == g_BadMDLHandles.end())
{
if (bInvalidHandle)
Error(eDLL_T::ENGINE, "Model with handle \"hu\" not found; replacing with \"%s\".\n", handle, ERROR_MODEL);
else if (bOldModel)
Error(eDLL_T::ENGINE, "Attempted to load old model \"%s\"; replace with rmdl.\n", v8);
else
{
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);
}
g_BadMDLHandles.push_back(handle);
}
v17 = g_pMDLFallback->m_pErrorHDR;
old_gather_props->SetValue(true); // mdl/error.rmdl fallback is not supported (yet) in the new GatherProps solution!
}
}
else
{
v_CMDLCache__FindCachedMDL(cache, a3, a4);
v17 = **(studiohdr_t***)a3;
}
CThreadFastMutex::ReleaseWaiter((CThreadFastMutex*)a3 + 128);
return v17;
}
//-----------------------------------------------------------------------------
// Purpose: gets the studiohdr from cache pool by handle
// Input : *this -
// handle -
// Output : a pointer to the studiohdr_t object
//-----------------------------------------------------------------------------
studiohdr_t* CMDLCache::GetStudioHDR(CMDLCache* pMDLCache, MDLHandle_t handle)
{
__int64 v2; // rbx
__int64 v3; // rbx
__int64 v4; // rdx
studiohdr_t* result = nullptr; // rax
if (!handle)
{
LABEL_ERROR:
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));
if (*(_QWORD*)(v3))
{
v4 = *(_QWORD*)(*(_QWORD*)(*(_QWORD*)v3 + 8i64) + 24i64);
if (v4)
result = (studiohdr_t*)(v4 + 16);
}
return result;
}
//-----------------------------------------------------------------------------
// Purpose: gets the studio hardware data reference from cache pool by handle
// Input : *this -
// handle -
// Output : a pointer to the CStudioHWDataRef object
//-----------------------------------------------------------------------------
CStudioHWDataRef* CMDLCache::GetStudioHardwareRef(CMDLCache* cache, MDLHandle_t handle)
{
__int64 v2; // rbx
__int64 v3; // rdi
__int64 v4; // rbx
__int64 result; // rax
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));
if (!v3)
{
if (!g_pMDLFallback->m_hErrorMDL)
{
Error(eDLL_T::ENGINE, "Studio hardware with handle \"%hu\" not found and \"%s\" couldn't be loaded.\n", handle, ERROR_MODEL);
return nullptr;
}
v3 = *(_QWORD*)(m_MDLDict.Deref().GetPtr() + 24 * g_pMDLFallback->m_hErrorMDL + 16);
}
if (*(_QWORD*)v3)
{
v4 = *(_QWORD*)(*(_QWORD*)v3 + 8i64);
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*m_MDLLock));
v_CStudioHWDataRef__SetFlags(reinterpret_cast<CStudioHWDataRef*>(v4), 1i64); // !!! DECLARED INLINE IN < S3 !!!
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*m_MDLLock));
}
if ((*(_BYTE*)(v3 + 18) & 1) != 0)
result = *(_QWORD*)(v3 + 0x20) + 16i64;
else
result = 0i64;
return reinterpret_cast<CStudioHWDataRef*>(result);
}
//-----------------------------------------------------------------------------
// Purpose: gets the studio material glue from cache pool by handle
// Input : *this -
// handle -
// Output : a pointer to the CMaterialGlue object
//-----------------------------------------------------------------------------
void* CMDLCache::GetStudioMaterialGlue(CMDLCache* cache, MDLHandle_t handle)
{
__int64 v2; // rbx
__int64 v3; // rbx
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));
return (char*)v3 + 40;
}
void MDLCache_Attach()
{
DetourAttach((LPVOID*)&v_CMDLCache__FindMDL, &CMDLCache::FindMDL);
DetourAttach((LPVOID*)&v_CMDLCache__FindCachedMDL, &CMDLCache::FindCachedMDL);
DetourAttach((LPVOID*)&v_CMDLCache__FindUncachedMDL, &CMDLCache::FindUncachedMDL);
DetourAttach((LPVOID*)&v_CMDLCache__GetStudioHardwareRef, &CMDLCache::GetStudioHardwareRef);
DetourAttach((LPVOID*)&v_CMDLCache__GetStudioHDR, &CMDLCache::GetStudioHDR);
}
void MDLCache_Detach()
{
DetourDetach((LPVOID*)&v_CMDLCache__FindMDL, &CMDLCache::FindMDL);
DetourDetach((LPVOID*)&v_CMDLCache__FindCachedMDL, &CMDLCache::FindCachedMDL);
DetourDetach((LPVOID*)&v_CMDLCache__FindUncachedMDL, &CMDLCache::FindUncachedMDL);
DetourDetach((LPVOID*)&v_CMDLCache__GetStudioHardwareRef, &CMDLCache::GetStudioHardwareRef);
DetourDetach((LPVOID*)&v_CMDLCache__GetStudioHDR, &CMDLCache::GetStudioHDR);
}