r5sdk/r5dev/rtech/rtech_game.cpp
Kawe Mazidjatari edc52ad669 IDetour: remove extraneous pointer assignments
Originally, we store the search results in a CMemory instance which we then assign to the actual function pointer. CMemory is just a pointer class; we can assign the results directly to the actual function pointer. This commit reduces a lot of code verbosity, and also reduced roughly 2KiB worth of static pointers in the resulting executable. This commit also officially deprecates the support for any GameDLL's below S3 (Season 3), since it makes more sense to port the assets from earlier/later games back to the version this SDK supports.
2024-04-05 17:19:32 +02:00

594 lines
22 KiB
C++

//=============================================================================//
//
// Purpose: RTech game utilities
//
//=============================================================================//
#include "core/stdafx.h"
#include "engine/host_cmd.h"
#include "engine/host_state.h"
#include "engine/cmodel_bsp.h"
#include "rtech/rtech_game.h"
#include "rtech/rtech_utils.h"
// Pak handles that have been loaded with the level
// from within the level settings KV (located in
// scripts/levels/settings/*.kv). On level unload,
// each pak listed in this vector gets unloaded.
CUtlVector<PakHandle_t> g_vLoadedPakHandle;
//-----------------------------------------------------------------------------
// Purpose: process guid relations for asset
// Input : *pak -
// *asset -
//-----------------------------------------------------------------------------
void Pak_ProcessGuidRelationsForAsset(PakFile_t* pak, PakAsset_t* asset)
{
static const int GLOBAL_MUL = 0x17;
PakPage_t* pGuidDescriptors = &pak->m_memoryData.m_guidDescriptors[asset->m_usesStartIdx];
volatile uint32_t* v5 = reinterpret_cast<volatile uint32_t*>(*(reinterpret_cast<uint64_t*>(g_pPakGlobals) + GLOBAL_MUL * (pak->m_memoryData.qword2D8 & 0x1FF) + 0x160212));
const bool bDebug = rtech_debug->GetBool();
if (bDebug)
Msg(eDLL_T::RTECH, "Processing GUID relations for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i\n", asset->m_guid, pak->m_memoryData.m_fileName, asset->m_usesCount);
for (uint32_t i = 0; i < asset->m_usesCount; i++)
{
void** pCurrentGuid = reinterpret_cast<void**>(pak->m_memoryData.m_pagePointers[pGuidDescriptors[i].m_index] + pGuidDescriptors[i].m_offset);
// Get current guid.
const uint64_t currentGuid = reinterpret_cast<uint64_t>(*pCurrentGuid);
// Get asset index.
int assetIdx = currentGuid & 0x3FFFF;
uint64_t assetIdxEntryGuid = g_pPakGlobals->m_assets[assetIdx].m_guid;
const int64_t v9 = 2i64 * InterlockedExchangeAdd(v5, 1u);
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 2])) = currentGuid;
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 4])) = asset->m_guid;
std::function<bool(bool)> fnCheckAsset = [&](bool shouldCheckTwo)
{
while (true)
{
if (shouldCheckTwo && assetIdxEntryGuid == 2)
{
if (pak->m_memoryData.m_pakHeader.m_assetEntryCount)
return false;
}
assetIdx++;
// Check if we have a deadlock and report it if we have rtech_debug enabled.
if (bDebug && assetIdx >= 0x40000)
{
if (assetIdx == 0x40000) // Only log it once.
Warning(eDLL_T::RTECH, "Possible deadlock detected while processing asset '0x%-16llX' in pak '%-32s'. Uses: %-4i | assetIdxEntryGuid: '0x%-16llX' | currentGuid: '0x%-16llX'\n", asset->m_guid, pak->m_memoryData.m_fileName, asset->m_usesCount, assetIdxEntryGuid, currentGuid);
if (IsDebuggerPresent())
DebugBreak();
}
assetIdx &= 0x3FFFF;
assetIdxEntryGuid = g_pPakGlobals->m_assets[assetIdx].m_guid;
if (assetIdxEntryGuid == currentGuid)
return true;
}
};
if (assetIdxEntryGuid != currentGuid)
{
// Are we some special asset with the guid 2?
if (!fnCheckAsset(true))
{
PakAsset_t* assetEntries = pak->m_memoryData.m_assetEntries;
uint64_t a = 0;
for (; assetEntries->m_guid != currentGuid; a++, assetEntries++)
{
if (a >= pak->m_memoryData.m_pakHeader.m_assetEntryCount)
{
fnCheckAsset(false);
break;
}
}
assetIdx = pak->m_memoryData.qword2E0[a];
}
}
// Finally write the pointer to the guid entry.
*pCurrentGuid = g_pPakGlobals->m_assets[assetIdx].m_head;
}
}
//-----------------------------------------------------------------------------
// Purpose: load user-requested pak files on-demand
// Input : *fileName -
// *allocator -
// nIdx -
// bUnk -
// Output : pak file handle on success, INVALID_PAK_HANDLE on failure
//-----------------------------------------------------------------------------
PakHandle_t Pak_LoadAsync(const char* fileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk)
{
PakHandle_t pakHandle = INVALID_PAK_HANDLE;
CUtlString pakBasePath;
CUtlString pakOverridePath;
pakBasePath.Format(PLATFORM_PAK_PATH "%s", fileName);
pakOverridePath.Format(PLATFORM_PAK_OVERRIDE_PATH "%s", fileName);
if (FileExists(pakOverridePath.Get()) || FileExists(pakBasePath.Get()))
{
Msg(eDLL_T::RTECH, "Loading pak file: '%s'\n", fileName);
pakHandle = v_Pak_LoadAsync(fileName, allocator, nIdx, bUnk);
if (pakHandle == INVALID_PAK_HANDLE)
{
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed read '%s' results '%u'\n", __FUNCTION__, fileName, pakHandle);
}
}
else
{
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed; file '%s' doesn't exist\n", __FUNCTION__, fileName);
}
return pakHandle;
}
//-----------------------------------------------------------------------------
// Purpose: unloads loaded pak files
// Input : handle -
//-----------------------------------------------------------------------------
void Pak_UnloadPak(PakHandle_t handle)
{
PakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(handle);
if (pakInfo && pakInfo->m_fileName)
{
Msg(eDLL_T::RTECH, "Unloading pak file: '%s'\n", pakInfo->m_fileName);
if (strcmp(pakInfo->m_fileName, "mp_lobby.rpak") == 0)
s_bBasePaksInitialized = false;
}
v_Pak_UnloadPak(handle);
}
//----------------------------------------------------------------------------------
// Purpose: open a file and add it to the file handle array
// Input : *filePath -
// unused -
// *fileSizeOut -
// Output : slot index in the array to which the file was added in
//----------------------------------------------------------------------------------
int32_t Pak_OpenFile(const CHAR* filePath, int64_t unused, LONGLONG* fileSizeOut)
{
const CHAR* szFileToLoad = filePath;
CUtlString pakBasePath(filePath);
if (pakBasePath.Find(PLATFORM_PAK_PATH) != -1)
{
pakBasePath = pakBasePath.Replace(PLATFORM_PAK_PATH, PLATFORM_PAK_OVERRIDE_PATH);
if (FileExists(pakBasePath.Get()))
{
szFileToLoad = pakBasePath.Get();
}
}
const HANDLE hFile = CreateFileA(szFileToLoad, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, 0);
if (hFile == INVALID_HANDLE_VALUE)
return -1;
if (rtech_debug->GetBool())
Msg(eDLL_T::RTECH, "Opened file: '%s'\n", szFileToLoad);
if (fileSizeOut)
{
LARGE_INTEGER fileSize{};
if (GetFileSizeEx(hFile, &fileSize))
*fileSizeOut = fileSize.QuadPart;
}
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*s_pFileArrayMutex));
const int32_t fileIdx = RTech_FindFreeSlotInFiles(s_pFileArray);
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*s_pFileArrayMutex));
const int32_t fileHandleIdx = (fileIdx & 0x3FF); // Something with ArraySize.
s_pFileHandles->self[fileHandleIdx].m_nFileNumber = fileIdx;
s_pFileHandles->self[fileHandleIdx].m_hFileHandle = hFile;
s_pFileHandles->self[fileHandleIdx].m_nCurOfs = 1;
return fileIdx;
}
//----------------------------------------------------------------------------------
// Purpose: loads and processes a pak file (handles decompression and patching)
// Input : *pak -
// Output : true if patch source size == 0, false otherwise
// TODO: !!! FINISH REBUILD !!!
//----------------------------------------------------------------------------------
/*bool __fastcall Pak_ProcessPakFile(PakFile_t* pak)
{
PakFileHeader_t* pakHeader; // r8
__int64 dwordB8; // rcx
int v6; // eax
__int64 v7; // rax
char v8; // r13
signed __int64 index_Maybe; // rdi
char v10; // r15
__int64 v11; // rdx
const char* v12; // rbp
unsigned int v13; // eax
__int64 v14; // r12
char byteBF; // al
unsigned __int64 v16; // r9
unsigned __int8 v17; // cl
unsigned __int64 v18; // r8
__int64 v19; // rdx
uint8_t byte1F8; // al
uint8_t byte1FD; // cl
_BYTE* v22; // rdi
uint64_t v23; // rax
PakDecompState_t* p_m_pakDecompState; // rbp
__int64 decomp_size_var; // rax
uint64_t v26; // rdx
uint64_t qword1D0; // rcx
__int64 v28; // rax
unsigned int m_bitsRemaining; // r8d
char* m_patchData; // rdx
unsigned __int64 v31; // rax
uint64_t m_dataBuf; // r11
int v33; // r8d
uint64_t v34; // rax
int v35; // ecx
__int64 v36; // rdx
uint64_t v37; // r11
__int64(__fastcall * v38)(); // rax
int v39; // r10d
int v40; // r9d
uint64_t v41; // r11
unsigned int v42; // ecx
unsigned int v43; // r8d
unsigned int v44; // r12d
char byteBC; // r15
__int64 v46; // rbp
__int64 v47; // r8
unsigned __int64 v48; // rbp
unsigned __int64 qword8; // rax
__int64 v50; // rdi
__int64 patchCount; // rcx
__int64 v52; // r15
char v53; // al
char* v54; // rcx
char* i; // rdx
int v56; // edi
__int64 v57; // r15
unsigned __int64 v58; // rdx
char pak_path_var[260]; // [rsp+40h] [rbp-148h] BYREF
char v61[12]; // [rsp+144h] [rbp-44h] BYREF
unsigned __int64 v62; // [rsp+190h] [rbp+8h]
size_t pak_file_size_var; // [rsp+198h] [rbp+10h] BYREF
PakFileStream_t* fileStream = &pak->m_fileStream;
PakMemoryData_t* memoryData = &pak->m_memoryData;
dwordB8 = (unsigned int)pak->m_fileStream.dwordB8;
if ((_DWORD)dwordB8)
v62 = dwordB8 << 19;
else
v62 = 128i64;
v6 = fileStream->unsigned_intB4;
if (v6 != (_DWORD)dwordB8)
{
while (1)
{
v7 = v6 & 0x1F;
v8 = fileStream->gap94[v7];
if (v8 != 1)
break;
LABEL_17:
v6 = fileStream->unsigned_intB4 + 1;
fileStream->unsigned_intB4 = v6;
if (v6 == fileStream->dwordB8)
goto LABEL_18;
}
index_Maybe = (unsigned __int64)LOBYTE(fileStream->gap14[v7]) << 6;
v10 = *((_BYTE*)&g_pakStatusSlots[0].someState + index_Maybe);
switch (v10)
{
case 0:
goto LABEL_18;
case 2:
v11 = *(unsigned int*)((char*)&g_pakStatusSlots[0].unk7 + index_Maybe);
if ((_DWORD)v11 == 0x8716253)
v12 = "Error: Short read.";
else
v12 = StrPrintf("Error 0x%08x", v11);
break;
case 3:
v12 = "Cancelled.";
break;
default:
v12 = "OK";
if (v10 == 1)
{
v13 = *(int*)((char*)&g_pakStatusSlots[0].unk6 + index_Maybe);
goto LABEL_11;
}
break;
}
v13 = 0;
LABEL_11:
v14 = v13;
v_Pak_CloseFile(*(int*)((char*)&g_pakStatusSlots[0].unk4 + index_Maybe));
AcquireSRWLockExclusive(&stru_16721D260);
RTech::FreeSlotInFiles((__int64)&dword_16721D240, index_Maybe >> 6);
ReleaseSRWLockExclusive(&stru_16721D260);
if (v10 == 2)
Error(eDLL_T::RTECH, EXIT_FAILURE, "Error reading pak file \"%s\" -- %s\n", pak->m_memoryData.m_fileName, v12);
fileStream->qword1D0 += v14;
if (v8)
{
byteBF = fileStream->byteBF;
pakHeader = &pak->m_memoryData.m_pakHeader;
v16 = (unsigned __int64)fileStream->unsigned_intB4 << 19;
v17 = byteBF & 7;
fileStream->byteBF = byteBF + 1;
if (v8 == 2)
{
v18 = v16 & fileStream->qword1C8;
fileStream->qword1D0 = v14 + v16;
pakHeader = (PakFileHeader_t*)&fileStream->buffer[v18];
}
v19 = 32i64 * v17;
*(_QWORD*)&fileStream->gapC0[32 * v17] = v16 + 128;
*(_QWORD*)&fileStream->gapC0[v19 + 8] = v16 + pakHeader->m_compressedSize;
*(_QWORD*)&fileStream->gapC0[v19 + 16] = pakHeader->m_decompressedSize;
fileStream->gapC0[v19 + 24] = pakHeader->m_flags[1] & 1;
}
goto LABEL_17;
}
LABEL_18:
byte1F8 = pak->byte1F8;
if (byte1F8 != fileStream->byteBF)
{
byte1FD = pak->byte1FD;
do
{
v22 = &fileStream->gapC0[32 * (byte1F8 & 7)];
if (byte1FD)
{
pak->byte1FD = 0;
pak->m_inputBytePos = *(_QWORD*)v22;
if (v22[24])
{
pak->flags_1FE = 256;
v23 = 128i64;
}
else
{
pak->flags_1FE = 1;
v23 = *(_QWORD*)v22;
}
memoryData->m_processedPatchedDataSize = v23;
if (!HIBYTE(pak->flags_1FE))
{
LABEL_35:
v26 = *((_QWORD*)v22 + 1);
qword1D0 = v26;
if (fileStream->qword1D0 < v26)
qword1D0 = fileStream->qword1D0;
goto LABEL_41;
}
p_m_pakDecompState = &pak->m_pakDecompState;
decomp_size_var = RTech::DecompressedSize(
&pak->m_pakDecompState,
(uint64_t)fileStream->buffer,
(__int64)pakHeader,
*((_QWORD*)v22 + 1) - (*(_QWORD*)v22 - sizeof(PakFileHeader_t)),
*(_QWORD*)v22 - sizeof(PakFileHeader_t));
if (decomp_size_var != *((_QWORD*)v22 + 2))
{
Error(eDLL_T::RTECH, EXIT_FAILURE,
"Error reading pak file \"%s\" -- decompressed size %u doesn't match expected value %u\n",
pak->m_memoryData.m_fileName,
decomp_size_var + sizeof(PakFileHeader_t),
pak->m_memoryData.m_pakHeader.m_decompressedSize);
}
pak->m_pakDecompState.m_outputBuf = (uint64_t)pak->m_decompBuffer;
pak->m_pakDecompState.m_outputMask = 0x3FFFFFi64;
}
else
{
p_m_pakDecompState = &pak->m_pakDecompState;
}
if (!HIBYTE(pak->flags_1FE))
goto LABEL_35;
qword1D0 = pak->m_pakDecompState.m_decompBytePosition;
if (qword1D0 != pak->m_pakDecompState.m_decompSize)
{
Rtech::Decompress(p_m_pakDecompState, fileStream->qword1D0, memoryData->m_processedPatchedDataSize + 0x400000);
qword1D0 = pak->m_pakDecompState.m_decompBytePosition;
pak->m_inputBytePos = pak->m_pakDecompState.m_fileBytePosition;
}
v26 = *((_QWORD*)v22 + 1);
LABEL_41:
if (pak->m_inputBytePos != v26 || memoryData->m_processedPatchedDataSize != qword1D0)
goto LABEL_45;
byte1FD = 1;
byte1F8 = pak->byte1F8 + 1;
pak->byte1FD = 1;
pak->byte1F8 = byte1F8;
} while (byte1F8 != fileStream->byteBF);
}
qword1D0 = memoryData->m_processedPatchedDataSize;
LABEL_45:
v28 = memoryData->field_2A8;
pak_file_size_var = qword1D0 - memoryData->m_processedPatchedDataSize;
if (memoryData->m_patchSrcSize + v28)
{
do
{
if (!memoryData->m_numBytesToProcess_maybe)
{
m_bitsRemaining = memoryData->m_bitBuf.m_bitsRemaining;
m_patchData = memoryData->m_patchData;
memoryData->m_bitBuf.m_dataBuf |= *m_patchData << (64 - (unsigned __int8)m_bitsRemaining);
v31 = m_bitsRemaining;
m_dataBuf = memoryData->m_bitBuf.m_dataBuf;
v33 = m_bitsRemaining & 7;
memoryData->m_bitBuf.m_bitsRemaining = v33;
memoryData->m_patchData = m_patchData + (v31 >> 3);
v34 = m_dataBuf & 0x3F;
v35 = (unsigned __int8)memoryData->PATCH_field_68[v34];
v36 = (unsigned __int8)memoryData->patchCommands[v34];
v37 = m_dataBuf >> v35;
memoryData->m_bitBuf.m_dataBuf = v37;
v38 = s_pakPatchFuncs[v36];
memoryData->m_bitBuf.m_bitsRemaining = v33 + v35;
memoryData->patchFunc = (unsigned __int8(__fastcall*)(PakFile_t*, unsigned __int64*))v38;
if ((unsigned __int8)v36 > 3u)
{
memoryData->m_numBytesToProcess_maybe = *((unsigned int*)&off_141367980 + v36);
}
else
{
v39 = (unsigned __int8)memoryData->PATCH_unk3[(unsigned __int8)v37];
v40 = (unsigned __int8)memoryData->PATCH_unk2[(unsigned __int8)v37];
v41 = v37 >> memoryData->PATCH_unk3[(unsigned __int8)v37];
memoryData->m_bitBuf.m_dataBuf = v41 >> v40;
memoryData->m_numBytesToProcess_maybe = (1i64 << v40) + (v41 & ((1i64 << v40) - 1));
memoryData->m_bitBuf.m_bitsRemaining = v33 + v35 + v40 + v39;
}
}
} while (pak->m_memoryData.patchFunc(pak, &pak_file_size_var) && memoryData->m_patchSrcSize + memoryData->field_2A8);
}
if (LOBYTE(pak->flags_1FE))
pak->m_inputBytePos = memoryData->m_processedPatchedDataSize;
if (!fileStream->byteBD)
{
v42 = fileStream->unsigned_intB4;
v43 = fileStream->dwordB8;
if ((unsigned int)(pak->m_inputBytePos >> 19) < v42)
v42 = pak->m_inputBytePos >> 19;
v44 = v42 + 32;
if (v43 != v42 + 32)
{
while (1)
{
byteBC = fileStream->byteBC;
v46 = v43;
v47 = v43 & 0x1F;
v48 = (v46 + 1) << 19;
if (byteBC == 1)
break;
qword8 = fileStream->qword8;
if (v62 < qword8)
{
v50 = (unsigned int)v47;
if (v48 < qword8)
qword8 = v48;
fileStream->gap14[(unsigned int)v47] = Pak_SetFileStreamContext(
fileStream->fileHandle,
v62 - fileStream->qword0,
qword8 - v62,
&fileStream->buffer[v62 & fileStream->qword1C8],
0i64,
0i64,
4);
fileStream->gap94[v50] = byteBC;
fileStream->byteBC = 0;
goto LABEL_65;
}
if (pak->m_patchCount >= LOWORD(pak->m_memoryData.m_pakHeader.m_patchIndex))
{
v_Pak_CloseFile(fileStream->fileHandle);
fileStream->fileHandle = -1;
fileStream->qword0 = 0i64;
fileStream->byteBD = 1;
return memoryData->m_patchSrcSize == 0;
}
if (!pak->dword14)
return memoryData->m_patchSrcSize == 0;
sprintf(pak_path_var, "paks\\Win64\\%s", pak->m_memoryData.m_fileName);
patchCount = pak->m_patchCount;
v52 = (unsigned int)patchCount;
pak->m_patchCount = patchCount + 1;
if (pak->m_memoryData.UnkPatchIndexes[patchCount])
{
v53 = pak_path_var[0];
v54 = pak_path_var;
for (i = 0i64; v53; ++v54)
{
if (v53 == '.')
{
i = v54;
}
else if (v53 == '\\' || v53 == '/')
{
i = 0i64;
}
v53 = v54[1];
}
if (i)
v54 = i;
snprintf(v54, v61 - v54, "(%02u).rpak");
}
v56 = v_Pak_OpenFile(pak_path_var, 5i64, (__int64*)&pak_file_size_var);
if (v56 == -1)
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't open file \"%s\".\n", pak_path_var);
v57 = v52;
if (pak_file_size_var < pak->m_memoryData.m_patchHeaders[v57].m_sizeDisk)
Error(eDLL_T::RTECH, EXIT_FAILURE, "File \"%s\" appears truncated.\n", pak_path_var);
v_Pak_CloseFile(fileStream->fileHandle);
v43 = fileStream->dwordB8;
fileStream->fileHandle = v56;
v58 = (unsigned __int64)((v43 + 7) & 0xFFFFFFF8) << 19;
fileStream->qword0 = v58;
fileStream->byteBC = (v43 == ((v43 + 7) & 0xFFFFFFF8)) + 1;
fileStream->qword8 = v58 + pak->m_memoryData.m_patchHeaders[v57].m_sizeDisk;
LABEL_84:
if (v43 == v44)
return memoryData->m_patchSrcSize == 0;
}
fileStream->gap14[v47] = -2;
fileStream->gap94[v47] = 1;
if ((((_BYTE)v47 + 1) & 7) == 0)
fileStream->byteBC = 2;
LABEL_65:
v43 = ++fileStream->dwordB8;
v62 = v48;
goto LABEL_84;
}
}
return memoryData->m_patchSrcSize == 0;
}*/
void V_RTechGame::Detour(const bool bAttach) const
{
DetourSetup(&v_Pak_OpenFile, &Pak_OpenFile, bAttach);
DetourSetup(&v_Pak_LoadAsync, &Pak_LoadAsync, bAttach);
DetourSetup(&v_Pak_UnloadPak, &Pak_UnloadPak, bAttach);
//DetourSetup(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset, bAttach);
}
// Symbols taken from R2 dll's.
PakLoadFuncs_t* g_pakLoadApi = nullptr;