r5sdk/r5dev/engine/cmodel_bsp.cpp
Kawe Mazidjatari 596682c483 More robust RPak loading/unloading system
This is currently the most robust way to perform this.
However it might fail still as the locks don't seem valid for the second loads (we currently load more paks from the same queue..).

We need to push the strings to the queue list and let the engine load these too so a new lock is acquired for that job.
2022-05-15 12:20:21 +02:00

364 lines
11 KiB
C++

//=============================================================================//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "core/stdafx.h"
#include "tier0/jobthread.h"
#include "engine/host_cmd.h"
#include "engine/sys_utils.h"
#include "engine/cmodel_bsp.h"
#include "rtech/rtech_utils.h"
#include "rtech/rtech_game.h"
#include "datacache/mdlcache.h"
string g_svLevelName;
bool s_bLevelResourceInitialized = false;
bool s_bBasePaksInitialized = false;
//-----------------------------------------------------------------------------
// Purpose: checks if level has changed
// Input : &svLevelName -
// Output : true if level name deviates from previous level
//-----------------------------------------------------------------------------
bool MOD_LevelHasChanged(const string& svLevelName)
{
return (strcmp(svLevelName.c_str(), g_svLevelName.c_str()) != 0);
}
//-----------------------------------------------------------------------------
// Purpose: gets the queued pak handles
// Input : *a1 -
// *a2 -
// a3 -
// Output : __int64
//-----------------------------------------------------------------------------
__int64 __fastcall MOD_GetQueuedPakHandle(char* a1, char* a2, __int64 a3)
{
char v3; // al
signed int v4; // er11
__int64 v5; // r10
char* v6; // r9
signed __int64 v7; // rdx
char v8; // al
char* v10; // r8
char* v11; // r8
v3 = *a2;
v4 = 0;
*a1 = *a2;
v5 = 0i64;
if (v3)
{
v6 = a1;
v7 = a2 - a1;
while (1)
{
++v5;
++v6;
if (v5 == a3)
break;
v8 = v6[v7];
*v6 = v8;
if (!v8)
return v5;
}
*(v6 - 1) = 0;
if (--v5)
{
v10 = &a1[v5 - 1];
if ((*v10 & 0xC0) == 0x80)
{
do
++v4;
while ((v10[-v4] & 0xC0) == 0x80);
}
v11 = &v10[-v4];
if (v4 != ((0xE5000000 >> (((unsigned __int8)*v11 >> 3) & 0x1E)) & 3))
{
*v11 = 0;
v5 -= v4;
}
}
}
return v5;
}
//-----------------------------------------------------------------------------
// Purpose: processes queued pak files
//-----------------------------------------------------------------------------
void MOD_ProcessPakQueue()
{
char v0; // bl
char** v1; // r10
int i; // er9
char* v3; // rcx
signed __int64 v4; // r8
int v5; // eax
int v6; // edx
int v7; // eax
__int64 v8; // rbp
__int64 v9; // rsi
char* v10; // rbx
unsigned int v11; // ecx
__int64 v12; // rax
int v13; // edi
char v14; // al
char* v15; // rbx
int v16; // edi
char* v17; // rsi
char* v18; // rax
int v19; // ecx
int v20; // er8
int v21; // ecx
__int64 v22; // rdx
__int64 v23; // rbx
__int64 v24{}; // rdx
__int64 v25{}; // rcx
v0 = 0;
if (*(float*)&*dword_14B383420 == 1.0 && *qword_167ED7BB8 && *((int*)&*qword_14180A098/* + 36*/) < 2)
{
*byte_16709DDDF = 0;
v0 = 1;
}
else if (*byte_16709DDDF)
{
return;
}
if ((*(unsigned __int8(__fastcall**)(__int64))(*(_QWORD*)*g_FileSystem + 696i64))(*g_FileSystem) && !*dword_1634F445C)
{
v1 = &*off_141874660;
for (i = 0; i < 5; ++i)
{
if (*((_BYTE*)v1 - 268))
break;
v3 = (char*)&*unk_141874555 + 280 * i;
v4 = *v1 - v3;
do
{
v5 = (unsigned __int8)v3[v4];
v6 = (unsigned __int8)*v3 - v5;
if (v6)
break;
++v3;
} while (v5);
if (v6)
break;
v1 += 35;
}
v7 = 0;
if (!v0)
v7 = i;
v8 = v7;
if (v7 <= 4i64)
{
v9 = 4i64;
v10 = (char*)&*unk_1418749B0;
do
{
if (v10[5])
{
v11 = *(_DWORD*)v10;
v12 = *(_DWORD*)v10 & 0x1FF;
v10[4] = 1;
if (*((_DWORD*)&*unk_167D40B70 + 46 * v12) == v11)
{
v13 = *((_DWORD*)&*unk_167D40B70 + 46 * v12 + 1);
v14 = v10[4];
}
else
{
v13 = 14;
v14 = 1;
}
if (!v14 || v13 == 9)
{
g_pakLoadApi->Unload(*(_DWORD*)v10);
MOD_UnloadPakFile();
}
if (v13 && (unsigned int)(v13 - 13) > 1)
return;
*((_WORD*)v10 + 2) = 0;
*(_DWORD*)v10 = -1;
}
--v9;
v10 -= 280;
} while (v9 >= v8);
}
*byte_16709DDDF = 1;
v15 = (char*)&*unk_141874550;
v16 = 0;
while (1)
{
v17 = (char*)&*unk_141874550 + 280 * v16 + 5;
v18 = v17;
do
{
v19 = (unsigned __int8)v18[*((_QWORD*)v15 + 34) - (_QWORD)v17];
v20 = (unsigned __int8)*v18 - v19;
if (v20)
break;
++v18;
} while (v19);
if (!v20)
goto LABEL_37;
sub_1401F9C10(v17, *((char**)v15 + 34), 260i64);
if (v15[5])
break;
*(_DWORD*)v15 = -1;
LABEL_40:
++v16;
v15 += 280;
if (v16 >= 5)
{
if (*byte_16709DDDF)
{
v23 = *qword_1671061C8;
if (*qword_1671061C8)
{
if (!*(_BYTE*)(*qword_1671061C8 + 4))
{
if (*qword_167ED7BC0 || WORD2(*qword_167ED7C68) != HIWORD(*qword_167ED7C68))
{
if (!JT_AcquireFifoLock((JobFifoLock_s*)&*qword_167ED7BE0)
&& !(unsigned __int8)sub_14045BAC0((__int64(__fastcall*)(__int64, _DWORD*, __int64, _QWORD*))qword_14045C070, (__int64)&*qword_167ED7BE0, -1i64, 0i64))
{
sub_14045A1D0((unsigned __int8(__fastcall*)(_QWORD))qword_14045C070, (__int64)&*qword_167ED7BE0, -1i64, 0i64, 0i64, 1);
}
sub_140441220(v25, v24);
if (GetCurrentThreadId() == *dword_1641E443C)
{
if (*byte_167208B0C)
{
*byte_167208B0C = 0;
JT_ReleaseFifoLock((JobFifoLock_s*)&*qword_167ED7BE0);
}
}
JT_ReleaseFifoLock((JobFifoLock_s*)&*qword_167ED7BE0);
v23 = *qword_1671061C8;
}
(*(void(__fastcall**)(__int64, __int64))(*(_QWORD*)*g_FileSystem + 656i64))(*g_FileSystem, 256i64);
(*(void(__fastcall**)(__int64, __int64))(*(_QWORD*)*g_FileSystem + 648i64))(*g_FileSystem, v23);
}
}
}
return;
}
}
if (strcmp(v17, "mp_lobby.rpak") == 0)
s_bBasePaksInitialized = true;
if (s_bBasePaksInitialized && !s_bLevelResourceInitialized)
{
s_bLevelResourceInitialized = true;
MOD_PreloadPakFile(g_svLevelName);
}
*(_DWORD*)v15 = g_pakLoadApi->AsyncLoad(v17, g_pMallocPool.GetPtr(), 4, 0);
LABEL_37:
v21 = *(_DWORD*)v15;
if (*(_DWORD*)v15 != -1)
{
v22 = 184i64 * (v21 & 0x1FF);
if (*(_DWORD*)((char*)&*unk_167D40B70 + v22) != v21 || ((*(_DWORD*)((char*)&*unk_167D40B70 + v22 + 4) - 9) & 0xFFFFFFFB) != 0)
{
*byte_16709DDDF = 0; return;
}
}
goto LABEL_40;
}
}
//-----------------------------------------------------------------------------
// Purpose: load assets for level with fifolock (still not reliable enough).
// Input : *szLevelName -
// Output : true on success, false on failure
//-----------------------------------------------------------------------------
bool MOD_LoadPakForMap(const char* szLevelName)
{
if (MOD_LevelHasChanged(szLevelName))
s_bLevelResourceInitialized = false;
g_svLevelName = szLevelName;
return v_MOD_LoadPakForMap(szLevelName);
}
//-----------------------------------------------------------------------------
// Purpose: loads required pakfile assets for specified BSP
// Input : &svSetFile -
//-----------------------------------------------------------------------------
void MOD_PreloadPakFile(const string& svLevelName)
{
ostringstream ostream;
ostream << "platform\\scripts\\levels\\settings\\" << svLevelName << ".json";
fs::path fsPath = std::filesystem::current_path() /= ostream.str();
if (FileExists(fsPath.string().c_str()))
{
nlohmann::json jsIn;
try
{
ifstream iPakLoadDefFile(fsPath.string().c_str(), std::ios::binary); // Load prerequisites file.
jsIn = nlohmann::json::parse(iPakLoadDefFile);
iPakLoadDefFile.close();
if (!jsIn.is_null())
{
if (!jsIn["rpak"].is_null())
{
for (auto& it : jsIn["rpak"])
{
if (it.is_string())
{
string svToLoad = it.get<string>() + ".rpak";
RPakHandle_t nPakId = g_pakLoadApi->AsyncLoad(svToLoad.c_str(), g_pMallocPool.GetPtr(), 4, 0);
if (nPakId == -1)
Error(eDLL_T::ENGINE, "%s: unable to load pak '%s' results '%d'\n", __FUNCTION__, svToLoad.c_str(), nPakId);
else
g_LoadedPakHandle.push_back(nPakId);
}
}
}
}
}
catch (const std::exception& ex)
{
Warning(eDLL_T::RTECH, "Exception while parsing RPak load list: '%s'\n", ex.what());
return;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: unloads all pakfiles loaded by the SDK
//-----------------------------------------------------------------------------
void MOD_UnloadPakFile(void)
{
for (auto& it : g_LoadedPakHandle)
{
if (it >= 0)
{
g_pakLoadApi->Unload(it);
}
}
g_LoadedPakHandle.clear();
g_BadMDLHandles.clear();
}
void CModelBsp_Attach()
{
DetourAttach((LPVOID*)&v_MOD_LoadPakForMap, &MOD_LoadPakForMap);
DetourAttach((LPVOID*)&v_MOD_ProcessPakQueue, &MOD_ProcessPakQueue);
}
void CModelBsp_Detach()
{
DetourDetach((LPVOID*)&v_MOD_LoadPakForMap, &MOD_LoadPakForMap);
DetourDetach((LPVOID*)&v_MOD_ProcessPakQueue, &MOD_ProcessPakQueue);
}