mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Fully implemented ConVar class so we could statically construct all SDK convars, this avoids a level of indirection, and allows for creating ConVar's everywhere in the project. This patch also removed the settings tab of the ImGui server browser, as it has threading issues, while it technically never caused a crash yet, it has been removed as there was no point keeping it vs the work required to make it thread save (it only managed 2 convars which are perfectly manageable through cfg's or the in-game console). Also temporarily disabled the creation of ConVar's in the mod system due to a memory leak, we would allocate and register a convar based on details parsed out of a mod file definition, but never unregister and free it.
1310 lines
49 KiB
C++
1310 lines
49 KiB
C++
//=============================================================================//
|
|
//
|
|
// Purpose: pak file loading and unloading
|
|
//
|
|
//=============================================================================//
|
|
#include "rtech/ipakfile.h"
|
|
#include "rtech/async/asyncio.h"
|
|
|
|
#include "paktools.h"
|
|
#include "pakstate.h"
|
|
#include "pakpatch.h"
|
|
#include "pakalloc.h"
|
|
#include "pakparse.h"
|
|
#include "pakdecode.h"
|
|
#include "pakstream.h"
|
|
|
|
static ConVar pak_debugrelations("pak_debugrelations", "0", FCVAR_DEVELOPMENTONLY, "Debug RPAK asset dependency resolving");
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// resolve the target guid from lookuo table
|
|
//-----------------------------------------------------------------------------
|
|
static bool Pak_ResolveAssetDependency(const PakFile_t* const pak, PakGuid_t currentGuid,
|
|
const PakGuid_t targetGuid, int& currentIndex, const bool shouldCheckTwo)
|
|
{
|
|
while (true)
|
|
{
|
|
if (shouldCheckTwo && currentGuid == 2)
|
|
{
|
|
if (pak->memoryData.pakHeader.assetCount)
|
|
return false;
|
|
}
|
|
|
|
currentIndex++;
|
|
|
|
if (currentIndex >= PAK_MAX_ASSETS)
|
|
return false;
|
|
|
|
currentIndex &= PAK_MAX_ASSETS_MASK;
|
|
currentGuid = g_pakGlobals->loadedAssets[currentIndex].guid;
|
|
|
|
if (currentGuid == targetGuid)
|
|
return true;
|
|
}
|
|
|
|
UNREACHABLE();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// resolve guid relations for asset
|
|
//-----------------------------------------------------------------------------
|
|
void Pak_ResolveAssetRelations(PakFile_t* const pak, const PakAsset_t* const asset)
|
|
{
|
|
PakPage_t* const pGuidDescriptors = &pak->memoryData.guidDescriptors[asset->dependenciesIndex];
|
|
uint32_t* const v5 = (uint32_t*)g_pakGlobals->loadedPaks[pak->memoryData.pakId & PAK_MAX_HANDLES_MASK].qword50;
|
|
|
|
if (pak_debugrelations.GetBool())
|
|
Msg(eDLL_T::RTECH, "Resolving relations for asset: '0x%-16llX', dependencies: %-4u; in pak '%s'\n",
|
|
asset->guid, asset->dependenciesCount, pak->memoryData.fileName);
|
|
|
|
for (uint32_t i = 0; i < asset->dependenciesCount; i++)
|
|
{
|
|
void** const pCurrentGuid = reinterpret_cast<void**>(pak->memoryData.memPageBuffers[pGuidDescriptors[i].index] + pGuidDescriptors[i].offset);
|
|
|
|
// get current guid
|
|
const PakGuid_t targetGuid = reinterpret_cast<uint64_t>(*pCurrentGuid);
|
|
|
|
// get asset index
|
|
int currentIndex = targetGuid & PAK_MAX_ASSETS_MASK;
|
|
const PakGuid_t currentGuid = g_pakGlobals->loadedAssets[currentIndex].guid;
|
|
|
|
const int64_t v9 = 2i64 * InterlockedExchangeAdd(v5, 1u);
|
|
*reinterpret_cast<PakGuid_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 2])) = targetGuid;
|
|
*reinterpret_cast<PakGuid_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 4])) = asset->guid;
|
|
|
|
if (currentGuid != targetGuid)
|
|
{
|
|
// are we some special asset with the guid 2?
|
|
if (!Pak_ResolveAssetDependency(pak, currentGuid, targetGuid, currentIndex, true))
|
|
{
|
|
PakAsset_t* assetEntries = pak->memoryData.assetEntries;
|
|
uint64_t a = 0;
|
|
|
|
for (; assetEntries->guid != targetGuid; a++, assetEntries++)
|
|
{
|
|
if (a >= pak->memoryData.pakHeader.assetCount)
|
|
{
|
|
if (!Pak_ResolveAssetDependency(pak, currentGuid, targetGuid, currentIndex, false))
|
|
{
|
|
// the dependency couldn't be resolved, this state is irrecoverable;
|
|
// error out
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Failed to resolve asset dependency %u of %u\n"
|
|
"pak: '%s'\n"
|
|
"asset: '0x%llX'\n"
|
|
"target: '0x%llX'\n",
|
|
i, asset->dependenciesCount,
|
|
pak->memoryData.fileName,
|
|
asset->guid,
|
|
targetGuid);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
currentIndex = pak->memoryData.loadedAssetIndices[a];
|
|
}
|
|
}
|
|
|
|
// finally write the pointer to the guid entry
|
|
*pCurrentGuid = g_pakGlobals->loadedAssets[currentIndex].head;
|
|
}
|
|
}
|
|
|
|
uint32_t Pak_ProcessRemainingPagePointers(PakFile_t* const pak)
|
|
{
|
|
uint32_t processedPointers = 0;
|
|
|
|
for (processedPointers = pak->numProcessedPointers; processedPointers < pak->GetPointerCount(); ++processedPointers)
|
|
{
|
|
PakPage_t* const curPage = &pak->memoryData.virtualPointers[processedPointers];
|
|
int curCount = curPage->index - pak->firstPageIdx;
|
|
|
|
if (curCount < 0)
|
|
curCount += pak->memoryData.pakHeader.memPageCount;
|
|
|
|
if (curCount >= pak->processedPageCount)
|
|
break;
|
|
|
|
PakPage_t* const ptr = reinterpret_cast<PakPage_t*>(pak->GetPointerForPageOffset(curPage));
|
|
ptr->ptr = pak->memoryData.memPageBuffers[ptr->index] + ptr->offset;
|
|
}
|
|
|
|
return processedPointers;
|
|
}
|
|
|
|
void Pak_RunAssetLoadingJobs(PakFile_t* const pak)
|
|
{
|
|
pak->numProcessedPointers = Pak_ProcessRemainingPagePointers(pak);
|
|
|
|
const uint32_t numAssets = pak->processedAssetCount;
|
|
|
|
if (numAssets == pak->memoryData.pakHeader.assetCount)
|
|
return;
|
|
|
|
PakAsset_t* pakAsset = &pak->memoryData.assetEntries[numAssets];
|
|
|
|
if (pakAsset->pageEnd > pak->processedPageCount)
|
|
return;
|
|
|
|
for (uint32_t currentAsset = numAssets; g_pakGlobals->numAssetLoadJobs <= 0xC8u;)
|
|
{
|
|
pak->memoryData.loadedAssetIndices[currentAsset] = Pak_TrackAsset(pak, pakAsset);
|
|
|
|
_InterlockedIncrement16(&g_pakGlobals->numAssetLoadJobs);
|
|
|
|
const uint8_t assetBind = pakAsset->HashTableIndexForAssetType();
|
|
|
|
if (g_pakGlobals->assetBindings[assetBind].loadAssetFunc)
|
|
{
|
|
const JobTypeID_t jobTypeId = g_pakGlobals->assetBindJobTypes[assetBind];
|
|
|
|
// have to cast it to a bigger size to send it as param to JTGuts_AddJob().
|
|
const int64_t pakId = pak->memoryData.pakId;
|
|
|
|
JTGuts_AddJob(jobTypeId, pak->memoryData.assetLoadJobId, (void*)pakId, (void*)(uint64_t)currentAsset);
|
|
}
|
|
else
|
|
{
|
|
if (_InterlockedExchangeAdd16((volatile signed __int16*)&pakAsset->numRemainingDependencies, 0xFFFFu) == 1)
|
|
Pak_ProcessAssetRelationsAndResolveDependencies(pak, pakAsset, currentAsset, assetBind);
|
|
|
|
_InterlockedDecrement16(&g_pakGlobals->numAssetLoadJobs);
|
|
}
|
|
|
|
currentAsset = ++pak->processedAssetCount;
|
|
|
|
if (currentAsset == pak->memoryData.pakHeader.assetCount)
|
|
{
|
|
JT_EndJobGroup(pak->memoryData.assetLoadJobId);
|
|
return;
|
|
}
|
|
|
|
pakAsset = &pak->memoryData.assetEntries[currentAsset];
|
|
|
|
if (pakAsset->pageEnd > pak->processedPageCount)
|
|
return;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// load user-requested pak files on-demand
|
|
//-----------------------------------------------------------------------------
|
|
PakHandle_t Pak_LoadAsync(const char* const fileName, CAlignedMemAlloc* const allocator, const int nIdx, const bool bUnk)
|
|
{
|
|
PakHandle_t pakId = INVALID_PAK_HANDLE;
|
|
|
|
if (Pak_FileExists(fileName))
|
|
{
|
|
Msg(eDLL_T::RTECH, "Loading pak file: '%s'\n", fileName);
|
|
pakId = v_Pak_LoadAsync(fileName, allocator, nIdx, bUnk);
|
|
|
|
if (pakId == INVALID_PAK_HANDLE)
|
|
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed read '%s' results '%d'\n", __FUNCTION__, fileName, pakId);
|
|
}
|
|
else
|
|
{
|
|
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed; file '%s' doesn't exist\n", __FUNCTION__, fileName);
|
|
}
|
|
|
|
return pakId;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// unloads loaded pak files
|
|
//-----------------------------------------------------------------------------
|
|
void Pak_UnloadAsync(PakHandle_t handle)
|
|
{
|
|
const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(handle);
|
|
|
|
if (pakInfo->fileName)
|
|
Msg(eDLL_T::RTECH, "Unloading pak file: '%s'\n", pakInfo->fileName);
|
|
|
|
v_Pak_UnloadAsync(handle);
|
|
}
|
|
|
|
#define CMD_INVALID -1
|
|
|
|
// only patch cmds 4,5,6 use this array to determine their data size
|
|
static const int s_patchCmdToBytesToProcess[] = { CMD_INVALID, CMD_INVALID, CMD_INVALID, CMD_INVALID, 3, 7, 6, 0 };
|
|
#undef CMD_INVALID
|
|
//----------------------------------------------------------------------------------
|
|
// loads and processes a pak file (handles decompression and patching)
|
|
// TODO: !!! FINISH REBUILD !!!
|
|
//----------------------------------------------------------------------------------
|
|
bool Pak_ProcessPakFile(PakFile_t* const pak)
|
|
{
|
|
PakFileStream_t* const fileStream = &pak->fileStream;
|
|
PakMemoryData_t* const memoryData = &pak->memoryData;
|
|
|
|
// first request is always just the header?
|
|
size_t readStart = sizeof(PakFileHeader_t);
|
|
|
|
if (fileStream->numDataChunks > 0)
|
|
readStart = fileStream->numDataChunks * PAK_READ_DATA_CHUNK_SIZE;
|
|
|
|
for (; fileStream->numDataChunksProcessed != fileStream->numDataChunks; fileStream->numDataChunksProcessed++)
|
|
{
|
|
const int v7 = fileStream->numDataChunksProcessed & 0x1F;
|
|
const uint8_t v8 = fileStream->gap94[v7];
|
|
if (v8 != 1)
|
|
{
|
|
size_t bytesProcessed = 0;
|
|
const char* statusMsg = "(no reason)";
|
|
const uint8_t currentStatus = g_pakLoadApi->CheckAsyncRequest(fileStream->asyncRequestHandles[v7], &bytesProcessed, &statusMsg);
|
|
|
|
if (currentStatus == AsyncHandleStatus_t::FS_ASYNC_ERROR)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Error reading pak file \"%s\" -- %s\n", pak->memoryData.fileName, statusMsg);
|
|
else if (currentStatus == AsyncHandleStatus_t::FS_ASYNC_PENDING)
|
|
break;
|
|
|
|
fileStream->bytesStreamed += bytesProcessed;
|
|
if (v8)
|
|
{
|
|
const PakFileHeader_t* pakHeader = &pak->memoryData.pakHeader;
|
|
const uint64_t v16 = fileStream->numDataChunksProcessed * PAK_READ_DATA_CHUNK_SIZE;
|
|
|
|
if (v8 == 2)
|
|
{
|
|
fileStream->bytesStreamed = bytesProcessed + v16;
|
|
pakHeader = (PakFileHeader_t*)&fileStream->buffer[v16 & fileStream->bufferMask];
|
|
}
|
|
|
|
const uint8_t fileIndex = fileStream->numLoadedFiles++ & PAK_MAX_ASYNC_STREAMED_LOAD_REQUESTS_MASK;
|
|
|
|
//printf("v16: %lld\n", v16);
|
|
fileStream->descriptors[fileIndex].dataOffset = v16 + sizeof(PakFileHeader_t);
|
|
fileStream->descriptors[fileIndex].compressedSize = v16 + pakHeader->compressedSize;
|
|
fileStream->descriptors[fileIndex].decompressedSize = pakHeader->decompressedSize;
|
|
fileStream->descriptors[fileIndex].compressionMode = pakHeader->GetCompressionMode();
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t qword1D0 = memoryData->processedPatchedDataSize;
|
|
|
|
for (; pak->byte1F8 != fileStream->numLoadedFiles; pak->byte1F8++)
|
|
{
|
|
PakFileStream_t::Descriptor* v22 = &fileStream->descriptors[pak->byte1F8 & PAK_MAX_ASYNC_STREAMED_LOAD_REQUESTS_MASK];
|
|
|
|
if (pak->byte1FD)
|
|
{
|
|
pak->byte1FD = false;
|
|
pak->inputBytePos = v22->dataOffset;
|
|
|
|
if (v22->compressionMode != EPakDecodeMode::MODE_DISABLED)
|
|
{
|
|
pak->isOffsetted_MAYBE = false;
|
|
pak->isCompressed = true;
|
|
memoryData->processedPatchedDataSize = sizeof(PakFileHeader_t);
|
|
}
|
|
else
|
|
{
|
|
pak->isOffsetted_MAYBE = true;
|
|
pak->isCompressed = false;
|
|
//printf("v22->dataOffset: %lld\n", v22->dataOffset);
|
|
memoryData->processedPatchedDataSize = v22->dataOffset;
|
|
}
|
|
|
|
if (pak->isCompressed)
|
|
{
|
|
const size_t decompressedSize = Pak_InitDecoder(&pak->pakDecoder,
|
|
fileStream->buffer, pak->decompBuffer,
|
|
PAK_DECODE_IN_RING_BUFFER_MASK, PAK_DECODE_OUT_RING_BUFFER_MASK,
|
|
v22->compressedSize - (v22->dataOffset - sizeof(PakFileHeader_t)),
|
|
v22->dataOffset - sizeof(PakFileHeader_t), sizeof(PakFileHeader_t), v22->compressionMode);
|
|
|
|
if (decompressedSize != v22->decompressedSize)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE,
|
|
"Error reading pak file \"%s\" with decoder \"%s\" -- decompressed size %zu doesn't match expected value %zu\n",
|
|
pak->memoryData.fileName,
|
|
Pak_DecoderToString(v22->compressionMode),
|
|
decompressedSize,
|
|
pak->memoryData.pakHeader.decompressedSize);
|
|
}
|
|
}
|
|
|
|
if (pak->isCompressed)
|
|
{
|
|
qword1D0 = pak->pakDecoder.outBufBytePos;
|
|
|
|
if (qword1D0 != pak->pakDecoder.decompSize)
|
|
{
|
|
const bool didDecode = Pak_StreamToBufferDecode(&pak->pakDecoder,
|
|
fileStream->bytesStreamed, (memoryData->processedPatchedDataSize + PAK_DECODE_OUT_RING_BUFFER_SIZE), v22->compressionMode);
|
|
|
|
qword1D0 = pak->pakDecoder.outBufBytePos;
|
|
pak->inputBytePos = pak->pakDecoder.inBufBytePos;
|
|
|
|
if (didDecode)
|
|
DevMsg(eDLL_T::RTECH, "%s: pak '%s' decoded successfully\n", __FUNCTION__, pak->GetName());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
qword1D0 = Min(v22->compressedSize, fileStream->bytesStreamed);
|
|
}
|
|
|
|
if (pak->inputBytePos != v22->compressedSize || memoryData->processedPatchedDataSize != qword1D0)
|
|
break;
|
|
|
|
pak->byte1FD = true;
|
|
qword1D0 = memoryData->processedPatchedDataSize;
|
|
}
|
|
|
|
size_t numBytesToProcess = qword1D0 - memoryData->processedPatchedDataSize;
|
|
|
|
while (memoryData->patchSrcSize + memoryData->field_2A8)
|
|
{
|
|
// if there are no bytes left to process in this patch operation
|
|
if (!memoryData->numBytesToProcess_maybe)
|
|
{
|
|
RBitRead& bitbuf = memoryData->bitBuf;
|
|
bitbuf.ConsumeData(memoryData->patchData, bitbuf.BitsAvailable());
|
|
|
|
// advance patch data buffer by the number of bytes that have just been fetched
|
|
memoryData->patchData = &memoryData->patchData[bitbuf.BitsAvailable() >> 3];
|
|
|
|
// store the number of bits remaining to complete the data read
|
|
bitbuf.m_bitsAvailable = bitbuf.BitsAvailable() & 7; // number of bits above a whole byte
|
|
|
|
const __int8 cmd = memoryData->patchCommands[bitbuf.ReadBits(6)];
|
|
|
|
bitbuf.DiscardBits(memoryData->PATCH_field_68[bitbuf.ReadBits(6)]);
|
|
|
|
// get the next patch function to execute
|
|
memoryData->patchFunc = g_pakPatchApi[cmd];
|
|
|
|
if (cmd <= 3u)
|
|
{
|
|
const uint8_t bitExponent = memoryData->PATCH_unk2[bitbuf.ReadBits(8)]; // number of stored bits for the data size
|
|
|
|
bitbuf.DiscardBits(memoryData->PATCH_unk3[bitbuf.ReadBits(8)]);
|
|
|
|
memoryData->numBytesToProcess_maybe = (1ull << bitExponent) + bitbuf.ReadBits(bitExponent);
|
|
|
|
bitbuf.DiscardBits(bitExponent);
|
|
}
|
|
else
|
|
{
|
|
memoryData->numBytesToProcess_maybe = s_patchCmdToBytesToProcess[cmd];
|
|
}
|
|
}
|
|
|
|
if (!pak->memoryData.patchFunc(pak, &numBytesToProcess))
|
|
break;
|
|
}
|
|
|
|
if (pak->isOffsetted_MAYBE)
|
|
pak->inputBytePos = memoryData->processedPatchedDataSize;
|
|
|
|
if (!fileStream->finishedLoadingPatches)
|
|
{
|
|
const size_t v42 = min(fileStream->numDataChunksProcessed, pak->inputBytePos >> 19);
|
|
|
|
//if ((unsigned int)(pak->inputBytePos >> 19) < v42)
|
|
// v42 = pak->inputBytePos >> 19;
|
|
|
|
while (fileStream->numDataChunks != v42 + 32)
|
|
{
|
|
const int8_t requestIdx = fileStream->numDataChunks & 0x1F;
|
|
const size_t readOffsetEnd = (fileStream->numDataChunks + 1ull) * PAK_READ_DATA_CHUNK_SIZE;
|
|
|
|
if (fileStream->fileReadStatus == 1)
|
|
{
|
|
fileStream->asyncRequestHandles[requestIdx] = FS_ASYNC_REQ_INVALID;
|
|
fileStream->gap94[requestIdx] = 1;
|
|
|
|
if (((requestIdx + 1) & PAK_MAX_ASYNC_STREAMED_LOAD_REQUESTS_MASK) == 0)
|
|
fileStream->fileReadStatus = 2;
|
|
|
|
++fileStream->numDataChunks;
|
|
readStart = readOffsetEnd;
|
|
}
|
|
else
|
|
{
|
|
if (readStart < fileStream->fileSize)
|
|
{
|
|
const size_t lenToRead = Min(fileStream->fileSize, readOffsetEnd);
|
|
|
|
const size_t readOffset = readStart - fileStream->qword0;
|
|
const size_t readSize = lenToRead - readStart;
|
|
|
|
fileStream->asyncRequestHandles[requestIdx] = v_FS_ReadAsyncFile(
|
|
fileStream->fileHandle,
|
|
readOffset,
|
|
readSize,
|
|
&fileStream->buffer[readStart & fileStream->bufferMask],
|
|
0,
|
|
0,
|
|
4);
|
|
|
|
fileStream->gap94[requestIdx] = fileStream->fileReadStatus;
|
|
fileStream->fileReadStatus = 0;
|
|
|
|
++fileStream->numDataChunks;
|
|
readStart = readOffsetEnd;
|
|
}
|
|
else
|
|
{
|
|
if (pak->patchCount >= pak->memoryData.pakHeader.patchIndex)
|
|
{
|
|
FS_CloseAsyncFile(fileStream->fileHandle);
|
|
fileStream->fileHandle = INVALID_PAK_HANDLE;
|
|
fileStream->qword0 = 0;
|
|
fileStream->finishedLoadingPatches = true;
|
|
|
|
return memoryData->patchSrcSize == 0;
|
|
}
|
|
|
|
if (!pak->dword14)
|
|
return memoryData->patchSrcSize == 0;
|
|
|
|
char pakPatchPath[MAX_PATH] = {};
|
|
sprintf(pakPatchPath, PLATFORM_PAK_PATH"%s", pak->memoryData.fileName);
|
|
|
|
// get path of next patch rpak to load
|
|
if (pak->memoryData.patchIndices[pak->patchCount])
|
|
{
|
|
char* pExtension = nullptr;
|
|
|
|
char* it = pakPatchPath;
|
|
while (*it)
|
|
{
|
|
if (*it == '.')
|
|
pExtension = it;
|
|
else if (*it == '\\' || *it == '/')
|
|
pExtension = nullptr;
|
|
|
|
++it;
|
|
}
|
|
|
|
if (pExtension)
|
|
it = pExtension;
|
|
|
|
// replace extension '.rpak' with '(xx).rpak'
|
|
snprintf(it, &pakPatchPath[sizeof(pakPatchPath)] - it,
|
|
"(%02u).rpak", pak->memoryData.patchIndices[pak->patchCount]);
|
|
}
|
|
|
|
const int patchFileHandle = FS_OpenAsyncFile(pakPatchPath, 5, &numBytesToProcess);
|
|
|
|
//printf("[%s] Opened pak '%s' with file handle %i\n", pak->GetName(), pakPatchPath, patchFileHandle);
|
|
|
|
if (patchFileHandle == FS_ASYNC_FILE_INVALID)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't open file \"%s\".\n", pakPatchPath);
|
|
|
|
if (numBytesToProcess < pak->memoryData.patchHeaders[pak->patchCount].compressedSize)
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "File \"%s\" appears truncated; read size: %zu < expected size: %zu.\n",
|
|
pakPatchPath, numBytesToProcess, pak->memoryData.patchHeaders[pak->patchCount].compressedSize);
|
|
|
|
FS_CloseAsyncFile(fileStream->fileHandle);
|
|
|
|
fileStream->fileHandle = patchFileHandle;
|
|
|
|
const size_t v58 = ALIGN_VALUE(fileStream->numDataChunks, 8ull) * PAK_READ_DATA_CHUNK_SIZE;
|
|
fileStream->fileReadStatus = (fileStream->numDataChunks == ALIGN_VALUE(fileStream->numDataChunks, 8ull)) + 1;
|
|
|
|
//printf("[%s] dwordB8: %i, v58: %lld, byteBC: %i, numFiles: %i\n", pak->GetName(), fileStream->numDataChunks, v58, fileStream->byteBC, fileStream->numLoadedFiles);
|
|
fileStream->qword0 = v58;
|
|
fileStream->fileSize = v58 + pak->memoryData.patchHeaders[pak->patchCount].compressedSize;
|
|
|
|
pak->patchCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return memoryData->patchSrcSize == 0;
|
|
}
|
|
|
|
// sets patch variables for copying the next unprocessed page into the relevant segment buffer
|
|
// if this is a header page, fetch info from the next unprocessed asset and copy over the asset's header
|
|
bool SetupNextPageForPatching(PakLoadedInfo_t* a1, PakFile_t* pak)
|
|
{
|
|
Pak_RunAssetLoadingJobs(pak);
|
|
|
|
// numProcessedPointers has just been set in the above function call
|
|
pak->memoryData.numShiftedPointers = pak->numProcessedPointers;
|
|
|
|
if (pak->processedPageCount == pak->GetPageCount())
|
|
return false;
|
|
//break;
|
|
|
|
const uint32_t highestProcessedPageIdx = pak->processedPageCount + pak->firstPageIdx;
|
|
pak->processedPageCount++;
|
|
|
|
int v26 = highestProcessedPageIdx - pak->GetPageCount();
|
|
if (highestProcessedPageIdx < pak->GetPageCount())
|
|
v26 = highestProcessedPageIdx;
|
|
|
|
const PakPageHeader_t* const nextMemPageHeader = &pak->memoryData.pageHeaders[v26];
|
|
if ((pak->memoryData.segmentHeaders[nextMemPageHeader->segmentIdx].typeFlags & (SF_TEMP | SF_CPU)) != 0)
|
|
{
|
|
pak->memoryData.patchSrcSize = nextMemPageHeader->dataSize;
|
|
pak->memoryData.patchDstPtr = reinterpret_cast<char*>(pak->memoryData.memPageBuffers[v26]);
|
|
|
|
return true;
|
|
//continue;
|
|
}
|
|
|
|
// headers
|
|
PakAsset_t* pakAsset = pak->memoryData.ppAssetEntries[pak->memoryData.someAssetCount];
|
|
|
|
pak->memoryData.patchSrcSize = pakAsset->headerSize;
|
|
int assetTypeIdx = pakAsset->HashTableIndexForAssetType();
|
|
|
|
pak->memoryData.patchDstPtr = reinterpret_cast<char*>(a1->segmentBuffers[0]) + pak->memoryData.unkAssetTypeBindingSizes[assetTypeIdx];
|
|
pak->memoryData.unkAssetTypeBindingSizes[assetTypeIdx] += g_pakGlobals->assetBindings[assetTypeIdx].nativeClassSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Pak_ProcessAssets(PakLoadedInfo_t* const a1)
|
|
{
|
|
PakFile_t* const pak = a1->pakFile;
|
|
while (pak->processedAssetCount != pak->GetAssetCount())
|
|
{
|
|
// TODO: invert condition and make the branch encompass the whole loop
|
|
if (!(pak->memoryData.patchSrcSize + pak->memoryData.field_2A8))
|
|
{
|
|
const bool res = SetupNextPageForPatching(a1, pak);
|
|
|
|
if (res)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (!Pak_ProcessPakFile(pak))
|
|
return false;
|
|
|
|
// processedPageCount must be greater than 0 here otherwise the page index will be negative and cause a crash
|
|
// if this happens, something probably went wrong with the patch data condition at the start of the loop, as that
|
|
// function call should increment processedPageCount if it succeeded
|
|
assert(pak->processedPageCount > 0);
|
|
|
|
const uint32_t pageCount = pak->GetPageCount();
|
|
const uint32_t v4 = (pak->firstPageIdx - 1) + pak->processedPageCount;
|
|
|
|
uint32_t shiftedPageIndex = v4;
|
|
|
|
if (v4 >= pageCount)
|
|
shiftedPageIndex -= pageCount;
|
|
|
|
// if "temp_" segment
|
|
if ((pak->memoryData.segmentHeaders[pak->memoryData.pageHeaders[shiftedPageIndex].segmentIdx].typeFlags & (SF_TEMP | SF_CPU)) != 0)
|
|
{
|
|
const bool res = SetupNextPageForPatching(a1, pak);
|
|
|
|
if (res)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
|
|
PakAsset_t* asset = pak->memoryData.ppAssetEntries[pak->memoryData.someAssetCount];
|
|
const uint32_t headPageOffset = asset->headPtr.offset;
|
|
char* v8 = pak->memoryData.patchDstPtr - asset->headerSize;
|
|
|
|
uint32_t newOffsetFromSegmentBufferToHeader = LODWORD(pak->memoryData.patchDstPtr)
|
|
- asset->headerSize
|
|
- LODWORD(a1->segmentBuffers[0]);
|
|
asset->headPtr.offset = newOffsetFromSegmentBufferToHeader;
|
|
|
|
uint32_t offsetSize = newOffsetFromSegmentBufferToHeader - headPageOffset;
|
|
|
|
for (uint32_t i = pak->memoryData.numShiftedPointers; i < pak->GetPointerCount(); pak->memoryData.numShiftedPointers = i)
|
|
{
|
|
PakPage_t* ptr = &pak->memoryData.virtualPointers[i];
|
|
|
|
ASSERT_PAKPTR_VALID(pak, ptr);
|
|
|
|
if (ptr->index != shiftedPageIndex)
|
|
break;
|
|
|
|
const uint32_t offsetToPointer = ptr->offset - headPageOffset;
|
|
if (offsetToPointer >= asset->headerSize)
|
|
break;
|
|
|
|
PakPage_t* pagePtr = reinterpret_cast<PakPage_t*>(v8 + offsetToPointer);
|
|
|
|
ASSERT_PAKPTR_VALID(pak, ptr);
|
|
|
|
ptr->offset += offsetSize;
|
|
|
|
if (pagePtr->index == shiftedPageIndex)
|
|
pagePtr->offset += offsetSize;
|
|
|
|
i = pak->memoryData.numShiftedPointers + 1;
|
|
}
|
|
|
|
for (uint32_t j = 0; j < asset->dependenciesCount; ++j)
|
|
{
|
|
PakPage_t* descriptor = &pak->memoryData.guidDescriptors[asset->dependenciesIndex + j];
|
|
|
|
if (descriptor->index == shiftedPageIndex)
|
|
descriptor->offset += offsetSize;
|
|
}
|
|
|
|
const uint32_t v16 = ++pak->memoryData.someAssetCount;
|
|
|
|
PakAsset_t* v17 = nullptr;
|
|
if (v16 < pak->GetAssetCount() && (v17 = pak->memoryData.ppAssetEntries[v16], v17->headPtr.index == shiftedPageIndex))
|
|
{
|
|
pak->memoryData.field_2A8 = v17->headPtr.offset - headPageOffset - asset->headerSize;
|
|
pak->memoryData.patchSrcSize = v17->headerSize;
|
|
const uint8_t assetTypeIdx = v17->HashTableIndexForAssetType();
|
|
|
|
pak->memoryData.patchDstPtr = reinterpret_cast<char*>(a1->segmentBuffers[0]) + pak->memoryData.unkAssetTypeBindingSizes[assetTypeIdx];
|
|
|
|
pak->memoryData.unkAssetTypeBindingSizes[assetTypeIdx] += g_pakGlobals->assetBindings[assetTypeIdx].nativeClassSize;
|
|
}
|
|
else
|
|
{
|
|
bool res = SetupNextPageForPatching(a1, pak);
|
|
|
|
if (res)
|
|
continue;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!JT_IsJobDone(pak->memoryData.assetLoadJobId))
|
|
return false;
|
|
|
|
uint32_t i = 0;
|
|
PakAsset_t* pAsset = nullptr;
|
|
|
|
for (int j = pak->memoryData.pakId & PAK_MAX_HANDLES_MASK; i < pak->GetHeader().assetCount; a1->assetGuids[i - 1] = pAsset->guid)
|
|
{
|
|
pAsset = &pak->memoryData.assetEntries[i];
|
|
if (pAsset->numRemainingDependencies)
|
|
{
|
|
//printf("[%s] processing deps for %llX (%.4s)\n", pak->GetName(), pAsset->guid, (char*)&pAsset->magic);
|
|
Pak_ResolveAssetRelations(pak, pAsset);
|
|
|
|
const int assetIndex = pak->memoryData.loadedAssetIndices[i];
|
|
const PakAssetShort_t& loadedAsset = g_pakGlobals->loadedAssets[assetIndex];
|
|
|
|
if (g_pakGlobals->trackedAssets[loadedAsset.trackerIndex].loadedPakIndex == j)
|
|
{
|
|
PakTracker_s* pakTracker = g_pakGlobals->pakTracker;
|
|
|
|
if (pakTracker)
|
|
{
|
|
if (pakTracker->numPaksTracked)
|
|
{
|
|
int* trackerIndices = g_pakGlobals->pakTracker->loadedAssetIndices;
|
|
uint32_t count = 0;
|
|
|
|
while (*trackerIndices != assetIndex)
|
|
{
|
|
++count;
|
|
++trackerIndices;
|
|
|
|
if (count >= pakTracker->numPaksTracked)
|
|
goto LABEL_41;
|
|
}
|
|
|
|
goto LABEL_42;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pakTracker = reinterpret_cast<PakTracker_s*>(AlignedMemAlloc()->Alloc(sizeof(PakTracker_s), 8));
|
|
pakTracker->numPaksTracked = 0;
|
|
pakTracker->unk_4 = 0;
|
|
pakTracker->unk_8 = 0;
|
|
|
|
g_pakGlobals->pakTracker = pakTracker;
|
|
}
|
|
LABEL_41:
|
|
|
|
pakTracker->loadedAssetIndices[pakTracker->numPaksTracked] = assetIndex;
|
|
++pakTracker->numPaksTracked;
|
|
}
|
|
}
|
|
LABEL_42:
|
|
++i;
|
|
}
|
|
|
|
if (g_pakGlobals->pakTracker)
|
|
sub_14043D870(a1, 0);
|
|
|
|
a1->status = EPakStatus::PAK_STATUS_LOADED;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Pak_StubInvalidAssetBinds(PakFile_t* const pak, PakSegmentDescriptor_t* const desc)
|
|
{
|
|
for (uint32_t i = 0; i < pak->GetAssetCount(); ++i)
|
|
{
|
|
PakAsset_t* const asset = &pak->memoryData.assetEntries[i];
|
|
pak->memoryData.ppAssetEntries[i] = asset;
|
|
|
|
const uint8_t assetTypeIndex = asset->HashTableIndexForAssetType();
|
|
desc->assetTypeCount[assetTypeIndex]++;
|
|
|
|
PakAssetBinding_t* const assetBinding = &g_pakGlobals->assetBindings[assetTypeIndex];
|
|
|
|
if (assetBinding->type == PakAssetBinding_t::NONE)
|
|
{
|
|
assetBinding->extension = asset->magic;
|
|
assetBinding->version = asset->version;
|
|
assetBinding->description = "<unknown>";
|
|
assetBinding->loadAssetFunc = nullptr;
|
|
assetBinding->unloadAssetFunc = nullptr;
|
|
assetBinding->replaceAssetFunc = nullptr;
|
|
assetBinding->allocator = AlignedMemAlloc();
|
|
assetBinding->headerSize = asset->headerSize;
|
|
assetBinding->nativeClassSize = asset->headerSize;
|
|
assetBinding->headerAlignment = pak->memoryData.pageHeaders[asset->headPtr.index].pageAlignment;
|
|
assetBinding->type = PakAssetBinding_t::STUB;
|
|
}
|
|
|
|
// this is dev only because it could spam a lot on older paks
|
|
// which isn't much help to the average user that can't rebuild other people's paks
|
|
if (asset->version != assetBinding->version)
|
|
{
|
|
FourCCString_t assetMagic;
|
|
FourCCToString(assetMagic, asset->magic);
|
|
|
|
DevWarning(eDLL_T::RTECH,
|
|
"Unexpected asset version for \"%s\" (%.4s) asset with guid 0x%llX (asset %u in pakfile '%s'). Expected %u, found %u.\n",
|
|
assetBinding->description,
|
|
assetMagic,
|
|
asset->guid,
|
|
i, pak->GetName(),
|
|
assetBinding->version, asset->version
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Pak_StartLoadingPak(PakLoadedInfo_t* const loadedInfo)
|
|
{
|
|
PakFile_t* const pakFile = loadedInfo->pakFile;
|
|
|
|
if (pakFile->memoryData.patchSrcSize && !Pak_ProcessPakFile(pakFile))
|
|
return false;
|
|
|
|
PakSegmentDescriptor_t pakDescriptor = {};
|
|
|
|
Pak_StubInvalidAssetBinds(pakFile, &pakDescriptor);
|
|
|
|
const uint32_t numAssets = pakFile->GetAssetCount();
|
|
|
|
if (pakFile->memoryData.pakHeader.patchIndex)
|
|
pakFile->firstPageIdx = pakFile->memoryData.patchDataHeader->pageCount;
|
|
|
|
sub_140442740(pakFile->memoryData.ppAssetEntries, &pakFile->memoryData.ppAssetEntries[numAssets], numAssets, pakFile);
|
|
|
|
// pak must have no more than PAK_MAX_SEGMENTS segments as otherwise we will overrun the above "segmentSizes" array
|
|
// and write to arbitrary locations on the stack
|
|
if (pakFile->GetSegmentCount() > PAK_MAX_SEGMENTS)
|
|
{
|
|
Error(eDLL_T::RTECH, EXIT_FAILURE, "Too many segments in pakfile '%s'. Max %i, found %i.\n", pakFile->GetName(), PAK_MAX_SEGMENTS, pakFile->GetSegmentCount());
|
|
return false;
|
|
}
|
|
|
|
Pak_AlignSegmentHeaders(pakFile, &pakDescriptor);
|
|
Pak_AlignSegments(pakFile, &pakDescriptor);
|
|
|
|
// allocate segment buffers with predetermined alignments; pages will be
|
|
// copied into here
|
|
for (int8_t i = 0; i < PAK_SEGMENT_BUFFER_TYPES; ++i)
|
|
{
|
|
if (pakDescriptor.segmentSizeForType[i])
|
|
loadedInfo->segmentBuffers[i] = AlignedMemAlloc()->Alloc(pakDescriptor.segmentSizeForType[i], pakDescriptor.segmentAlignmentForType[i]);
|
|
}
|
|
|
|
Pak_CopyPagesToSegments(pakFile, loadedInfo, &pakDescriptor);
|
|
|
|
const PakFileHeader_t& pakHdr = pakFile->GetHeader();
|
|
|
|
if (Pak_StreamingEnabled())
|
|
Pak_LoadStreamingData(loadedInfo);
|
|
|
|
const __int64 v106 = pakHdr.descriptorCount + 2 * (pakHdr.patchIndex + pakHdr.assetCount + 4ull * pakHdr.assetCount + pakHdr.virtualSegmentCount);
|
|
const __int64 patchDestOffset = pakHdr.GetTotalHeaderSize() + 2 * (pakHdr.patchIndex + 6ull * pakHdr.memPageCount + 4 * v106);
|
|
|
|
pakFile->dword14 = 1;
|
|
|
|
PakMemoryData_t& memoryData = pakFile->memoryData;
|
|
|
|
memoryData.patchSrcSize = pakFile->memoryData.qword2D0 - patchDestOffset;
|
|
memoryData.patchDstPtr = (char*)&pakHdr + patchDestOffset;
|
|
|
|
loadedInfo->status = EPakStatus::PAK_STATUS_LOAD_PAKHDR;
|
|
|
|
return true;
|
|
}
|
|
|
|
// #STR: "(%02u).rpak", "Couldn't read package file \"%s\".\n", "Error 0x%08x", "paks\\Win64\\%s"
|
|
//bool Pak_SetupBuffersAndLoad(PakHandle_t pakId)
|
|
//{
|
|
// __int64 v2; // rdi
|
|
// const char* pakFilePath; // rsi
|
|
// unsigned int v7; // ebx
|
|
// unsigned int v8; // r14d
|
|
// char** v9; // r12
|
|
// int v10; // eax
|
|
// __int64 v11; // r11
|
|
// char v12; // al
|
|
// char* i; // rdx
|
|
// uint32_t pakFileHandle; // eax
|
|
// bool result; // al
|
|
// int AsyncFile; // bl
|
|
// signed __int64 v19; // rbx
|
|
// char v20; // r14
|
|
// __int64 v21; // rdx
|
|
// const char* v22; // rax
|
|
// __int64 v23; // rbx
|
|
// __int64 asset_entry_count_var; // rax MAPDST
|
|
// __int64 patchIndex; // r11
|
|
// __int64 memPageCount; // r9
|
|
// __int64 virtualSegmentCount; // rcx
|
|
// __int64 v32; // r8
|
|
// __int64 v33; // rcx
|
|
// __int64 v34; // r14
|
|
// __int64 v35; // r12
|
|
// uint64_t ringBufferStreamSize; // rsi
|
|
// uint64_t ringBufferOutSize; // rax
|
|
// PakFile_t* pak; // rax MAPDST
|
|
// _DWORD* v40; // rax
|
|
// __int64 v43; // rdx
|
|
// uint8_t** v44; // rcx
|
|
// PakAsset_t** v45; // rdx
|
|
// PakPatchFileHeader_t* p_patchHeader; // rcx
|
|
// uint16_t v47; // ax
|
|
// PakPatchFileHeader_t* p_decompressedSize; // rdx
|
|
// __int64 v49; // rcx
|
|
// __int64 v50; // rax
|
|
// unsigned __int16* v51; // rcx
|
|
// char* v52; // rcx
|
|
// char* v53; // rdx
|
|
// __int64 v54; // rax
|
|
// PakSegmentHeader_t* v55; // rdx
|
|
// __int64 v56; // rcx
|
|
// __int64 v57; // rax
|
|
// PakPageHeader_t* v58; // rcx
|
|
// __int64 descriptorCount; // rdx
|
|
// PakPage_t* v60; // rcx
|
|
// __int64 assetCount; // rax
|
|
// PakAsset_t* v62; // r8
|
|
// __int64 guidDescriptorCount; // r9
|
|
// PakPage_t* v64; // rdx
|
|
// __int64 relationsCounts; // rcx
|
|
// uint32_t* v66; // rax
|
|
// __int64 v67; // rdx
|
|
// uint32_t* v68; // rcx
|
|
// __int64 v69; // r8
|
|
// uint32_t* v70; // rax
|
|
// __int64 v71; // rcx
|
|
// PakPatchDataHeader_t* patchDataHeader; // rax
|
|
// size_t v73; // rdx
|
|
// uint8_t* ringBuffer; // rax
|
|
// bool v75; // zf
|
|
// __int64 v76; // r10
|
|
// unsigned __int64 v77; // r8
|
|
// __int64 v78; // rax
|
|
// PakFileHeader_t pakHdr; // [rsp+40h] [rbp-C0h] BYREF
|
|
// __int64 v80; // [rsp+C0h] [rbp-40h]
|
|
// __int64 v81; // [rsp+C8h] [rbp-38h]
|
|
// char relativeFilePath[260]; // [rsp+E0h] [rbp-20h] BYREF
|
|
// char v84[12]; // [rsp+1E4h] [rbp+E4h] BYREF
|
|
// CHAR LibFileName[4]; // [rsp+1F0h] [rbp+F0h] BYREF
|
|
// char v86[8252]; // [rsp+1F4h] [rbp+F4h]
|
|
// size_t pak_file_size_var; // [rsp+2248h] [rbp+2148h] BYREF
|
|
// __int64 v89; // [rsp+2250h] [rbp+2150h]
|
|
// uint64_t v90; // [rsp+2258h] [rbp+2158h]
|
|
//
|
|
// v2 = 0i64;
|
|
//
|
|
// PakLoadedInfo_t* const loadedInfo = Pak_GetPakInfo(pakId);
|
|
//
|
|
// loadedInfo->status = PAK_STATUS_LOAD_STARTING;
|
|
// pakFilePath = loadedInfo->fileName;
|
|
//
|
|
// //
|
|
// assert(pakFilePath);
|
|
//
|
|
// const char* nameUnqualified = V_UnqualifiedFileName(pakFilePath);
|
|
//
|
|
// if (nameUnqualified != pakFilePath)
|
|
// goto LABEL_27;
|
|
//
|
|
// snprintf(relativeFilePath, 0x100ui64, "paks\\Win64\\%s", pakFilePath);
|
|
//
|
|
// v7 = g_nPatchEntryCount;
|
|
// v8 = 0;
|
|
//
|
|
// // if this pak is patched, load the last patch file first before proceeding
|
|
// // with any other pak that is getting patched. note that the patch number
|
|
// // does not indicate which pak file is the actual last patch file; a patch
|
|
// // with number (01) can also patch (02) and base, these details are
|
|
// // determined from the pak file header
|
|
// if (g_nPatchEntryCount)
|
|
// {
|
|
// v9 = g_pszPakPatchList;
|
|
//
|
|
// int n;
|
|
// while (1)
|
|
// {
|
|
// n = V_stricmp(pakFilePath, v9[(v7 + v8) >> 1]);
|
|
//
|
|
// if (n >= 0)
|
|
// break;
|
|
//
|
|
// v7 = v11;
|
|
// LABEL_13:
|
|
// if (v8 >= v7)
|
|
// goto SKIP_PATCH_LOADING;
|
|
// }
|
|
//
|
|
// if (n > 0)
|
|
// {
|
|
// v8 = v11 + 1;
|
|
// goto LABEL_13;
|
|
// }
|
|
//
|
|
// const int patchNumber = g_pnPatchNumbers[v11];
|
|
//
|
|
// if (patchNumber)
|
|
// {
|
|
// char* const extension = (char*)V_GetFileExtension(pakFilePath, true);
|
|
// snprintf(extension, &relativeFilePath[sizeof(relativeFilePath)] - extension, "(%02u).rpak", patchNumber);
|
|
// }
|
|
// }
|
|
//
|
|
// if (!g_nPatchEntryCount)
|
|
// goto SKIP_PATCH_LOADING;
|
|
//
|
|
// v9 = g_pszPakPatchList;
|
|
// while (1)
|
|
// {
|
|
// LOBYTE(v10) = stricmp(pakFilePath, v9[(v7 + v8) >> 1]);
|
|
// if (v10 >= 0)
|
|
// break;
|
|
// v7 = v11;
|
|
// LABEL_13:
|
|
// if (v8 >= v7)
|
|
// goto SKIP_PATCH_LOADING;
|
|
// }
|
|
// if (v10 > 0)
|
|
// {
|
|
// v8 = v11 + 1;
|
|
// goto LABEL_13;
|
|
// }
|
|
//
|
|
// const int patchNumber = g_pnPatchNumbers[v11];
|
|
//
|
|
// if (patchNumber)
|
|
// {
|
|
// char* const extension = (char*)V_GetFileExtension(pakFilePath, true);
|
|
// snprintf(extension, &relativeFilePath[sizeof(relativeFilePath)] - extension, "(%02u).rpak", patchNumber);
|
|
// }
|
|
//
|
|
//SKIP_PATCH_LOADING:
|
|
// pakFilePath = relativeFilePath;
|
|
//LABEL_27:
|
|
// pakFileHandle = FS_OpenAsyncFile(pakFilePath, loadedInfo->logLevel, &pak_file_size_var);
|
|
//
|
|
// if (pakFileHandle == FS_ASYNC_FILE_INVALID)
|
|
// {
|
|
// if (async_debug_level.GetInt() >= loadedInfo->logLevel)
|
|
// Error(eDLL_T::RTECH, NO_ERROR, "Couldn't read package file \"%s\".\n", pakFilePath);
|
|
//
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// loadedInfo->fileHandle = pakFileHandle;
|
|
//
|
|
// // file appears truncated/corrupt
|
|
// if (pak_file_size_var < sizeof(PakFileHeader_t))
|
|
// {
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// AsyncFile = v_FS_ReadAsyncFile(pakFileHandle, 0i64, sizeof(PakFileHeader_t), &pakHdr, 0i64, 0i64, 4);
|
|
// v_FS_WaitForAsyncRead(AsyncFile);
|
|
//
|
|
// size_t bytesProcessed = 0;
|
|
// const char* statusMsg = "(no reason)";
|
|
// const uint8_t currentStatus = g_pakLoadApi->CheckAsyncRequest(AsyncFile, &bytesProcessed, &statusMsg);
|
|
//
|
|
// if (currentStatus == AsyncHandleStatus_t::FS_ASYNC_ERROR)
|
|
// {
|
|
// Error(eDLL_T::RTECH, EXIT_FAILURE, "Error reading pak file \"%s\" -- %s\n", pak->memoryData.fileName, statusMsg);
|
|
//
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// if (pakHdr.magic != PAK_HEADER_MAGIC || pakHdr.version != PAK_HEADER_VERSION)
|
|
// {
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// if (pakHdr.flags & PAK_HEADER_FLAGS_HAS_MODULE_EXTENDED)
|
|
// {
|
|
// v22 = V_GetFileExtension(pakFilePath);
|
|
// v23 = v22 - pakFilePath;
|
|
//
|
|
// if ((unsigned __int64)(v22 - pakFilePath + 4) >= 0x2000)
|
|
// {
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// memcpy(LibFileName, pakFilePath, v22 - pakFilePath);
|
|
//
|
|
// *(_DWORD*)&LibFileName[v23] = *(_DWORD*)".dll";
|
|
// v86[v23] = '\0';
|
|
//
|
|
// const HMODULE hModule = LoadLibraryA(LibFileName);
|
|
// loadedInfo->hModule = hModule;
|
|
//
|
|
// if (!hModule)
|
|
// {
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
// }
|
|
//
|
|
// loadedInfo->fileTime = pakHdr.fileTime;
|
|
// asset_entry_count_var = pakHdr.assetCount;
|
|
//
|
|
// loadedInfo->assetCount = pakHdr.assetCount;
|
|
//
|
|
// asset_entry_count_var = pakHdr.assetCount;
|
|
// patchIndex = pakHdr.patchIndex;
|
|
// memPageCount = pakHdr.memPageCount;
|
|
// virtualSegmentCount = pakHdr.virtualSegmentCount;
|
|
// v32 = *(unsigned int*)&pakHdr.unk2[4];
|
|
//
|
|
// loadedInfo->assetGuids = (PakGuid_t*)loadedInfo->allocator->Alloc(sizeof(PakGuid_t) * asset_entry_count_var, 8);;
|
|
//
|
|
// size_t streamingFilesBuifSize = pakHdr.streamingFilesBufSize[STREAMING_SET_OPTIONAL] + pakHdr.streamingFilesBufSize[STREAMING_SET_MANDATORY];
|
|
//
|
|
// v81 = 8 * memPageCount;
|
|
//
|
|
// pak_file_size_var = streamingFilesBuifSize
|
|
// + ((_WORD)patchIndex != 0 ? 8 : 0)
|
|
// + 2
|
|
// * (patchIndex
|
|
// + 2
|
|
// * (pakHdr.relationsCounts
|
|
// + *(unsigned int*)pakHdr.unk2
|
|
// + 3 * memPageCount
|
|
// + 2 * (pakHdr.descriptorCount + pakHdr.guidDescriptorCount + 16i64 + 2 * (asset_entry_count_var + patchIndex + 4 * asset_entry_count_var + virtualSegmentCount))))
|
|
// + v32;
|
|
//
|
|
// v80 = 4 * asset_entry_count_var;
|
|
// v90 = pak_file_size_var + 2080;
|
|
// v33 = -((_DWORD)pak_file_size_var + 2080 + 4 * (_DWORD)asset_entry_count_var) & 7;
|
|
// v89 = v33;
|
|
// v34 = 4 * asset_entry_count_var + pak_file_size_var + 2080 + v33 + 8 * memPageCount + 12 * asset_entry_count_var;
|
|
// v35 = (-(4 * (_DWORD)asset_entry_count_var + (_DWORD)pak_file_size_var + 2080 + (_DWORD)v33 + 8 * (_DWORD)memPageCount + 12 * (_DWORD)asset_entry_count_var) & 7) + 4088i64;
|
|
//
|
|
// if ((pakHdr.flags & 0x100) != 0)
|
|
// {
|
|
// ringBufferStreamSize = PAK_DECODE_IN_RING_BUFFER_SIZE;
|
|
// ringBufferOutSize = PAK_DECODE_OUT_RING_BUFFER_SIZE;
|
|
//
|
|
// if (pakHdr.compressedSize < PAK_DECODE_IN_RING_BUFFER_SIZE && !(_WORD)patchIndex)
|
|
// ringBufferStreamSize = (pakHdr.compressedSize + PAK_DECODE_IN_RING_BUFFER_SMALL_MASK) & 0xFFFFFFFFFFFFF000ui64;
|
|
// }
|
|
// else
|
|
// {
|
|
// ringBufferStreamSize = 0i64;
|
|
// ringBufferOutSize = PAK_DECODE_IN_RING_BUFFER_SIZE;
|
|
// }
|
|
//
|
|
// if (ringBufferOutSize > pakHdr.decompressedSize && !(_WORD)patchIndex)
|
|
// ringBufferOutSize = (pakHdr.decompressedSize + PAK_DECODE_IN_RING_BUFFER_SMALL_MASK) & 0xFFFFFFFFFFFFF000ui64;
|
|
//
|
|
// pak = (PakFile_t*)AlignedMemAlloc()->Alloc(v34 + v35 + ringBufferOutSize + ringBufferStreamSize, 8);
|
|
//
|
|
// if (pak)
|
|
// {
|
|
// loadedInfo->pakFile = pak;
|
|
//
|
|
// *(_QWORD*)&pak->processedPageCount = 0i64;
|
|
// *(_QWORD*)&pak->patchCount = 0i64;
|
|
// *(_QWORD*)&pak->numProcessedPointers = 0i64;
|
|
// *(_QWORD*)&pak->memoryData.someAssetCount = 0i64;
|
|
//
|
|
// v40 = (_DWORD*)loadedInfo->allocator->Alloc(16i64 * pakHdr.guidDescriptorCount + 8, 8i64);
|
|
// loadedInfo->qword50 = v40;
|
|
//
|
|
// *v40 = 0;
|
|
//
|
|
// *(_DWORD*)(loadedInfo->qword50 + 4i64) = 0;
|
|
//
|
|
// pak->memoryData.pakHeader = pakHdr;
|
|
//
|
|
// pak->memoryData.pakId = pakId;
|
|
// pak->memoryData.qword2D0 = pak_file_size_var;
|
|
//
|
|
// JobID_t jobId = PAK_DEFAULT_JOB_GROUP_ID;
|
|
//
|
|
// if (pakHdr.assetCount)
|
|
// jobId = JT_BeginJobGroup(0);
|
|
//
|
|
// pak->memoryData.unkJobID = jobId;
|
|
//
|
|
//
|
|
// v43 = v81;
|
|
// v44 = (uint8_t**)((char*)pak + v89 + v90 + v80);
|
|
// pak->memoryData.memPageBuffers = v44;
|
|
// v45 = (PakAsset_t**)((char*)v44 + v43);
|
|
// pak->memoryData.ppAssetEntries = v45;
|
|
// pak->memoryData.qword2E0 = (int*)&v45[pakHdr.assetCount];
|
|
// p_patchHeader = &pak->memoryData.patchHeader;
|
|
// v47 = pak->memoryData.pakHeader.patchIndex;
|
|
//
|
|
// p_decompressedSize = (PakPatchFileHeader_t*)&pak->memoryData.patchHeader.decompressedSize;
|
|
// if (!v47)
|
|
// p_decompressedSize = &pak->memoryData.patchHeader;
|
|
// if (!v47)
|
|
// p_patchHeader = 0i64;
|
|
//
|
|
// pak->memoryData.patchDataHeader = (PakPatchDataHeader_t*)p_patchHeader;
|
|
// v49 = pak->memoryData.pakHeader.patchIndex;
|
|
// pak->memoryData.patchHeaders = p_decompressedSize;
|
|
// v50 = pak->memoryData.pakHeader.patchIndex;
|
|
// v51 = (unsigned __int16*)&p_decompressedSize[v49];
|
|
// pak->memoryData.patchIndices = v51;
|
|
// v52 = (char*)&v51[v50];
|
|
// v53 = &v52[pak->memoryData.pakHeader.streamingFilesBufSize[0]];
|
|
// pak->memoryData.streamingFilePaths[0] = v52;
|
|
// v54 = pak->memoryData.pakHeader.streamingFilesBufSize[1];
|
|
// pak->memoryData.streamingFilePaths[1] = v53;
|
|
// v55 = (PakSegmentHeader_t*)&v53[v54];
|
|
// v56 = pak->memoryData.pakHeader.virtualSegmentCount;
|
|
// pak->memoryData.segmentHeaders = v55;
|
|
// v57 = pak->memoryData.pakHeader.memPageCount;
|
|
// v58 = (PakPageHeader_t*)&v55[v56];
|
|
// pak->memoryData.pageHeaders = v58;
|
|
// descriptorCount = pak->memoryData.pakHeader.descriptorCount;
|
|
// v60 = (PakPage_t*)&v58[v57];
|
|
// pak->memoryData.virtualPointers = v60;
|
|
// assetCount = pak->memoryData.pakHeader.assetCount;
|
|
// v62 = (PakAsset_t*)&v60[descriptorCount];
|
|
// pak->memoryData.assetEntries = v62;
|
|
// guidDescriptorCount = pak->memoryData.pakHeader.guidDescriptorCount;
|
|
// v64 = (PakPage_t*)&v62[assetCount];
|
|
// pak->memoryData.guidDescriptors = v64;
|
|
// relationsCounts = pak->memoryData.pakHeader.relationsCounts;
|
|
// v66 = (uint32_t*)&v64[guidDescriptorCount];
|
|
// pak->memoryData.fileRelations = v66;
|
|
// v67 = *(unsigned int*)pak->memoryData.pakHeader.unk2;
|
|
// v68 = &v66[relationsCounts];
|
|
// *(_QWORD*)pak->memoryData.gap5E0 = v68;
|
|
// v69 = *(unsigned int*)&pak->memoryData.pakHeader.unk2[4];
|
|
// *(_QWORD*)&pak->memoryData.gap5E0[16] = 0i64;
|
|
// v70 = &v68[v67];
|
|
// *(_QWORD*)&pak->memoryData.gap5E0[8] = v70;
|
|
// v71 = (__int64)v70 + v69;
|
|
// *(_QWORD*)&pak->memoryData.gap5E0[24] = (char*)v70 + v69;
|
|
// if (pak->memoryData.pakHeader.patchIndex)
|
|
// {
|
|
// patchDataHeader = pak->memoryData.patchDataHeader;
|
|
// if (patchDataHeader->editStreamSize)
|
|
// {
|
|
// *(_QWORD*)&pak->memoryData.gap5E0[16] = v71;
|
|
// *(_QWORD*)&pak->memoryData.gap5E0[24] = v71 + (unsigned int)patchDataHeader->editStreamSize;
|
|
// }
|
|
// }
|
|
// v73 = PAK_DECODE_IN_RING_BUFFER_MASK;
|
|
//
|
|
// pak->memoryData.fileName = loadedInfo->fileName;
|
|
// pak->fileStream.qword0 = 0i64;
|
|
// pak->fileStream.fileSize = pakHdr.compressedSize;
|
|
// pak->fileStream.fileHandle = loadedInfo->fileHandle;
|
|
// loadedInfo->fileHandle = FS_ASYNC_FILE_INVALID;
|
|
//
|
|
// pak->fileStream.bufferMask = PAK_DECODE_IN_RING_BUFFER_MASK;
|
|
//
|
|
// ringBuffer = (uint8_t*)(((unsigned __int64)pak + v35 + v34) & 0xFFFFFFFFFFFFF000ui64);
|
|
//
|
|
// pak->fileStream.buffer = ringBuffer;
|
|
// pak->fileStream.numDataChunksProcessed = 0;
|
|
// pak->fileStream.numDataChunks = 0;
|
|
// pak->fileStream.fileReadStatus = 3;
|
|
// pak->fileStream.finishedLoadingPatches = 0;
|
|
// pak->fileStream.numLoadedFiles = 0;
|
|
// pak->fileStream.bytesStreamed = sizeof(PakFileHeader_t);
|
|
// pak->decompBuffer = &ringBuffer[ringBufferStreamSize];
|
|
// pak->inputBytePos = sizeof(PakFileHeader_t);
|
|
// pak->byte1F8 = 0;
|
|
// pak->byte1FD = 1;
|
|
// pak->isOffsetted_MAYBE = 0;
|
|
// pak->isCompressed = 0;
|
|
//
|
|
// // FINISHME: this means if the pak file is not encoded, but we should also
|
|
// // check on the zstd flags
|
|
// v75 = (pakHdr.flags & 0x100) == 0;
|
|
//
|
|
// pak->qword298 = 128i64;
|
|
//
|
|
// if (!v75)
|
|
// v73 = PAK_DECODE_OUT_RING_BUFFER_MASK;
|
|
//
|
|
// pak->maxCopySize = v73;
|
|
// memset(&pak->pakDecoder, 0, sizeof(pak->pakDecoder));
|
|
//
|
|
// pak->pakDecoder.outBufBytePos = 128i64;
|
|
// pak->pakDecoder.decompSize = 128i64;
|
|
// pak->memoryData.processedPatchedDataSize = 128i64;
|
|
// v76 = pakHdr.patchIndex;
|
|
// v77 = pakHdr.descriptorCount + 2 * (pakHdr.patchIndex + (unsigned __int64)pakHdr.assetCount + 4i64 * pakHdr.assetCount + pakHdr.virtualSegmentCount);
|
|
// v78 = pakHdr.memPageCount;
|
|
//
|
|
// pak->memoryData.field_2A8 = 0i64;
|
|
// pak->memoryData.patchData = 0i64;
|
|
// pak->memoryData.patchDataPtr = 0i64;
|
|
// pak->memoryData.bitBuf.m_dataBuf = 0i64;
|
|
// pak->memoryData.bitBuf.m_bitsAvailable = 0;
|
|
// pak->memoryData.patchDataOffset = 0;
|
|
// pak->memoryData.patchSrcSize = v82 + ((_WORD)v76 != 0 ? 8 : 0) + 2 * (v76 + 6 * v78 + 4 * v77);
|
|
// pak->memoryData.patchDstPtr = (char*)&pak->memoryData.patchHeader;
|
|
// pak->memoryData.patchFunc = g_pakPatchApi[0];
|
|
//
|
|
// LOBYTE(v2) = pakHdr.patchIndex == 0;
|
|
// pak->memoryData.numBytesToProcess_maybe = pak->memoryData.pakHeader.decompressedSize + v2 - 0x80;
|
|
//
|
|
// Pak_ProcessPakFile(pak);
|
|
// return true;
|
|
// }
|
|
// else
|
|
// {
|
|
// loadedInfo->status = PAK_STATUS_ERROR;
|
|
// return false;
|
|
// }
|
|
//
|
|
// return result;
|
|
//}
|
|
|
|
|
|
void V_PakParse::Detour(const bool bAttach) const
|
|
{
|
|
DetourSetup(&v_Pak_LoadAsync, &Pak_LoadAsync, bAttach);
|
|
DetourSetup(&v_Pak_UnloadAsync, &Pak_UnloadAsync, bAttach);
|
|
|
|
DetourSetup(&v_Pak_StartLoadingPak, &Pak_StartLoadingPak, bAttach);
|
|
|
|
DetourSetup(&v_Pak_ProcessPakFile, &Pak_ProcessPakFile, bAttach);
|
|
DetourSetup(&v_Pak_ResolveAssetRelations, &Pak_ResolveAssetRelations, bAttach);
|
|
DetourSetup(&v_Pak_ProcessAssets, &Pak_ProcessAssets, bAttach);
|
|
|
|
DetourSetup(&v_Pak_RunAssetLoadingJobs, &Pak_RunAssetLoadingJobs, bAttach);
|
|
}
|