r5sdk/r5dev/rtech/rtech_utils.cpp
Kawe Mazidjatari 8d38de1ce0 Move client only code from rtech libraries
Moved, and renamed to 'CreateTextureResource'. Reason for move was that the rtech libraries is used by server and client, and using this on dedicated requires linking directx libraries, as it has to be hooked (even when not used). Moved to client only code to avoid having to hook it. Material system is no longer linked to the dedicated server module, as nothing from it was getting used.
2023-05-13 18:03:48 +02:00

723 lines
25 KiB
C++

#include "core/stdafx.h"
#include "tier1/cvar.h"
#include "rtech/rtech_utils.h"
#ifndef DEDICATED
#include "windows/id3dx.h"
#include "materialsystem/cshaderglue.h"
#include "public/rendersystem/schema/texture.g.h"
#endif // !DEDICATED
/******************************************************************************
-------------------------------------------------------------------------------
File : rtech.cpp
Date : 18:07:2021
Author : Kawe Mazidjatari
Purpose: Implements the 'rtech_game' core utilities
-------------------------------------------------------------------------------
History:
- 18:07:2021 | 13:02 : Created by Kawe Mazidjatari
- 10:09:2021 | 18:22 : Implement 'StringToGuid' method
- 12:11:2021 | 14:41 : Add decompression method to ConCommand callback
- 25:12:2021 | 23:20 : Made everything more readable thanks to bezdna5-rs
- 28:03:2022 | 18:00 : Added getting pak info by PakID.
******************************************************************************/
//-----------------------------------------------------------------------------
// Purpose: calculate 'GUID' from input data
//-----------------------------------------------------------------------------
uint64_t __fastcall RTech::StringToGuid(const char* pData)
{
uint32_t* v1; // r8
uint64_t v2; // r10
int32_t v3; // er11
uint32_t v4; // er9
uint32_t i; // edx
uint64_t v6; // rcx
int32_t v7; // er9
int32_t v8; // edx
int32_t v9; // eax
uint32_t v10; // er8
int32_t v12; // ecx
uint32_t* a1 = (uint32_t*)pData;
v1 = a1;
v2 = 0i64;
v3 = 0;
v4 = (*a1 - 45 * ((~(*a1 ^ 0x5C5C5C5Cu) >> 7) & (((*a1 ^ 0x5C5C5C5Cu) - 0x1010101) >> 7) & 0x1010101)) & 0xDFDFDFDF;
for (i = ~*a1 & (*a1 - 0x1010101) & 0x80808080; !i; i = v8 & 0x80808080)
{
v6 = v4;
v7 = v1[1];
++v1;
v3 += 4;
v2 = ((((uint64_t)(0xFB8C4D96501i64 * v6) >> 24) + 0x633D5F1 * v2) >> 61) ^ (((uint64_t)(0xFB8C4D96501i64 * v6) >> 24)
+ 0x633D5F1 * v2);
v8 = ~v7 & (v7 - 0x1010101);
v4 = (v7 - 45 * ((~(v7 ^ 0x5C5C5C5Cu) >> 7) & (((v7 ^ 0x5C5C5C5Cu) - 0x1010101) >> 7) & 0x1010101)) & 0xDFDFDFDF;
}
v9 = -1;
v10 = (i & -(signed)i) - 1;
if (_BitScanReverse((unsigned long*)&v12, v10))
{
v9 = v12;
}
return 0x633D5F1 * v2 + ((0xFB8C4D96501i64 * (uint64_t)(v4 & v10)) >> 24) - 0xAE502812AA7333i64 * (uint32_t)(v3 + v9 / 8);
}
//-----------------------------------------------------------------------------
// Purpose: calculate 'decompressed' size and commit parameters
//-----------------------------------------------------------------------------
uint64_t __fastcall RTech::DecompressPakFileInit(RPakDecompState_t* state, uint8_t* fileBuffer, uint64_t fileSize, uint64_t offNoHeader, uint64_t headerSize)
{
int64_t input_byte_pos_init; // r9
uint64_t byte_init; // r11
int32_t decompressed_size_bits; // ecx
int64_t byte_1_low; // rdi
uint64_t input_byte_pos_1; // r10
uint32_t bit_pos_final; // ebp
uint64_t byte_1; // rdi
uint32_t brih_bits; // er11
uint64_t inv_mask_in; // r8
uint64_t byte_final_full; // rbx
uint64_t bit_pos_final_1; // rax
int32_t byte_bit_offset_final; // ebp
uint64_t input_byte_pos_final; // r10
uint64_t byte_final; // rbx
uint32_t brih_bytes; // er11
uint64_t byte_tmp; // rdx
uint64_t stream_len_needed; // r14
uint64_t result; // rax
uint64_t inv_mask_out; // r8
uint64_t qw70; // rcx
uint64_t stream_compressed_size_new; // rdx
const uintptr_t mask = UINT64_MAX;
const uintptr_t file_buf = uintptr_t(fileBuffer);
state->m_nInputBuf = file_buf;
state->m_nOut = 0i64;
state->m_nOutMask = 0i64;
state->dword44 = 0;
state->m_nTotalFileLen = fileSize + offNoHeader;
state->m_nMask = mask;
input_byte_pos_init = offNoHeader + headerSize + 8;
byte_init = *(uint64_t*)((mask & (offNoHeader + headerSize)) + file_buf);
state->m_nDecompPosition = headerSize;
decompressed_size_bits = byte_init & 0x3F;
byte_init >>= 6;
state->m_nInputBytePos = input_byte_pos_init;
state->m_nDecompSize = (byte_init & ((1i64 << decompressed_size_bits) - 1)) | (1i64 << decompressed_size_bits);
byte_1_low = *(uint64_t*)((mask & input_byte_pos_init) + file_buf) << (64
- ((uint8_t)decompressed_size_bits
+ 6));
input_byte_pos_1 = input_byte_pos_init + ((uint64_t)(uint32_t)(decompressed_size_bits + 6) >> 3);
state->m_nInputBytePos = input_byte_pos_1;
bit_pos_final = ((decompressed_size_bits + 6) & 7) + 13;
byte_1 = (0xFFFFFFFFFFFFFFFFui64 >> ((decompressed_size_bits + 6) & 7)) & ((byte_init >> decompressed_size_bits) | byte_1_low);
brih_bits = (((uint8_t)byte_1 - 1) & 0x3F) + 1;
inv_mask_in = 0xFFFFFFFFFFFFFFFFui64 >> (64 - (uint8_t)brih_bits);
state->m_nInvMaskIn = inv_mask_in;
state->m_nInvMaskOut = 0xFFFFFFFFFFFFFFFFui64 >> (63 - (((byte_1 >> 6) - 1) & 0x3F));
byte_final_full = (byte_1 >> 13) | (*(uint64_t*)((mask & input_byte_pos_1) + file_buf) << (64
- (uint8_t)bit_pos_final));
bit_pos_final_1 = bit_pos_final;
byte_bit_offset_final = bit_pos_final & 7;
input_byte_pos_final = (bit_pos_final_1 >> 3) + input_byte_pos_1;
byte_final = (0xFFFFFFFFFFFFFFFFui64 >> byte_bit_offset_final) & byte_final_full;
state->m_nInputBytePos = input_byte_pos_final;
if (inv_mask_in == -1i64)
{
state->m_nHeaderOffset = 0;
stream_len_needed = fileSize;
}
else
{
brih_bytes = brih_bits >> 3;
state->m_nHeaderOffset = brih_bytes + 1;
byte_tmp = *(uint64_t*)((mask & input_byte_pos_final) + file_buf);
state->m_nInputBytePos = input_byte_pos_final + brih_bytes + 1;
stream_len_needed = byte_tmp & ((1i64 << (8 * ((uint8_t)brih_bytes + 1))) - 1);
}
result = state->m_nDecompSize;
inv_mask_out = state->m_nInvMaskOut;
qw70 = offNoHeader + state->m_nInvMaskIn - 6i64;
state->m_nLengthNeeded = stream_len_needed + offNoHeader;
state->qword70 = qw70;
state->byte = byte_final;
state->m_nByteBitOffset = byte_bit_offset_final;
state->dword6C = 0;
state->m_nCompressedStreamSize = stream_len_needed + offNoHeader;
state->m_nDecompStreamSize = result;
if (result - 1 > inv_mask_out)
{
stream_compressed_size_new = stream_len_needed + offNoHeader - state->m_nHeaderOffset;
state->m_nDecompStreamSize = inv_mask_out + 1;
state->m_nCompressedStreamSize = stream_compressed_size_new;
}
return result;
}
//-----------------------------------------------------------------------------
// Purpose: decompress input data
//-----------------------------------------------------------------------------
uint8_t __fastcall RTech::DecompressPakFile(RPakDecompState_t* state, uint64_t inLen, uint64_t outLen)
{
char result; // al
uint64_t v5; // r15
uint64_t v6; // r11
uint32_t v7; // ebp
uint64_t v8; // rsi
uint64_t v9; // rdi
uint64_t v10; // r12
uint64_t v11; // r13
uint32_t v12; // ecx
uint64_t v13; // rsi
uint64_t i; // rax
uint64_t v15; // r8
int64_t v16; // r9
int v17; // ecx
uint64_t v18; // rax
uint64_t v19; // rsi
int64_t v20; // r14
int v21; // ecx
uint64_t v22; // r11
int v23; // edx
uint64_t v24; // rax
int v25; // er8
uint32_t v26; // er13
uint64_t v27; // r10
uint64_t v28; // rax
_QWORD* v29; // r10
uint64_t v30; // r9
uint64_t v31; // r10
uint64_t v32; // r8
uint64_t v33; // rax
uint64_t v34; // rax
uint64_t v35; // rax
uint64_t v36; // rcx
int64_t v37; // rdx
uint64_t v38; // r14
uint64_t v39; // r11
char v40; // cl
uint64_t v41; // rsi
int64_t v42; // rcx
uint64_t v43; // r8
int v44; // er11
uint8_t v45; // r9
uint64_t v46; // rcx
uint64_t v47; // rcx
int64_t v48; // r9
int64_t l; // r8
uint32_t v50; // er9
int64_t v51; // r8
int64_t v52; // rdx
int64_t k; // r8
char* v54; // r10
int64_t v55; // rdx
uint32_t v56; // er14
int64_t* v57; // rdx
int64_t* v58; // r8
char v59; // al
uint64_t v60; // rsi
int64_t v61; // rax
uint64_t v62; // r9
int v63; // er10
uint8_t v64; // cl
uint64_t v65; // rax
uint32_t v66; // er14
uint32_t j; // ecx
int64_t v68; // rax
uint64_t v69; // rcx
uint64_t v70; // [rsp+0h] [rbp-58h]
uint32_t v71; // [rsp+60h] [rbp+8h]
uint64_t v74; // [rsp+78h] [rbp+20h]
if (inLen < state->m_nLengthNeeded)
return 0;
v5 = state->m_nDecompPosition;
if (outLen < state->m_nInvMaskOut + (v5 & ~state->m_nInvMaskOut) + 1 && outLen < state->m_nDecompSize)
return 0;
v6 = state->m_nOut;
v7 = state->m_nByteBitOffset;
v8 = state->byte;
v9 = state->m_nInputBytePos;
v10 = state->qword70;
v11 = state->m_nInputBuf;
if (state->m_nCompressedStreamSize < v10)
v10 = state->m_nCompressedStreamSize;
v12 = state->dword6C;
v74 = v11;
v70 = v6;
v71 = v12;
if (!v7)
goto LABEL_11;
v13 = (*(_QWORD*)((v9 & state->m_nMask) + v11) << (64 - (unsigned __int8)v7)) | v8;
for (i = v7; ; i = v7)
{
v7 &= 7u;
v9 += i >> 3;
v12 = v71;
v8 = (0xFFFFFFFFFFFFFFFFui64 >> v7) & v13;
LABEL_11:
v15 = (unsigned __int64)v12 << 8;
v16 = v12;
v17 = *((unsigned __int8*)&s_PakFileCompressionLUT + (unsigned __int8)v8 + v15 + 512);
v18 = (unsigned __int8)v8 + v15;
v7 += v17;
v19 = v8 >> v17;
v20 = (unsigned int)*((char*)&s_PakFileCompressionLUT + v18);
if (*((char*)&s_PakFileCompressionLUT + v18) < 0)
{
v56 = -(int)v20;
v57 = (__int64*)(v11 + (v9 & state->m_nMask));
v71 = 1;
v58 = (__int64*)(v6 + (v5 & state->m_nOutMask));
if (v56 == *((unsigned __int8*)&s_PakFileCompressionLUT + v16 + 1248))
{
if ((~v9 & state->m_nInvMaskIn) < 0xF || (state->m_nInvMaskOut & ~v5) < 15 || state->m_nDecompSize - v5 < 0x10)
v56 = 1;
v59 = char(v19);
v60 = v19 >> 3;
v61 = v59 & 7;
v62 = v60;
if (v61)
{
v63 = *((unsigned __int8*)&s_PakFileCompressionLUT + v61 + 1232);
v64 = *((_BYTE*)&s_PakFileCompressionLUT + v61 + 1240);
}
else
{
v62 = v60 >> 4;
v65 = v60 & 0xF;
v7 += 4;
v63 = *((_DWORD*)&s_PakFileCompressionLUT + v65 + 288);
v64 = *((_BYTE*)&s_PakFileCompressionLUT + v65 + 1216);
}
v7 += v64 + 3;
v19 = v62 >> v64;
v66 = v63 + (v62 & ((1 << v64) - 1)) + v56;
for (j = v66 >> 3; j; --j)
{
v68 = *v57++;
*v58++ = v68;
}
if ((v66 & 4) != 0)
{
*(_DWORD*)v58 = *(_DWORD*)v57;
v58 = (__int64*)((char*)v58 + 4);
v57 = (__int64*)((char*)v57 + 4);
}
if ((v66 & 2) != 0)
{
*(_WORD*)v58 = *(_WORD*)v57;
v58 = (__int64*)((char*)v58 + 2);
v57 = (__int64*)((char*)v57 + 2);
}
if ((v66 & 1) != 0)
*(_BYTE*)v58 = *(_BYTE*)v57;
v9 += v66;
v5 += v66;
}
else
{
*v58 = *v57;
v58[1] = v57[1];
v9 += v56;
v5 += v56;
}
}
else
{
v21 = v19 & 0xF;
v71 = 0;
v22 = ((unsigned __int64)(unsigned int)v19 >> (((unsigned int)(v21 - 31) >> 3) & 6)) & 0x3F;
v23 = 1 << (v21 + ((v19 >> 4) & ((24 * (((unsigned int)(v21 - 31) >> 3) & 2)) >> 4)));
v7 += (((unsigned int)(v21 - 31) >> 3) & 6) + *((unsigned __int8*)&s_PakFileCompressionLUT + v22 + 1088) + v21 + ((v19 >> 4) & ((24 * (((unsigned int)(v21 - 31) >> 3) & 2)) >> 4));
v24 = state->m_nOutMask;
v25 = 16 * (v23 + ((v23 - 1) & (v19 >> ((((unsigned int)(v21 - 31) >> 3) & 6) + *((_BYTE*)&s_PakFileCompressionLUT + v22 + 1088)))));
v19 >>= (((unsigned int)(v21 - 31) >> 3) & 6) + *((_BYTE*)&s_PakFileCompressionLUT + v22 + 1088) + v21 + ((v19 >> 4) & ((24 * (((unsigned int)(v21 - 31) >> 3) & 2)) >> 4));
v26 = v25 + *((unsigned __int8*)&s_PakFileCompressionLUT + v22 + 1024) - 16;
v27 = v24 & (v5 - v26);
v28 = v70 + (v5 & v24);
v29 = (_QWORD*)(v70 + v27);
if ((_DWORD)v20 == 17)
{
v40 = char(v19);
v41 = v19 >> 3;
v42 = v40 & 7;
v43 = v41;
if (v42)
{
v44 = *((unsigned __int8*)&s_PakFileCompressionLUT + v42 + 1232);
v45 = *((_BYTE*)&s_PakFileCompressionLUT + v42 + 1240);
}
else
{
v7 += 4;
v46 = v41 & 0xF;
v43 = v41 >> 4;
v44 = *((_DWORD*)&s_PakFileCompressionLUT + v46 + 288);
v45 = *((_BYTE*)&s_PakFileCompressionLUT + v46 + 1216);
if (v74 && v7 + v45 >= 61)
{
v47 = v9++ & state->m_nMask;
v43 |= (unsigned __int64)*(unsigned __int8*)(v47 + v74) << (61 - (unsigned __int8)v7);
v7 -= 8;
}
}
v7 += v45 + 3;
v19 = v43 >> v45;
v48 = ((unsigned int)v43 & ((1 << v45) - 1)) + v44 + 17;
v5 += v48;
if (v26 < 8)
{
v50 = uint32_t(v48 - 13);
v5 -= 13i64;
if (v26 == 1)
{
v51 = *(unsigned __int8*)v29;
//++dword_14D40B2BC;
v52 = 0i64;
for (k = 0x101010101010101i64 * v51; (unsigned int)v52 < v50; v52 = (unsigned int)(v52 + 8))
*(_QWORD*)(v52 + v28) = k;
}
else
{
//++dword_14D40B2B8;
if (v50)
{
v54 = (char*)v29 - v28;
v55 = v50;
do
{
*(_BYTE*)v28 = v54[v28];
++v28;
--v55;
} while (v55);
}
}
}
else
{
//++dword_14D40B2AC;
for (l = 0i64; (unsigned int)l < (unsigned int)v48; l = (unsigned int)(l + 8))
*(_QWORD*)(l + v28) = *(_QWORD*)((char*)v29 + l);
}
}
else
{
v5 += v20;
*(_QWORD*)v28 = *v29;
*(_QWORD*)(v28 + 8) = v29[1];
}
v11 = v74;
}
if (v9 >= v10)
break;
LABEL_29:
v6 = v70;
v13 = (*(_QWORD*)((v9 & state->m_nMask) + v11) << (64 - (unsigned __int8)v7)) | v19;
}
if (v5 != state->m_nDecompStreamSize)
goto LABEL_25;
v30 = state->m_nDecompSize;
if (v5 == v30)
{
result = 1;
goto LABEL_69;
}
v31 = state->m_nInvMaskIn;
v32 = state->m_nHeaderOffset;
v33 = v31 & -(__int64)v9;
v19 >>= 1;
++v7;
if (v32 > v33)
{
v9 += v33;
v34 = state->qword70;
if (v9 > v34)
state->qword70 = v31 + v34 + 1;
}
v35 = v9 & state->m_nMask;
v9 += v32;
v36 = v5 + state->m_nInvMaskOut + 1;
v37 = *(_QWORD*)(v35 + v11) & ((1i64 << (8 * (unsigned __int8)v32)) - 1);
v38 = v37 + state->m_nLengthNeeded;
v39 = v37 + state->m_nCompressedStreamSize;
state->m_nLengthNeeded = v38;
state->m_nCompressedStreamSize = v39;
if (v36 >= v30)
{
v36 = v30;
state->m_nCompressedStreamSize = v32 + v39;
}
state->m_nDecompStreamSize = v36;
if (inLen >= v38 && outLen >= v36)
{
LABEL_25:
v10 = state->qword70;
if (v9 >= v10)
{
v9 = ~state->m_nInvMaskIn & (v9 + 7);
v10 += state->m_nInvMaskIn + 1;
state->qword70 = v10;
}
if (state->m_nCompressedStreamSize < v10)
v10 = state->m_nCompressedStreamSize;
goto LABEL_29;
}
v69 = state->qword70;
if (v9 >= v69)
{
v9 = ~v31 & (v9 + 7);
state->qword70 = v69 + v31 + 1;
}
state->dword6C = v71;
result = 0;
state->byte = v19;
state->m_nByteBitOffset = v7;
LABEL_69:
state->m_nDecompPosition = v5;
state->m_nInputBytePos = v9;
return result;
}
//----------------------------------------------------------------------------------
// Purpose: start loading shader sets, assign vftable pointer
//----------------------------------------------------------------------------------
void** RTech::LoadShaderSet(void** VTablePtr)
{
*VTablePtr = &g_pShaderGlueVFTable;
return &g_pShaderGlueVFTable;
}
//----------------------------------------------------------------------------------
// Purpose: open a file and add it to m_FileHandles.
//----------------------------------------------------------------------------------
int32_t RTech::OpenFile(const CHAR* szFilePath, void* unused, LONGLONG* fileSizeOut)
{
string svModFile = szFilePath;
string svBaseFile = szFilePath;
const string svModDir = "paks\\Win32\\";
const string svBaseDir = "paks\\Win64\\";
if (strstr(ConvertToWinPath(szFilePath).c_str(), svBaseDir.c_str()))
{
svBaseFile.erase(0, 11); // Erase 'base_dir'.
svModFile = svModDir + svBaseFile; // Prepend 'mod_dir'.
if (!FileExists(svModFile))
{
svModFile = szFilePath;
}
}
const HANDLE hFile = CreateFileA(svModFile.c_str(), 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())
DevMsg(eDLL_T::RTECH, "Opened file: '%s'\n", svModFile.c_str());
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: gets information about loaded pak file via pak ID
//-----------------------------------------------------------------------------
RPakLoadedInfo_t* RTech::GetPakLoadedInfo(RPakHandle_t nHandle)
{
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
{
RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
if (!info)
continue;
if (info->m_nHandle != nHandle)
continue;
return info;
}
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for handle '%d'\n", __FUNCTION__, nHandle);
return nullptr;
}
//-----------------------------------------------------------------------------
// Purpose: gets information about loaded pak file via pak name
//-----------------------------------------------------------------------------
RPakLoadedInfo_t* RTech::GetPakLoadedInfo(const char* szPakName)
{
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
{
RPakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
if (!info)
continue;
if (!info->m_pszFileName || !*info->m_pszFileName)
continue;
if (strcmp(szPakName, info->m_pszFileName) != 0)
continue;
return info;
}
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for name '%s'\n", __FUNCTION__, szPakName);
return nullptr;
}
//-----------------------------------------------------------------------------
// Purpose: returns pak status as string
//-----------------------------------------------------------------------------
const char* RTech::PakStatusToString(RPakStatus_t status)
{
switch (status)
{
case RPakStatus_t::PAK_STATUS_FREED: return "PAK_STATUS_FREED";
case RPakStatus_t::PAK_STATUS_LOAD_PENDING: return "PAK_STATUS_LOAD_PENDING";
case RPakStatus_t::PAK_STATUS_REPAK_RUNNING: return "PAK_STATUS_REPAK_RUNNING";
case RPakStatus_t::PAK_STATUS_REPAK_DONE: return "PAK_STATUS_REPAK_DONE";
case RPakStatus_t::PAK_STATUS_LOAD_STARTING: return "PAK_STATUS_LOAD_STARTING";
case RPakStatus_t::PAK_STATUS_LOAD_PAKHDR: return "PAK_STATUS_LOAD_PAKHDR";
case RPakStatus_t::PAK_STATUS_LOAD_PATCH_INIT: return "PAK_STATUS_LOAD_PATCH_INIT";
case RPakStatus_t::PAK_STATUS_LOAD_PATCH_EDIT_STREAM: return "PAK_STATUS_LOAD_PATCH_EDIT_STREAM";
case RPakStatus_t::PAK_STATUS_LOAD_ASSETS: return "PAK_STATUS_LOAD_ASSETS";
case RPakStatus_t::PAK_STATUS_LOADED: return "PAK_STATUS_LOADED";
case RPakStatus_t::PAK_STATUS_UNLOAD_PENDING: return "PAK_STATUS_UNLOAD_PENDING";
case RPakStatus_t::PAK_STATUS_FREE_PENDING: return "PAK_STATUS_FREE_PENDING";
case RPakStatus_t::PAK_STATUS_CANCELING: return "PAK_STATUS_CANCELING";
case RPakStatus_t::PAK_STATUS_ERROR: return "PAK_STATUS_ERROR";
case RPakStatus_t::PAK_STATUS_INVALID_PAKHANDLE: return "PAK_STATUS_INVALID_PAKHANDLE";
case RPakStatus_t::PAK_STATUS_BUSY: return "PAK_STATUS_BUSY";
default: return "PAK_STATUS_UNKNOWN";
}
}
#ifdef GAMEDLL_S3
//-----------------------------------------------------------------------------
// Purpose: process guid relations for asset
//-----------------------------------------------------------------------------
void RTech::PakProcessGuidRelationsForAsset(PakFile_t* pPak, RPakAssetEntry_t* pAsset)
{
#if defined (GAMEDLL_S0) && defined (GAMEDLL_S1) && defined (GAMEDLL_S2)
static const int GLOBAL_MUL = 0x1D;
#else
static const int GLOBAL_MUL = 0x17;
#endif
RPakDescriptor_t* pGuidDescriptors = &pPak->m_pGuidDescriptors[pAsset->m_nUsesStartIdx];
volatile uint32_t* v5 = reinterpret_cast<volatile uint32_t*>(*(reinterpret_cast<uint64_t*>(g_pPakGlobals) + GLOBAL_MUL * (pPak->qword578 & 0x1FF) + 0x160212));
const bool bDebug = rtech_debug->GetBool();
if (bDebug)
DevMsg(eDLL_T::RTECH, "Processing GUID relations for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount);
for (uint32_t i = 0; i < pAsset->m_nUsesCount; i++)
{
void** pCurrentGuid = reinterpret_cast<void**>(pPak->m_ppPagePointers[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])) = pAsset->m_Guid;
std::function<bool(bool)> fnCheckAsset = [&](bool shouldCheckTwo)
{
while (true)
{
if (shouldCheckTwo && assetIdxEntryGuid == 2)
{
if (pPak->m_PakHdr.m_nAssetEntryCount)
return false;
}
assetIdx++;
// Check if we have a deadlock and report it if we have rtech_debug enabled.
if (bDebug && assetIdx >= 0x40000)
{
Warning(eDLL_T::RTECH, "Possible deadlock detected while processing asset '0x%-16llX' in pak '%-32s'. Uses: %-4i | assetIdxEntryGuid: '0x%-16llX' | currentGuid: '0x%-16llX'\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount, 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))
{
RPakAssetEntry_t* assetEntries = pPak->m_pAssetEntries;
uint64_t a = 0;
for (; assetEntries->m_Guid != currentGuid; a++, assetEntries++)
{
if (a >= pPak->m_PakHdr.m_nAssetEntryCount)
{
fnCheckAsset(false);
break;
}
}
assetIdx = pPak->qword580[a];
}
}
// Finally write the pointer to the guid entry.
*pCurrentGuid = g_pPakGlobals->m_Assets[assetIdx].m_pHead;
}
}
#endif // GAMEDLL_S3
void V_RTechUtils::Attach() const
{
DetourAttach(&RTech_OpenFile, &RTech::OpenFile);
#ifdef GAMEDLL_S3
DetourAttach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset);
#endif
}
void V_RTechUtils::Detach() const
{
DetourDetach(&RTech_OpenFile, &RTech::OpenFile);
#ifdef GAMEDLL_S3
DetourDetach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset);
#endif
}
///////////////////////////////////////////////////////////////////////////////
RTech* g_pRTech = new RTech();