diff --git a/src/common/callback.cpp b/src/common/callback.cpp index ea9f7ad7..bf5ef3e6 100644 --- a/src/common/callback.cpp +++ b/src/common/callback.cpp @@ -608,10 +608,10 @@ void RTech_Decompress_f(const CCommand& args) { PakPatchFileHeader_t* pPatchHeader = reinterpret_cast(pDecompBuf + nPatchOffset); Msg(eDLL_T::RTECH, " | |-+ Patch #%02u -----------------------------------------\n", i); - Msg(eDLL_T::RTECH, " | %s |-- Size comp: '%llu'\n", i < pHeader->m_patchIndex ? "|" : " ", pPatchHeader->sizeDisk); - Msg(eDLL_T::RTECH, " | %s |-- Size decp: '%llu'\n", i < pHeader->m_patchIndex ? "|" : " ", pPatchHeader->sizeMemory); + Msg(eDLL_T::RTECH, " | %s |-- Size comp: '%llu'\n", i < pHeader->m_patchIndex ? "|" : " ", pPatchHeader->m_sizeDisk); + Msg(eDLL_T::RTECH, " | %s |-- Size decp: '%llu'\n", i < pHeader->m_patchIndex ? "|" : " ", pPatchHeader->m_sizeMemory); - pPatchHeader->sizeDisk = pPatchHeader->sizeMemory; // Fix size for decompress. + pPatchHeader->m_sizeDisk = pPatchHeader->m_sizeMemory; // Fix size for decompress. } } diff --git a/src/public/rtech/ipakfile.h b/src/public/rtech/ipakfile.h index ffe58af7..524d6692 100644 --- a/src/public/rtech/ipakfile.h +++ b/src/public/rtech/ipakfile.h @@ -117,7 +117,7 @@ struct PakFileHeader_t uint8_t unk2[0x10]; // uint32_t m_memPageOffset; // Size not verified. Offsets every page by x amount, if not 0 start of first page has data corresponding for 'patching some page' uint8_t unk3[0x8]; // -}; +}; static_assert(sizeof(PakFileHeader_t) == 0x80); struct PakPatchFileHeader_t { @@ -294,13 +294,7 @@ struct PakFile_t uint32_t m_patchCount; uint32_t dword14; - PakFileStream_t* m_fileStream; - size_t m_compressSize; - int m_fileHandle; - - _BYTE gap2c[164]; - uint32_t unsigned_intD0; - char gapD4[284]; + PakFileStream_t m_fileStream; uint64_t m_inputBytePos; uint8_t byte1F8; char gap1F9[4]; diff --git a/src/rtech/rtech_game.cpp b/src/rtech/rtech_game.cpp index c9b51053..52fe216a 100644 --- a/src/rtech/rtech_game.cpp +++ b/src/rtech/rtech_game.cpp @@ -16,37 +16,131 @@ // each pak listed in this vector gets unloaded. CUtlVector g_vLoadedPakHandle; +#ifdef GAMEDLL_S3 +//----------------------------------------------------------------------------- +// Purpose: process guid relations for asset +// Input : *pak - +// *asset - +//----------------------------------------------------------------------------- +void Pak_ProcessGuidRelationsForAsset(PakFile_t* pak, PakAsset_t* asset) +{ +#if defined (GAMEDLL_S0) && defined (GAMEDLL_S1) && defined (GAMEDLL_S2) + static const int GLOBAL_MUL = 0x1D; +#else + static const int GLOBAL_MUL = 0x17; +#endif + + PakPage_t* pGuidDescriptors = &pak->m_memoryData.m_guidDescriptors[asset->m_usesStartIdx]; + volatile uint32_t* v5 = reinterpret_cast(*(reinterpret_cast(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(pak->m_memoryData.m_pagePointers[pGuidDescriptors[i].m_index] + pGuidDescriptors[i].m_offset); + + // Get current guid. + const uint64_t currentGuid = reinterpret_cast(*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(const_cast(&v5[2 * v9 + 2])) = currentGuid; + *reinterpret_cast(const_cast(&v5[2 * v9 + 4])) = asset->m_guid; + + std::function 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; + } +} +#endif // GAMEDLL_S3 + + //----------------------------------------------------------------------------- // Purpose: load user-requested pak files on-demand -// Input : *szPakFileName - -// *pMalloc - -// nIdx - -// bUnk - +// Input : *fileName - +// *allocator - +// nIdx - +// bUnk - // Output : pak file handle on success, INVALID_PAK_HANDLE on failure //----------------------------------------------------------------------------- -PakHandle_t Pak_LoadAsync(const char* szPakFileName, CAlignedMemAlloc* pMalloc, int nIdx, bool bUnk) +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", szPakFileName); - pakOverridePath.Format(PLATFORM_PAK_OVERRIDE_PATH "%s", szPakFileName); + 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", szPakFileName); - pakHandle = v_Pak_LoadAsync(szPakFileName, pMalloc, nIdx, bUnk); + 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__, szPakFileName, pakHandle); + 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__, szPakFileName); + Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed; file '%s' doesn't exist\n", __FUNCTION__, fileName); } return pakHandle; @@ -71,16 +165,449 @@ void Pak_UnloadPak(PakHandle_t handle) 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(&*s_pFileArrayMutex)); + const int32_t fileIdx = RTech_FindFreeSlotInFiles(s_pFileArray); + ReleaseSRWLockExclusive(reinterpret_cast(&*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::Attach() const { + DetourAttach(&v_Pak_OpenFile, &Pak_OpenFile); + DetourAttach(&v_Pak_LoadAsync, &Pak_LoadAsync); DetourAttach(&v_Pak_UnloadPak, &Pak_UnloadPak); + +#ifdef GAMEDLL_S3 + //DetourAttach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset); +#endif } void V_RTechGame::Detach() const { + DetourDetach(&v_Pak_OpenFile, &Pak_OpenFile); + DetourDetach(&v_Pak_LoadAsync, &Pak_LoadAsync); DetourDetach(&v_Pak_UnloadPak, &Pak_UnloadPak); + +#ifdef GAMEDLL_S3 + //DetourDetach(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset); +#endif } // Symbols taken from R2 dll's. diff --git a/src/rtech/rtech_game.h b/src/rtech/rtech_game.h index b7572306..37c4239e 100644 --- a/src/rtech/rtech_game.h +++ b/src/rtech/rtech_game.h @@ -5,10 +5,10 @@ /* ==== RTECH_GAME ====================================================================================================================================================== */ inline CMemory p_Pak_LoadAsync; -inline PakHandle_t(*v_Pak_LoadAsync)(const char* szPakFileName, CAlignedMemAlloc* pMalloc, int nIdx, bool bUnk); +inline PakHandle_t(*v_Pak_LoadAsync)(const char* fileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk); inline CMemory p_Pak_WaitAsync; -inline EPakStatus(*v_Pak_WaitAsync)(PakHandle_t handle, void* pFinishCallback); +inline EPakStatus(*v_Pak_WaitAsync)(PakHandle_t handle, void* finishCallback); inline CMemory p_Pak_LoadPak; inline unsigned int (*v_Pak_LoadPak)(void* thisptr, void* a2, uint64_t a3); @@ -16,9 +16,16 @@ inline unsigned int (*v_Pak_LoadPak)(void* thisptr, void* a2, uint64_t a3); inline CMemory p_Pak_UnloadPak; inline void(*v_Pak_UnloadPak)(PakHandle_t handle); +inline CMemory p_Pak_OpenFile; +inline int(*v_Pak_OpenFile)(const CHAR* fileName, int64_t unused, LONGLONG* outFileSize); + +inline CMemory p_Pak_CloseFile; +inline void(*v_Pak_CloseFile)(short fileHandle); + inline CMemory p_Pak_OpenFileOffset; // Offset to inlined 'Pak_OpenFile'. -inline EPakStatus WaitAsync(PakHandle_t handle, void* pFinishCallback = nullptr) { return v_Pak_WaitAsync(handle, pFinishCallback); } +inline CMemory p_Pak_ProcessGuidRelationsForAsset; +inline void(*v_Pak_ProcessGuidRelationsForAsset)(PakFile_t* pak, PakAsset_t* asset); typedef struct PakLoadFuncs_s { @@ -32,7 +39,7 @@ typedef struct PakLoadFuncs_s char unknown2[16]; void* Func7; void* Func8; - EPakStatus(*WaitAsync)(PakHandle_t handle, void* pFinishCallback); + EPakStatus(*WaitAsync)(PakHandle_t handle, void* finishCallback); void* Func10; void* Func11; void* FindByGUID; @@ -73,7 +80,9 @@ class V_RTechGame : public IDetour LogFunAdr("Pak_WaitAsync", p_Pak_WaitAsync.GetPtr()); LogFunAdr("Pak_LoadPak", p_Pak_LoadPak.GetPtr()); LogFunAdr("Pak_UnloadPak", p_Pak_UnloadPak.GetPtr()); - LogFunAdr("Pak_OpenFile", p_Pak_OpenFileOffset.GetPtr()); + LogFunAdr("Pak_OpenFile", p_Pak_OpenFile.GetPtr()); + LogFunAdr("Pak_CloseFile", p_Pak_CloseFile.GetPtr()); + LogFunAdr("Pak_ProcessGuidRelationsForAsset", p_Pak_ProcessGuidRelationsForAsset.GetPtr()); LogVarAdr("g_pakLoadApi", reinterpret_cast(g_pakLoadApi)); } virtual void GetFun(void) const @@ -89,6 +98,17 @@ class V_RTechGame : public IDetour p_Pak_UnloadPak = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 85 FF 74 0C").FollowNearCallSelf(); v_Pak_UnloadPak = p_Pak_UnloadPak.RCast(); + + p_Pak_OpenFile = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 85 08 01 ?? ??").FollowNearCallSelf(); + v_Pak_OpenFile = p_Pak_OpenFile.RCast(); + + p_Pak_CloseFile = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B D9 48 8D 35 ?? ?? ?? ??"); + v_Pak_CloseFile = p_Pak_CloseFile.RCast(); + +#ifdef GAMEDLL_S3 + p_Pak_ProcessGuidRelationsForAsset = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 48 8B 86 ?? ?? ?? ?? 42 8B 0C B0").FollowNearCallSelf(); + v_Pak_ProcessGuidRelationsForAsset = p_Pak_ProcessGuidRelationsForAsset.RCast(); +#endif } virtual void GetVar(void) const { diff --git a/src/rtech/rtech_utils.cpp b/src/rtech/rtech_utils.cpp index 1743b223..7b80b394 100644 --- a/src/rtech/rtech_utils.cpp +++ b/src/rtech/rtech_utils.cpp @@ -611,53 +611,6 @@ void** RTech::LoadShaderSet(void** VTablePtr) return &g_pShaderGlueVFTable; } -//---------------------------------------------------------------------------------- -// Purpose: open a file and add it to m_FileHandles. -//---------------------------------------------------------------------------------- -int32_t RTech::OpenFile(const CHAR* szFilePath, void* unused, LONGLONG* fileSizeOut) -{ - const CHAR* szFileToLoad = szFilePath; - CUtlString pakBasePath(szFilePath); - - 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(&*s_pFileArrayMutex)); - const int32_t fileIdx = RTech_FindFreeSlotInFiles(s_pFileArray); - ReleaseSRWLockExclusive(reinterpret_cast(&*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 //----------------------------------------------------------------------------- @@ -729,110 +682,12 @@ const char* RTech::PakStatusToString(EPakStatus status) default: return "PAK_STATUS_UNKNOWN"; } } -#ifdef GAMEDLL_S3 -//----------------------------------------------------------------------------- -// Purpose: process guid relations for asset -//----------------------------------------------------------------------------- -void RTech::PakProcessGuidRelationsForAsset(PakFile_t* pPak, PakAsset_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 - - PakPage_t* pGuidDescriptors = &pPak->m_memoryData.m_guidDescriptors[pAsset->m_usesStartIdx]; - volatile uint32_t* v5 = reinterpret_cast(*(reinterpret_cast(g_pPakGlobals) + GLOBAL_MUL * (pPak->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", pAsset->m_guid, pPak->m_memoryData.m_fileName, pAsset->m_usesCount); - - for (uint32_t i = 0; i < pAsset->m_usesCount; i++) - { - void** pCurrentGuid = reinterpret_cast(pPak->m_memoryData.m_pagePointers[pGuidDescriptors[i].m_index] + pGuidDescriptors[i].offset); - - // Get current guid. - const uint64_t currentGuid = reinterpret_cast(*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(const_cast(&v5[2 * v9 + 2])) = currentGuid; - *reinterpret_cast(const_cast(&v5[2 * v9 + 4])) = pAsset->m_guid; - - std::function fnCheckAsset = [&](bool shouldCheckTwo) - { - while (true) - { - if (shouldCheckTwo && assetIdxEntryGuid == 2) - { - if (pPak->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) - { - 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_memoryData.m_fileName, pAsset->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 = pPak->m_memoryData.m_assetEntries; - uint64_t a = 0; - - for (; assetEntries->m_guid != currentGuid; a++, assetEntries++) - { - if (a >= pPak->m_memoryData.m_pakHeader.m_assetEntryCount) - { - fnCheckAsset(false); - break; - } - } - - assetIdx = pPak->m_memoryData.qword2E0[a]; - } - } - - // Finally write the pointer to the guid entry. - *pCurrentGuid = g_pPakGlobals->m_assets[assetIdx].m_head; - } -} -#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 } /////////////////////////////////////////////////////////////////////////////// diff --git a/src/rtech/rtech_utils.h b/src/rtech/rtech_utils.h index a8c6e18b..788001db 100644 --- a/src/rtech/rtech_utils.h +++ b/src/rtech/rtech_utils.h @@ -10,17 +10,9 @@ inline CMemory p_RTech_FindFreeSlotInFiles; inline int32_t(*RTech_FindFreeSlotInFiles)(int32_t*); -inline CMemory p_RTech_OpenFile; -inline int32_t(*RTech_OpenFile)(const char*, void*, int64_t*); - inline CMemory p_RTech_RegisterAsset; inline void(*RTech_RegisterAsset)(int, int, const char*, void*, void*, void*, void*, int, int, uint32_t, int, int); -#ifdef GAMEDLL_S3 -inline CMemory p_Pak_ProcessGuidRelationsForAsset; -inline void(*RTech_Pak_ProcessGuidRelationsForAsset)(PakFile_t*, PakAsset_t*); -#endif - inline CMemory p_StreamDB_Init; inline void(*v_StreamDB_Init)(const char* pszLevelName); @@ -48,11 +40,6 @@ public: PakLoadedInfo_t* GetPakLoadedInfo(const char* szPakName); const char* PakStatusToString(EPakStatus status); - static int32_t OpenFile(const CHAR* szFilePath, void* unused, LONGLONG* fileSizeOut); -#ifdef GAMEDLL_S3 - static void PakProcessGuidRelationsForAsset(PakFile_t* pak, PakAsset_t* asset); -#endif // GAMEDLL_S3 - void** LoadShaderSet(void** VTablePtr); }; @@ -65,7 +52,6 @@ class V_RTechUtils : public IDetour virtual void GetAdr(void) const { LogFunAdr("RTech::FindFreeSlotInFiles", p_RTech_FindFreeSlotInFiles.GetPtr()); - LogFunAdr("RTech::OpenFile", p_RTech_OpenFile.GetPtr()); LogFunAdr("StreamDB_Init", p_StreamDB_Init.GetPtr()); LogVarAdr("s_FileArray", reinterpret_cast(s_pFileArray)); @@ -91,16 +77,8 @@ class V_RTechUtils : public IDetour p_RTech_FindFreeSlotInFiles = g_GameDll.FindPatternSIMD("44 8B 51 0C 4C 8B C1"); RTech_FindFreeSlotInFiles = p_RTech_FindFreeSlotInFiles.RCast(); /*44 8B 51 0C 4C 8B C1*/ - p_RTech_OpenFile = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 85 08 01 ?? ??").FollowNearCallSelf(); - RTech_OpenFile = p_RTech_OpenFile.RCast(); /*E8 ? ? ? ? 89 85 08 01 00 00*/ - p_RTech_RegisterAsset = g_GameDll.FindPatternSIMD("4D 89 42 08").FindPatternSelf("48 89 6C", CMemory::Direction::UP); RTech_RegisterAsset = p_RTech_RegisterAsset.RCast(); /*4D 89 42 08*/ - -#ifdef GAMEDLL_S3 - p_Pak_ProcessGuidRelationsForAsset = g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 48 8B 86 ?? ?? ?? ?? 42 8B 0C B0").FollowNearCallSelf(); - RTech_Pak_ProcessGuidRelationsForAsset = p_Pak_ProcessGuidRelationsForAsset.RCast(); /*E8 ? ? ? ? 48 8B 86 ? ? ? ? 42 8B 0C B0*/ -#endif } virtual void GetVar(void) const {