mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
RTech: major pak system overhaul and rebuild
* split rtech_game and rtech_utils cpp files into multiple files * rebuilt several large pak load routines for debugging and custom implementations * moved rson code to rtech_game * reworked and improved engine and sdk pak precache system * reversed more of the jobthreads system
This commit is contained in:
parent
1783db92b5
commit
fe2a95e4ec
@ -25,9 +25,14 @@
|
||||
#ifndef CLIENT_DLL
|
||||
#include "engine/server/server.h"
|
||||
#endif // !CLIENT_DLL
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
|
||||
#include "rtech/pak/pakdecode.h"
|
||||
#include "rtech/pak/pakparse.h"
|
||||
#include "rtech/pak/pakstate.h"
|
||||
#include "rtech/pak/paktools.h"
|
||||
|
||||
#include "rtech/playlists/playlists.h"
|
||||
|
||||
#include "filesystem/basefilesystem.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "vpklib/packedstore.h"
|
||||
@ -295,13 +300,13 @@ void Pak_ListPaks_f(const CCommand& args)
|
||||
{
|
||||
const PakLoadedInfo_t& info = g_pLoadedPakInfo[i];
|
||||
|
||||
if (info.m_status == EPakStatus::PAK_STATUS_FREED)
|
||||
if (info.status == EPakStatus::PAK_STATUS_FREED)
|
||||
continue;
|
||||
|
||||
const char* szRpakStatus = g_pRTech->PakStatusToString(info.m_status);
|
||||
const char* szRpakStatus = Pak_StatusToString(info.status);
|
||||
|
||||
// todo: make status into a string from an array/vector
|
||||
Msg(eDLL_T::RTECH, "| %04i | %-50s | %-36s | %11i |\n", info.m_handle, info.m_fileName, szRpakStatus, info.m_assetCount);
|
||||
Msg(eDLL_T::RTECH, "| %04i | %-50s | %-36s | %11i |\n", info.handle, info.fileName, szRpakStatus, info.assetCount);
|
||||
nTotalLoaded++;
|
||||
}
|
||||
Msg(eDLL_T::RTECH, "|------|----------------------------------------------------|--------------------------------------|-------------|\n");
|
||||
@ -325,10 +330,10 @@ void Pak_ListTypes_f(const CCommand& args)
|
||||
{
|
||||
PakAssetBinding_t* type = &g_pPakGlobals->m_assetBindings[i];
|
||||
|
||||
if (!type->m_description)
|
||||
if (!type->description)
|
||||
continue;
|
||||
|
||||
Msg(eDLL_T::RTECH, "| %-4s | %-25s | %7i | %11i | %11i |\n", FourCCToString(type->m_extension).c_str(), type->m_description, type->m_version, type->m_subHeaderSize, type->m_nativeClassSize);
|
||||
Msg(eDLL_T::RTECH, "| %-4s | %-25s | %7i | %11i | %11i |\n", FourCCToString(type->extension).c_str(), type->description, type->version, type->headerSize, type->nativeClassSize);
|
||||
nRegistered++;
|
||||
}
|
||||
Msg(eDLL_T::RTECH, "|------|---------------------------|---------|-------------|-------------|\n");
|
||||
@ -348,37 +353,31 @@ void Pak_RequestUnload_f(const CCommand& args)
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
if (args.HasOnlyDigits(1))
|
||||
{
|
||||
if (args.HasOnlyDigits(1))
|
||||
{
|
||||
const PakHandle_t pakHandle = atoi(args.Arg(1));
|
||||
const PakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(pakHandle);
|
||||
if (!pakInfo)
|
||||
{
|
||||
throw std::exception("Found no pak entry for specified handle.");
|
||||
}
|
||||
const PakHandle_t pakHandle = atoi(args.Arg(1));
|
||||
const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(pakHandle);
|
||||
|
||||
const string pakName = pakInfo->m_fileName;
|
||||
!pakName.empty() ? Msg(eDLL_T::RTECH, "Requested pak unload for file '%s'\n", pakName.c_str()) : Msg(eDLL_T::RTECH, "Requested pak unload for handle '%d'\n", pakHandle);
|
||||
g_pakLoadApi->UnloadPak(pakHandle);
|
||||
}
|
||||
else
|
||||
if (!pakInfo)
|
||||
{
|
||||
const PakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(args.Arg(1));
|
||||
if (!pakInfo)
|
||||
{
|
||||
throw std::exception("Found no pak entry for specified name.");
|
||||
}
|
||||
|
||||
Msg(eDLL_T::RTECH, "Requested pak unload for file '%s'\n", args.Arg(1));
|
||||
g_pakLoadApi->UnloadPak(pakInfo->m_handle);
|
||||
Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Msg(eDLL_T::RTECH, "Requested pak unload for handle '%d'\n", pakHandle);
|
||||
g_pakLoadApi->UnloadAsync(pakHandle);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
else
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - %s\n", __FUNCTION__, e.what());
|
||||
return;
|
||||
const PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(args.Arg(1));
|
||||
if (!pakInfo)
|
||||
{
|
||||
Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
Msg(eDLL_T::RTECH, "Requested pak unload for file '%s'\n", args.Arg(1));
|
||||
g_pakLoadApi->UnloadAsync(pakInfo->handle);
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,49 +399,45 @@ Pak_Swap_f
|
||||
*/
|
||||
void Pak_Swap_f(const CCommand& args)
|
||||
{
|
||||
try
|
||||
const char* pakName = nullptr;
|
||||
|
||||
PakHandle_t pakHandle = INVALID_PAK_HANDLE;
|
||||
const PakLoadedInfo_t* pakInfo = nullptr;
|
||||
|
||||
if (args.HasOnlyDigits(1))
|
||||
{
|
||||
string pakName;
|
||||
PakHandle_t pakHandle = 0;
|
||||
PakLoadedInfo_t* pakInfo = nullptr;
|
||||
pakHandle = atoi(args.Arg(1));
|
||||
pakInfo = Pak_GetPakInfo(pakHandle);
|
||||
|
||||
if (args.HasOnlyDigits(1))
|
||||
if (!pakInfo)
|
||||
{
|
||||
pakHandle = atoi(args.Arg(1));
|
||||
pakInfo = g_pRTech->GetPakLoadedInfo(pakHandle);
|
||||
if (!pakInfo)
|
||||
{
|
||||
throw std::exception("Found no pak entry for specified handle.");
|
||||
}
|
||||
|
||||
pakName = pakInfo->m_fileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
pakName = args.Arg(1);
|
||||
pakInfo = g_pRTech->GetPakLoadedInfo(args.Arg(1));
|
||||
if (!pakInfo)
|
||||
{
|
||||
throw std::exception("Found no pak entry for specified name.");
|
||||
}
|
||||
|
||||
pakHandle = pakInfo->m_handle;
|
||||
Warning(eDLL_T::RTECH, "Found no pak entry for specified handle.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
!pakName.empty() ? Msg(eDLL_T::RTECH, "Requested pak swap for file '%s'\n", pakName.c_str()) : Msg(eDLL_T::RTECH, "Requested pak swap for handle '%d'\n", pakHandle);
|
||||
|
||||
g_pakLoadApi->UnloadPak(pakHandle);
|
||||
|
||||
while (pakInfo->m_status != EPakStatus::PAK_STATUS_FREED) // Wait till this slot gets free'd.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
g_pakLoadApi->LoadAsync(pakName.c_str(), AlignedMemAlloc(), NULL, 0);
|
||||
pakName = pakInfo->fileName;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
else
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - %s\n", __FUNCTION__, e.what());
|
||||
return;
|
||||
pakName = args.Arg(1);
|
||||
pakInfo = Pak_GetPakInfo(pakName);
|
||||
|
||||
if (!pakInfo)
|
||||
{
|
||||
Warning(eDLL_T::RTECH, "Found no pak entry for specified name.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pakHandle = pakInfo->handle;
|
||||
}
|
||||
|
||||
Msg(eDLL_T::RTECH, "Requested pak swap for handle '%d'\n", pakHandle);
|
||||
g_pakLoadApi->UnloadAsync(pakHandle);
|
||||
|
||||
while (pakInfo->status != EPakStatus::PAK_STATUS_FREED) // Wait till this slot gets free'd.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
g_pakLoadApi->LoadAsync(pakName, AlignedMemAlloc(), NULL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -450,14 +445,14 @@ void Pak_Swap_f(const CCommand& args)
|
||||
RTech_StringToGUID_f
|
||||
=====================
|
||||
*/
|
||||
void RTech_StringToGUID_f(const CCommand& args)
|
||||
void Pak_StringToGUID_f(const CCommand& args)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long long guid = g_pRTech->StringToGuid(args.Arg(1));
|
||||
unsigned long long guid = Pak_StringToGuid(args.Arg(1));
|
||||
|
||||
Msg(eDLL_T::RTECH, "______________________________________________________________\n");
|
||||
Msg(eDLL_T::RTECH, "] RTECH_HASH ]------------------------------------------------\n");
|
||||
@ -469,10 +464,10 @@ void RTech_StringToGUID_f(const CCommand& args)
|
||||
RTech_Decompress_f
|
||||
|
||||
Decompresses input RPak file and
|
||||
dumps results to 'paks\Win32\*.rpak'
|
||||
dumps results to override path
|
||||
=====================
|
||||
*/
|
||||
void RTech_Decompress_f(const CCommand& args)
|
||||
void Pak_Decompress_f(const CCommand& args)
|
||||
{
|
||||
if (args.ArgC() < 2)
|
||||
{
|
||||
@ -505,41 +500,41 @@ void RTech_Decompress_f(const CCommand& args)
|
||||
return;
|
||||
}
|
||||
|
||||
const ssize_t nPakLen = FileSystem()->Size(hPakFile);
|
||||
const ssize_t nFileSize = FileSystem()->Size(hPakFile);
|
||||
|
||||
std::unique_ptr<uint8_t[]> pPakBufContainer(new uint8_t[nPakLen]);
|
||||
std::unique_ptr<uint8_t[]> pPakBufContainer(new uint8_t[nFileSize]);
|
||||
uint8_t* const pPakBuf = pPakBufContainer.get();
|
||||
|
||||
FileSystem()->Read(pPakBuf, nPakLen, hPakFile);
|
||||
FileSystem()->Read(pPakBuf, nFileSize, hPakFile);
|
||||
FileSystem()->Close(hPakFile);
|
||||
|
||||
PakFileHeader_t* pHeader = reinterpret_cast<PakFileHeader_t*>(pPakBuf);
|
||||
uint16_t flags = (pHeader->m_flags[0] << 8) | pHeader->m_flags[1];
|
||||
uint16_t flags = (pHeader->flags[0] << 8) | pHeader->flags[1];
|
||||
|
||||
SYSTEMTIME systemTime;
|
||||
FileTimeToSystemTime(&pHeader->m_fileTime, &systemTime);
|
||||
FileTimeToSystemTime(&pHeader->fileTime, &systemTime);
|
||||
|
||||
Msg(eDLL_T::RTECH, " | |-+ Header ------------------------------------------------\n");
|
||||
Msg(eDLL_T::RTECH, " | |-- Magic : '0x%08X'\n", pHeader->m_magic);
|
||||
Msg(eDLL_T::RTECH, " | |-- Version : '%hu'\n", pHeader->m_version);
|
||||
Msg(eDLL_T::RTECH, " | |-- Magic : '0x%08X'\n", pHeader->magic);
|
||||
Msg(eDLL_T::RTECH, " | |-- Version : '%hu'\n", pHeader->version);
|
||||
Msg(eDLL_T::RTECH, " | |-- Flags : '0x%04hX'\n", flags);
|
||||
Msg(eDLL_T::RTECH, " | |-- Time : '%hu-%hu-%hu/%hu %hu:%hu:%hu.%hu'\n",
|
||||
systemTime.wYear,systemTime.wMonth,systemTime.wDay, systemTime.wDayOfWeek,
|
||||
systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wDayOfWeek,
|
||||
systemTime.wHour, systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
|
||||
Msg(eDLL_T::RTECH, " | |-- Hash : '0x%08llX'\n", pHeader->m_checksum);
|
||||
Msg(eDLL_T::RTECH, " | |-- Entries : '%u'\n", pHeader->m_assetEntryCount);
|
||||
Msg(eDLL_T::RTECH, " | |-- Hash : '0x%08llX'\n", pHeader->checksum);
|
||||
Msg(eDLL_T::RTECH, " | |-- Entries : '%u'\n", pHeader->assetCount);
|
||||
Msg(eDLL_T::RTECH, " | |-+ Compression -----------------------------------------\n");
|
||||
Msg(eDLL_T::RTECH, " | |-- Size comp: '%zu'\n", pHeader->m_compressedSize);
|
||||
Msg(eDLL_T::RTECH, " | |-- Size decp: '%zu'\n", pHeader->m_decompressedSize);
|
||||
Msg(eDLL_T::RTECH, " | |-- Size comp: '%zu'\n", pHeader->compressedSize);
|
||||
Msg(eDLL_T::RTECH, " | |-- Size decp: '%zu'\n", pHeader->decompressedSize);
|
||||
|
||||
if (pHeader->m_magic != PAK_HEADER_MAGIC)
|
||||
if (pHeader->magic != PAK_HEADER_MAGIC)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' has invalid magic!\n",
|
||||
__FUNCTION__, inPakFile.String());
|
||||
|
||||
return;
|
||||
}
|
||||
if ((pHeader->m_flags[1] & 1) != 1)
|
||||
if ((pHeader->flags[1] & 1) != 1)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' already decompressed!\n",
|
||||
__FUNCTION__, inPakFile.String());
|
||||
@ -547,23 +542,21 @@ void RTech_Decompress_f(const CCommand& args)
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t unsignedPakLen = static_cast<size_t>(nPakLen);
|
||||
|
||||
if (pHeader->m_compressedSize != unsignedPakLen)
|
||||
if (pHeader->compressedSize != size_t(nFileSize))
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - pak file '%s' decompressed size '%zu' doesn't match expected size '%zu'!\n",
|
||||
__FUNCTION__, inPakFile.String(), unsignedPakLen, pHeader->m_decompressedSize);
|
||||
__FUNCTION__, inPakFile.String(), size_t(nFileSize), pHeader->compressedSize);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PakDecompState_t decompState;
|
||||
const uint64_t nDecompSize = g_pRTech->DecompressPakFileInit(&decompState, pPakBuf, unsignedPakLen, NULL, sizeof(PakFileHeader_t));
|
||||
PakDecoder_t decoder{}; // Needs full decode mask as we don't decompress in chunks.
|
||||
const uint64_t nDecompSize = Pak_InitDefaultDecoder(&decoder, pPakBuf, PAK_DECODE_MASK_FULL, nFileSize, NULL, sizeof(PakFileHeader_t));
|
||||
|
||||
if (nDecompSize != pHeader->m_decompressedSize)
|
||||
if (nDecompSize != pHeader->decompressedSize)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - calculated size: '%llu' expected: '%llu'!\n",
|
||||
__FUNCTION__, nDecompSize, pHeader->m_decompressedSize);
|
||||
__FUNCTION__, nDecompSize, pHeader->decompressedSize);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -572,24 +565,25 @@ void RTech_Decompress_f(const CCommand& args)
|
||||
Msg(eDLL_T::RTECH, " | |-- Size calc: '%llu'\n", nDecompSize);
|
||||
}
|
||||
|
||||
Msg(eDLL_T::RTECH, " | |-- Ratio : '%.02f'\n", (pHeader->m_compressedSize * 100.f) / pHeader->m_decompressedSize);
|
||||
Msg(eDLL_T::RTECH, " | |-- Ratio : '%.02f'\n", (pHeader->compressedSize * 100.f) / pHeader->decompressedSize);
|
||||
|
||||
|
||||
std::unique_ptr<uint8_t[]> pDecompBufContainer(new uint8_t[pHeader->m_decompressedSize]);
|
||||
std::unique_ptr<uint8_t[]> pDecompBufContainer(new uint8_t[pHeader->decompressedSize]);
|
||||
uint8_t* const pDecompBuf = pDecompBufContainer.get();
|
||||
|
||||
decompState.m_outputMask = UINT64_MAX;
|
||||
decompState.m_outputBuf = uint64_t(pDecompBuf);
|
||||
// Needs full decode mask as we don't decompress in chunks.
|
||||
decoder.outputMask = PAK_DECODE_MASK_FULL;
|
||||
decoder.outputBuf = pDecompBuf;
|
||||
|
||||
uint8_t nDecompResult = g_pRTech->DecompressPakFile(&decompState, unsignedPakLen, pHeader->m_decompressedSize);
|
||||
uint8_t nDecompResult = Pak_DefaultDecode(&decoder, pHeader->compressedSize, pHeader->decompressedSize);
|
||||
if (nDecompResult != 1)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s - decompression failed for '%s' return value: '%hu'!\n",
|
||||
__FUNCTION__, inPakFile.String(), nDecompResult);
|
||||
}
|
||||
|
||||
pHeader->m_flags[1] = 0x0; // Set compressed flag to false for the decompressed pak file.
|
||||
pHeader->m_compressedSize = pHeader->m_decompressedSize; // Equal compressed size with decompressed.
|
||||
pHeader->flags[1] = 0x0; // Set compressed flag to false for the decompressed pak file.
|
||||
pHeader->compressedSize = pHeader->decompressedSize; // Equal compressed size with decompressed.
|
||||
|
||||
FileSystem()->CreateDirHierarchy(PLATFORM_PAK_OVERRIDE_PATH, "GAME");
|
||||
FileHandle_t hDecompFile = FileSystem()->Open(outPakFile.String(), "wb", "GAME");
|
||||
@ -602,25 +596,25 @@ void RTech_Decompress_f(const CCommand& args)
|
||||
return;
|
||||
}
|
||||
|
||||
if (pHeader->m_patchIndex > 0) // Check if its an patch rpak.
|
||||
if (pHeader->patchIndex > 0) // Check if its an patch rpak.
|
||||
{
|
||||
// Loop through all the structs and patch their compress size.
|
||||
for (uint32_t i = 1, nPatchOffset = (sizeof(PakFileHeader_t) + sizeof(uint64_t));
|
||||
i <= pHeader->m_patchIndex; i++, nPatchOffset += sizeof(PakPatchFileHeader_t))
|
||||
i <= pHeader->patchIndex; i++, nPatchOffset += sizeof(PakPatchFileHeader_t))
|
||||
{
|
||||
PakPatchFileHeader_t* pPatchHeader = reinterpret_cast<PakPatchFileHeader_t*>(pDecompBuf + nPatchOffset);
|
||||
Msg(eDLL_T::RTECH, " | |-+ Patch #%02u -----------------------------------------\n", i);
|
||||
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);
|
||||
Msg(eDLL_T::RTECH, " | %s |-- Size comp: '%llu'\n", i < pHeader->patchIndex ? "|" : " ", pPatchHeader->m_sizeDisk);
|
||||
Msg(eDLL_T::RTECH, " | %s |-- Size decp: '%llu'\n", i < pHeader->patchIndex ? "|" : " ", pPatchHeader->m_sizeMemory);
|
||||
|
||||
pPatchHeader->m_sizeDisk = pPatchHeader->m_sizeMemory; // Fix size for decompress.
|
||||
}
|
||||
}
|
||||
|
||||
memcpy_s(pDecompBuf, sizeof(PakFileHeader_t), pPakBuf, sizeof(PakFileHeader_t));// Overwrite first 0x80 bytes which are NULL with the header data.
|
||||
FileSystem()->Write(pDecompBuf, decompState.m_decompSize, hDecompFile);
|
||||
FileSystem()->Write(pDecompBuf, decoder.decompSize, hDecompFile);
|
||||
|
||||
Msg(eDLL_T::RTECH, " |-- Checksum : '0x%08X'\n", crc32::update(NULL, pDecompBuf, decompState.m_decompSize));
|
||||
Msg(eDLL_T::RTECH, " |-- Checksum : '0x%08X'\n", crc32::update(NULL, pDecompBuf, decoder.decompSize));
|
||||
Msg(eDLL_T::RTECH, "-+ Decompressed pak file to: '%s'\n", outPakFile.String());
|
||||
Msg(eDLL_T::RTECH, "--------------------------------------------------------------\n");
|
||||
|
||||
|
@ -29,8 +29,8 @@ void Pak_ListTypes_f(const CCommand& args);
|
||||
void Pak_RequestUnload_f(const CCommand& args);
|
||||
void Pak_RequestLoad_f(const CCommand& args);
|
||||
void Pak_Swap_f(const CCommand& args);
|
||||
void RTech_StringToGUID_f(const CCommand& args);
|
||||
void RTech_Decompress_f(const CCommand& args);
|
||||
void Pak_StringToGUID_f(const CCommand& args);
|
||||
void Pak_Decompress_f(const CCommand& args);
|
||||
void VPK_Pack_f(const CCommand& args);
|
||||
void VPK_Unpack_f(const CCommand& args);
|
||||
void VPK_Mount_f(const CCommand& args);
|
||||
|
@ -293,7 +293,9 @@ ConVar* curl_timeout = nullptr;
|
||||
ConVar* curl_debug = nullptr;
|
||||
//-----------------------------------------------------------------------------
|
||||
// RTECH API |
|
||||
ConVar* rtech_debug = nullptr;
|
||||
ConVar* async_debug_level = nullptr;
|
||||
ConVar* async_debug_close = nullptr;
|
||||
ConVar* pak_debugrelations = nullptr;
|
||||
//-----------------------------------------------------------------------------
|
||||
// RUI |
|
||||
#ifndef DEDICATED
|
||||
@ -366,11 +368,11 @@ void ConVar_StaticInit(void)
|
||||
navmesh_debug_tile_range = ConVar::StaticCreate("navmesh_debug_tile_range" , "0" , FCVAR_DEVELOPMENTONLY, "NavMesh debug draw tiles ranging from shift index to this cvar.", true, 0.f, false, 0.f, nullptr, nullptr);
|
||||
navmesh_debug_camera_range = ConVar::StaticCreate("navmesh_debug_camera_range" , "2000" , FCVAR_DEVELOPMENTONLY, "Only debug draw tiles within this distance from camera origin.", true, 0.f, false, 0.f, nullptr, nullptr);
|
||||
#ifndef DEDICATED
|
||||
navmesh_draw_bvtree = ConVar::StaticCreate("navmesh_draw_bvtree" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the BVTree of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_portal = ConVar::StaticCreate("navmesh_draw_portal" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the portal of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_polys = ConVar::StaticCreate("navmesh_draw_polys" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the polys of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_poly_bounds = ConVar::StaticCreate("navmesh_draw_poly_bounds" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the bounds of the NavMesh polys.", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_poly_bounds_inner = ConVar::StaticCreate("navmesh_draw_poly_bounds_inner" , "0" , FCVAR_DEVELOPMENTONLY, "Draws the inner bounds of the NavMesh polys (requires navmesh_draw_poly_bounds).", false, 0.f, false, 0.f, nullptr, "Index: > 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_bvtree = ConVar::StaticCreate("navmesh_draw_bvtree" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the BVTree of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: >= 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_portal = ConVar::StaticCreate("navmesh_draw_portal" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the portal of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: >= 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_polys = ConVar::StaticCreate("navmesh_draw_polys" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the polys of the NavMesh tiles.", false, 0.f, false, 0.f, nullptr, "Index: >= 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_poly_bounds = ConVar::StaticCreate("navmesh_draw_poly_bounds" , "-1", FCVAR_DEVELOPMENTONLY, "Draws the bounds of the NavMesh polys.", false, 0.f, false, 0.f, nullptr, "Index: >= 0 && < mesh->m_tileCount");
|
||||
navmesh_draw_poly_bounds_inner = ConVar::StaticCreate("navmesh_draw_poly_bounds_inner" , "0" , FCVAR_DEVELOPMENTONLY, "Draws the inner bounds of the NavMesh polys (requires navmesh_draw_poly_bounds).", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
#endif // !DEDICATED
|
||||
|
||||
sv_language = ConVar::StaticCreate("sv_language", "english", FCVAR_RELEASE, "Language of the server. Sent to MasterServer for localising error messages.", false, 0.f, false, 0.f, LanguageChanged_f, nullptr);
|
||||
@ -521,7 +523,10 @@ void ConVar_StaticInit(void)
|
||||
pylon_showdebuginfo = ConVar::StaticCreate("pylon_showdebuginfo" , "0" , FCVAR_RELEASE, "Shows debug output for pylon.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
//-------------------------------------------------------------------------
|
||||
// RTECH API |
|
||||
rtech_debug = ConVar::StaticCreate("rtech_debug", "0", FCVAR_DEVELOPMENTONLY, "Shows debug output for the RTech system.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
async_debug_level = ConVar::StaticCreate("async_debug_level" , "0", FCVAR_DEVELOPMENTONLY, "The debug level for async reads.", false, 0.f, false, 0.f, nullptr, "0 = disabled");
|
||||
async_debug_close = ConVar::StaticCreate("async_debug_close" , "0", FCVAR_DEVELOPMENTONLY, "Debug async file closing.", false, 0.f, false, 0.f, nullptr, "0 = disabled");
|
||||
|
||||
pak_debugrelations = ConVar::StaticCreate("pak_debugrelations" , "0", FCVAR_DEVELOPMENTONLY, "Debug RPAK asset dependency resolving.", false, 0.f, false, 0.f, nullptr, nullptr);
|
||||
//-------------------------------------------------------------------------
|
||||
// RUI |
|
||||
#ifndef DEDICATED
|
||||
@ -765,8 +770,8 @@ void ConCommand_StaticInit(void)
|
||||
ConCommand::StaticCreate("fs_vpk_unpack", "Unpack all files from a VPK file.", nullptr, FCVAR_DEVELOPMENTONLY, VPK_Unpack_f, nullptr);
|
||||
//-------------------------------------------------------------------------
|
||||
// RTECH API |
|
||||
ConCommand::StaticCreate("rtech_strtoguid", "Calculates the GUID from input data.", nullptr, FCVAR_DEVELOPMENTONLY, RTech_StringToGUID_f, nullptr);
|
||||
ConCommand::StaticCreate("pak_decompress", "Decompresses specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, RTech_Decompress_f, RTech_PakDecompress_f_CompletionFunc);
|
||||
ConCommand::StaticCreate("pak_strtoguid", "Calculates the GUID from input data.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_StringToGUID_f, nullptr);
|
||||
ConCommand::StaticCreate("pak_decompress", "Decompresses specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_Decompress_f, RTech_PakDecompress_f_CompletionFunc);
|
||||
ConCommand::StaticCreate("pak_requestload", "Requests asynchronous load for specified RPAK file.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_RequestLoad_f, RTech_PakLoad_f_CompletionFunc);
|
||||
ConCommand::StaticCreate("pak_requestunload", "Requests unload for specified RPAK file or ID.", nullptr, FCVAR_DEVELOPMENTONLY, Pak_RequestUnload_f, RTech_PakUnload_f_CompletionFunc);
|
||||
ConCommand::StaticCreate("pak_swap", "Requests swap for specified RPAK file or ID", nullptr, FCVAR_DEVELOPMENTONLY, Pak_Swap_f, nullptr);
|
||||
|
@ -280,7 +280,9 @@ extern ConVar* curl_timeout;
|
||||
extern ConVar* curl_debug;
|
||||
//-------------------------------------------------------------------------
|
||||
// RTECH API |
|
||||
extern ConVar* rtech_debug;
|
||||
extern ConVar* async_debug_level;
|
||||
extern ConVar* async_debug_close;
|
||||
extern ConVar* pak_debugrelations;
|
||||
//-------------------------------------------------------------------------
|
||||
// RUI |
|
||||
#ifndef DEDICATED
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "game/server/ai_networkmanager.h"
|
||||
#include "game/server/detour_impl.h"
|
||||
#endif // !CLIENT_DLL
|
||||
#include "rtech/rtech_game.h"
|
||||
//#include "rtech/rui/rui.h"
|
||||
//#include "materialsystem/cmaterialsystem.h"
|
||||
//#include "studiorender/studiorendercontext.h"
|
||||
@ -350,16 +349,4 @@ void RuntimePtc_Init() /* .TEXT */
|
||||
#else
|
||||
CMemory(v_SQVM_CompileError).Offset(0xE0).FindPatternSelf("E8", CMemory::Direction::DOWN, 200).Patch({ 0x90, 0x90, 0x90, 0x90, 0x90 }); // CAL --> NOP | For dedicated we should not perform post-error events such as telemetry / showing 'COM_ExplainDisconnection' UI etc.
|
||||
#endif // !DEDICATED
|
||||
|
||||
const vector<uint8_t> starPakOpenFile = {
|
||||
0x4D, 0x31, 0xC0, // xor, r8, r8
|
||||
0x48, 0x8D, 0x8C, 0x24, 0x90, 0x00, 0x00, 0x00, // lea rcx, [rsp+378h+90h] FileName
|
||||
|
||||
// call RTech::OpenFile [RIP+RVA]
|
||||
0xE8, 0x77, 0x8F, 0xFF, 0xFF,
|
||||
0x8B, 0xF8, // mov edi, eax
|
||||
0xE9, 0xDA, 0x00, 0x00, 0x00 // jmp [RIP+RVA]
|
||||
};
|
||||
|
||||
p_Pak_OpenFileOffset.Patch(starPakOpenFile);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
|
||||
"SV_RCon_Pb"
|
||||
"CL_RCon_Pb"
|
||||
|
||||
"rtech_tools"
|
||||
"rson"
|
||||
"rtech_game"
|
||||
"playlists"
|
||||
"stryder"
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/keyvalues_iface.h"
|
||||
#include "vpc/IAppSystem.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "vpc/interfaces.h"
|
||||
#include "common/callback.h"
|
||||
#include "common/completion.h"
|
||||
@ -60,8 +59,13 @@
|
||||
#include "engine/server/datablock_sender.h"
|
||||
#endif // !CLIENT_DLL
|
||||
#include "studiorender/studiorendercontext.h"
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/rstdlib.h"
|
||||
#include "rtech/rson.h"
|
||||
#include "rtech/async/asyncio.h"
|
||||
#include "rtech/pak/pakalloc.h"
|
||||
#include "rtech/pak/pakparse.h"
|
||||
#include "rtech/pak/pakstate.h"
|
||||
#include "rtech/pak/pakstream.h"
|
||||
#include "rtech/stryder/stryder.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#ifndef DEDICATED
|
||||
@ -550,8 +554,15 @@ void DetourRegister() // Register detour classes to be searched and hooked.
|
||||
#endif // !DEDICATED
|
||||
|
||||
// RTech
|
||||
REGISTER(V_RTechGame);
|
||||
REGISTER(V_RTechUtils);
|
||||
REGISTER(V_ReSTD);
|
||||
|
||||
REGISTER(V_AsyncIO);
|
||||
|
||||
REGISTER(V_PakAlloc);
|
||||
REGISTER(V_PakParse);
|
||||
REGISTER(V_PakState);
|
||||
REGISTER(V_PakStream);
|
||||
|
||||
REGISTER(VStryder);
|
||||
REGISTER(VPlaylists);
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "datacache/mdlcache.h"
|
||||
#include "datacache/imdlcache.h"
|
||||
#include "datacache/idatacache.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/pak/paktools.h"
|
||||
#include "public/studio.h"
|
||||
|
||||
CStudioFallbackHandler g_StudioMdlFallbackHandler;
|
||||
@ -153,7 +153,7 @@ studiohdr_t* CMDLCache::FindUncachedMDL(CMDLCache* const cache, const MDLHandle_
|
||||
}
|
||||
|
||||
pStudioData->processing = true;
|
||||
g_pRTech->StringToGuid(modelName);
|
||||
Pak_StringToGuid(modelName);
|
||||
pStudioData->processing = false;
|
||||
|
||||
studiomodelcache_t* const modelCache = pStudioData->GetModelCache();
|
||||
|
@ -18,7 +18,8 @@ public:
|
||||
, m_hFallbackMDL(NULL)
|
||||
{}
|
||||
|
||||
// This must be cleared if 'common.rpak' is getting unloaded!
|
||||
// This must be cleared if 'common.rpak' is getting unloaded, as this pak
|
||||
// contains the default fallback models!!!
|
||||
inline void Clear(void)
|
||||
{
|
||||
m_pFallbackHDR = nullptr;
|
||||
|
@ -8,12 +8,17 @@
|
||||
#include "core/stdafx.h"
|
||||
#include "tier0/memstd.h"
|
||||
#include "tier0/jobthread.h"
|
||||
#include "tier1/fmtstr.h"
|
||||
#include "tier2/fileutils.h"
|
||||
#include "engine/sys_dll2.h"
|
||||
#include "engine/host_cmd.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/rtech_game.h"
|
||||
|
||||
#include "rtech/pak/pakstate.h"
|
||||
#include "rtech/pak/pakparse.h"
|
||||
#include "rtech/pak/paktools.h"
|
||||
#include "rtech/pak/pakstream.h"
|
||||
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "datacache/mdlcache.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
@ -22,23 +27,91 @@
|
||||
#endif // !DEDICATED
|
||||
|
||||
CUtlVector<CUtlString> g_InstalledMaps;
|
||||
string s_LevelName;
|
||||
CFmtStrN<MAX_MAP_NAME> s_CurrentLevelName;
|
||||
|
||||
std::regex s_ArchiveRegex{ R"([^_]*_(.*)(.bsp.pak000_dir).*)" };
|
||||
static std::regex s_ArchiveRegex{ R"([^_]*_(.*)(.bsp.pak000_dir).*)" };
|
||||
|
||||
bool s_bLevelResourceInitialized = false;
|
||||
bool s_bBasePaksInitialized = false;
|
||||
KeyValues* s_pLevelSetKV = nullptr;
|
||||
static CustomPakData_t s_customPakData;
|
||||
static KeyValues* s_pLevelSetKV = nullptr;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: load a custom pak and add it to the list
|
||||
//-----------------------------------------------------------------------------
|
||||
PakHandle_t CustomPakData_t::LoadAndAddPak(const char* const pakFile)
|
||||
{
|
||||
if (numHandles >= MAX_CUSTOM_PAKS)
|
||||
{
|
||||
Error(eDLL_T::ENGINE, NO_ERROR, "Tried to load pak '%s', but already reached the SDK's limit of %d!\n", pakFile, MAX_CUSTOM_PAKS);
|
||||
return INVALID_PAK_HANDLE;
|
||||
}
|
||||
|
||||
const PakHandle_t pakId = g_pakLoadApi->LoadAsync(pakFile, AlignedMemAlloc(), 4, 0);
|
||||
|
||||
// failure, don't add and return the invalid handle.
|
||||
if (pakId == INVALID_PAK_HANDLE)
|
||||
return pakId;
|
||||
|
||||
handles[numHandles++] = pakId;
|
||||
return pakId;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: unloads all active custom pak handles
|
||||
//-----------------------------------------------------------------------------
|
||||
void CustomPakData_t::UnloadAndRemoveAll()
|
||||
{
|
||||
for (; numHandles-1 >= CustomPakData_t::PAK_TYPE_COUNT; numHandles--)
|
||||
{
|
||||
const PakHandle_t pakId = handles[numHandles-1];
|
||||
|
||||
if (pakId == INVALID_PAK_HANDLE)
|
||||
{
|
||||
assert(0); // invalid handles should not be inserted
|
||||
return;
|
||||
}
|
||||
|
||||
g_pakLoadApi->UnloadAsync(pakId);
|
||||
handles[numHandles-1] = INVALID_PAK_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: loads the base SDK pak file by type
|
||||
//-----------------------------------------------------------------------------
|
||||
PakHandle_t CustomPakData_t::LoadBasePak(const char* const pakFile, const EPakType type)
|
||||
{
|
||||
const PakHandle_t pakId = g_pakLoadApi->LoadAsync(pakFile, AlignedMemAlloc(), 4, 0);
|
||||
|
||||
// the file is most likely missing
|
||||
assert(pakId != INVALID_PAK_HANDLE);
|
||||
handles[type] = pakId;
|
||||
|
||||
return pakId;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: unload the SDK base pak file by type
|
||||
//-----------------------------------------------------------------------------
|
||||
void CustomPakData_t::UnloadBasePak(const EPakType type)
|
||||
{
|
||||
const PakHandle_t pakId = handles[type];
|
||||
|
||||
// only unload if it was actually successfully loaded
|
||||
if (pakId != INVALID_PAK_HANDLE)
|
||||
{
|
||||
g_pakLoadApi->UnloadAsync(pakId);
|
||||
handles[type] = INVALID_PAK_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: checks if level has changed
|
||||
// Input : *pszLevelName -
|
||||
// Output : true if level name deviates from previous level
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Mod_LevelHasChanged(const char* pszLevelName)
|
||||
bool Mod_LevelHasChanged(const char* const pszLevelName)
|
||||
{
|
||||
return (s_LevelName.compare(pszLevelName) != 0);
|
||||
return (V_strcmp(pszLevelName, s_CurrentLevelName.String()) == NULL);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -85,309 +158,271 @@ void Mod_GetAllInstalledMaps()
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets the queued pak handles
|
||||
// Input : *a1 -
|
||||
// *a2 -
|
||||
// a3 -
|
||||
// Output : __int64
|
||||
//-----------------------------------------------------------------------------
|
||||
__int64 __fastcall Mod_GetQueuedPakHandle(char* a1, char* a2, __int64 a3)
|
||||
{
|
||||
char v3; // al
|
||||
signed int v4; // er11
|
||||
__int64 v5; // r10
|
||||
char* v6; // r9
|
||||
signed __int64 v7; // rdx
|
||||
char v8; // al
|
||||
char* v10; // r8
|
||||
char* v11; // r8
|
||||
|
||||
v3 = *a2;
|
||||
v4 = 0;
|
||||
*a1 = *a2;
|
||||
v5 = 0i64;
|
||||
if (v3)
|
||||
{
|
||||
v6 = a1;
|
||||
v7 = a2 - a1;
|
||||
while (1)
|
||||
{
|
||||
++v5;
|
||||
++v6;
|
||||
if (v5 == a3)
|
||||
break;
|
||||
v8 = v6[v7];
|
||||
*v6 = v8;
|
||||
if (!v8)
|
||||
return v5;
|
||||
}
|
||||
*(v6 - 1) = 0;
|
||||
if (--v5)
|
||||
{
|
||||
v10 = &a1[v5 - 1];
|
||||
if ((*v10 & 0xC0) == 0x80)
|
||||
{
|
||||
do
|
||||
++v4;
|
||||
while ((v10[-v4] & 0xC0) == 0x80);
|
||||
}
|
||||
v11 = &v10[-v4];
|
||||
if (v4 != (signed int)((0xE5000000 >> (((unsigned __int8)*v11 >> 3) & 0x1E)) & 3))
|
||||
{
|
||||
*v11 = 0;
|
||||
v5 -= v4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return v5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: processes queued pak files
|
||||
//-----------------------------------------------------------------------------
|
||||
void Mod_ProcessPakQueue()
|
||||
void Mod_QueuedPakCacheFrame()
|
||||
{
|
||||
char v0; // bl
|
||||
char** v1; // r10
|
||||
__int64 i; // er9
|
||||
char* v3; // rcx
|
||||
signed __int64 v4; // r8
|
||||
int v5; // eax
|
||||
int v6; // edx
|
||||
__int64 v7; // eax
|
||||
__int64 v8; // rbp
|
||||
__int64 v9; // rsi
|
||||
char* v10; // rbx
|
||||
unsigned int v11; // ecx
|
||||
__int64 v12; // rax
|
||||
int v13; // edi
|
||||
char v14; // al
|
||||
char* v15; // rbx
|
||||
__int64 v16; // edi
|
||||
char* v17; // rsi
|
||||
char* v18; // rax
|
||||
int v19; // ecx
|
||||
int v20; // er8
|
||||
int v21; // ecx
|
||||
__int64 v22; // rdx
|
||||
__int64 v24{}; // rdx
|
||||
__int64 v25{}; // rcx
|
||||
|
||||
v0 = 0;
|
||||
#ifndef DEDICATED
|
||||
bool bUnconnected = !(*g_pClientState_Shifted)->IsConnected();
|
||||
#else // !DEDICATED
|
||||
bool bUnconnected = true; // Always true for dedicated.
|
||||
#endif
|
||||
|
||||
if (*(float*)&*dword_14B383420 == 1.0 && *qword_167ED7BB8 && bUnconnected)
|
||||
bool startFromFirst = false;
|
||||
|
||||
if (Pak_StreamingDownloadFinished() && Pak_GetNumStreamableAssets() && bUnconnected)
|
||||
{
|
||||
*byte_16709DDDF = 0;
|
||||
v0 = 1;
|
||||
*g_pPakPrecacheJobFinished = false;
|
||||
startFromFirst = true;
|
||||
}
|
||||
else if (*byte_16709DDDF)
|
||||
else if (*g_pPakPrecacheJobFinished)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (FileSystem()->ResetItemCache() && !*dword_1634F445C)
|
||||
|
||||
if (!FileSystem()->ResetItemCache() || *g_pNumPrecacheItemsMTVTF)
|
||||
{
|
||||
v1 = &*off_141874660;
|
||||
for (i = 0; i < 5; ++i)
|
||||
return;
|
||||
}
|
||||
|
||||
const char** pPakName = &g_commonPakData[0].basePakName;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 5; ++i)
|
||||
{
|
||||
if (*((_BYTE*)pPakName - 268))
|
||||
break;
|
||||
|
||||
const char* pakName = g_commonPakData[i].pakName;
|
||||
const int64_t v4 = *pPakName - pakName;
|
||||
|
||||
int v5;
|
||||
int v6;
|
||||
|
||||
do
|
||||
{
|
||||
if (*((_BYTE*)v1 - 268))
|
||||
break;
|
||||
v3 = (char*)&*unk_141874555 + 280 * i;
|
||||
v4 = *v1 - v3;
|
||||
do
|
||||
{
|
||||
v5 = (unsigned __int8)v3[v4];
|
||||
v6 = (unsigned __int8)*v3 - v5;
|
||||
if (v6)
|
||||
break;
|
||||
++v3;
|
||||
} while (v5);
|
||||
v5 = (unsigned __int8)pakName[v4];
|
||||
v6 = (unsigned __int8)*pakName - v5;
|
||||
if (v6)
|
||||
break;
|
||||
v1 += 35;
|
||||
}
|
||||
v7 = 0;
|
||||
if (!v0)
|
||||
v7 = i;
|
||||
v8 = v7;
|
||||
if (v7 <= 4i64)
|
||||
{
|
||||
v9 = 4i64;
|
||||
v10 = (char*)&*unk_1418749B0;
|
||||
do
|
||||
{
|
||||
if (v10[5])
|
||||
{
|
||||
v11 = *(_DWORD*)v10;
|
||||
v12 = *(_DWORD*)v10 & 0x1FF;
|
||||
v10[4] = 1;
|
||||
if (*((_DWORD*)&*g_pLoadedPakInfo + 46 * v12) == v11)
|
||||
{
|
||||
v13 = *((_DWORD*)&*g_pLoadedPakInfo + 46 * v12 + 1);
|
||||
v14 = v10[4];
|
||||
}
|
||||
else
|
||||
{
|
||||
v13 = 14;
|
||||
v14 = 1;
|
||||
}
|
||||
if (!v14 || v13 == 9)
|
||||
{
|
||||
// SDK pak files must be unloaded before the engine pak files,
|
||||
// as we reference assets within engine pak files.
|
||||
const PakLoadedInfo_t* pLoadedPakInfo = g_pRTech->GetPakLoadedInfo(*(PakHandle_t*)v10);
|
||||
if (pLoadedPakInfo)
|
||||
{
|
||||
const char* pszLoadedPakName = pLoadedPakInfo->m_fileName;
|
||||
|
||||
if (strcmp(pszLoadedPakName, "common.rpak") == 0)
|
||||
{
|
||||
g_StudioMdlFallbackHandler.Clear();
|
||||
}
|
||||
else if (strcmp(pszLoadedPakName, "common_mp.rpak") == 0 ||
|
||||
strcmp(pszLoadedPakName, "common_sp.rpak") == 0 ||
|
||||
strcmp(pszLoadedPakName, "common_pve.rpak") == 0)
|
||||
{
|
||||
const PakLoadedInfo_t* pLoadedSdkPak = g_pRTech->GetPakLoadedInfo("common_sdk.rpak");
|
||||
++pakName;
|
||||
} while (v5);
|
||||
|
||||
if (pLoadedSdkPak) // Only unload if sdk pak file is loaded.
|
||||
g_pakLoadApi->UnloadPak(pLoadedSdkPak->m_handle);
|
||||
if (v6)
|
||||
break;
|
||||
|
||||
}
|
||||
#ifndef DEDICATED
|
||||
else if (strcmp(pszLoadedPakName, "ui_mp.rpak") == 0)
|
||||
{
|
||||
const PakLoadedInfo_t* pLoadedSdkPak = g_pRTech->GetPakLoadedInfo("ui_sdk.rpak");
|
||||
|
||||
if (pLoadedSdkPak) // Only unload if sdk pak file is loaded.
|
||||
g_pakLoadApi->UnloadPak(pLoadedSdkPak->m_handle);
|
||||
}
|
||||
#endif // !DEDICATED
|
||||
}
|
||||
|
||||
// The old gather props is set if a model couldn't be
|
||||
// loaded properly. If we unload level assets, we just
|
||||
// enable the new implementation again and re-evaluate
|
||||
// on the next level load. If we load a missing/bad
|
||||
// model again, we toggle the old implementation as
|
||||
// otherwise the fallback models won't render; the new
|
||||
// gather props solution does not attempt to obtain
|
||||
// studio hardware data on bad mdl handles. See
|
||||
// 'CMDLCache::GetErrorModel' for more information.
|
||||
g_StudioMdlFallbackHandler.DisableLegacyGatherProps();
|
||||
|
||||
g_pakLoadApi->UnloadPak(*(PakHandle_t*)v10);
|
||||
Mod_UnloadPakFile(); // Unload mod pak files.
|
||||
|
||||
if (s_pLevelSetKV)
|
||||
{
|
||||
// Delete current level settings if we drop all paks..
|
||||
s_pLevelSetKV->DeleteThis();
|
||||
s_pLevelSetKV = nullptr;
|
||||
}
|
||||
}
|
||||
if (v13 && (unsigned int)(v13 - 13) > 1)
|
||||
return;
|
||||
*((_WORD*)v10 + 2) = 0;
|
||||
*(_DWORD*)v10 = 0xFFFFFFFF;
|
||||
}
|
||||
--v9;
|
||||
v10 -= 280;
|
||||
} while (v9 >= v8);
|
||||
}
|
||||
*byte_16709DDDF = 1;
|
||||
v15 = (char*)&*unk_141874550;
|
||||
v16 = 0;
|
||||
while (1)
|
||||
{
|
||||
v17 = (char*)&*unk_141874550 + 280 * v16 + 5;
|
||||
v18 = v17;
|
||||
do
|
||||
{
|
||||
v19 = (unsigned __int8)v18[*((_QWORD*)v15 + 34) - (_QWORD)v17];
|
||||
v20 = (unsigned __int8)*v18 - v19;
|
||||
if (v20)
|
||||
break;
|
||||
++v18;
|
||||
} while (v19);
|
||||
if (!v20)
|
||||
goto LABEL_37;
|
||||
Mod_GetQueuedPakHandle(v17, *((char**)v15 + 34), 260i64);
|
||||
if (v15[5])
|
||||
break;
|
||||
*(_DWORD*)v15 = 0xFFFFFFFF;
|
||||
LABEL_40:
|
||||
++v16;
|
||||
v15 += 280;
|
||||
if (v16 >= 5)
|
||||
{
|
||||
if (*byte_16709DDDF)
|
||||
{
|
||||
if (*g_pMTVFTaskItem)
|
||||
{
|
||||
if (!*(_BYTE*)(*g_pMTVFTaskItem + 4))
|
||||
{
|
||||
if (*qword_167ED7BC0 || WORD2(*g_pPakLoadJobID) != HIWORD(*g_pPakLoadJobID))
|
||||
{
|
||||
if (!JT_AcquireFifoLock(g_pPakFifoLock)
|
||||
&& !(unsigned __int8)sub_14045BAC0((__int64(__fastcall*)(__int64, _DWORD*, __int64, _QWORD*))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64))
|
||||
{
|
||||
sub_14045A1D0((unsigned __int8(__fastcall*)(_QWORD))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64, 0i64, 1);
|
||||
}
|
||||
|
||||
sub_140441220(v25, v24);
|
||||
if (ThreadInMainThread())
|
||||
{
|
||||
if (*g_bPakFifoLockAcquired)
|
||||
{
|
||||
*g_bPakFifoLockAcquired = 0;
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
}
|
||||
}
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
}
|
||||
FileSystem()->ResetItemCacheSize(256);
|
||||
FileSystem()->PrecacheTaskItem(*g_pMTVFTaskItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (strcmp(v17, "mp_lobby.rpak") == 0)
|
||||
s_bBasePaksInitialized = true;
|
||||
|
||||
if (s_bBasePaksInitialized && !s_bLevelResourceInitialized)
|
||||
{
|
||||
Mod_PreloadLevelPaks(s_LevelName.c_str());
|
||||
s_bLevelResourceInitialized = true;
|
||||
}
|
||||
*(_DWORD*)v15 = g_pakLoadApi->LoadAsync(v17, AlignedMemAlloc(), 4, 0);
|
||||
|
||||
if (strcmp(v17, "common_mp.rpak") == 0 || strcmp(v17, "common_sp.rpak") == 0 || strcmp(v17, "common_pve.rpak") == 0)
|
||||
g_pakLoadApi->LoadAsync("common_sdk.rpak", AlignedMemAlloc(), 4, 0);
|
||||
#ifndef DEDICATED
|
||||
if (strcmp(v17, "ui_mp.rpak") == 0)
|
||||
g_pakLoadApi->LoadAsync("ui_sdk.rpak", AlignedMemAlloc(), 4, 0);
|
||||
#endif // !DEDICATED
|
||||
|
||||
LABEL_37:
|
||||
v21 = *(_DWORD*)v15;
|
||||
if (*(_DWORD*)v15 != INVALID_PAK_HANDLE)
|
||||
{
|
||||
v22 = 184i64 * (v21 & 0x1FF);
|
||||
if (*(_DWORD*)((char*)&*g_pLoadedPakInfo + v22) != _DWORD(v21) || ((*(_DWORD*)((char*)&*g_pLoadedPakInfo + v22 + 4) - 9) & 0xFFFFFFFB) != 0)
|
||||
{
|
||||
*byte_16709DDDF = 0; return;
|
||||
}
|
||||
}
|
||||
goto LABEL_40;
|
||||
pPakName += 35;
|
||||
}
|
||||
|
||||
int startIndex = 0;
|
||||
|
||||
if (!startFromFirst)
|
||||
startIndex = i; // start from last pre-cached
|
||||
|
||||
const int numToProcess = startIndex;
|
||||
|
||||
if (startIndex <= 4)
|
||||
{
|
||||
int numLeftToProcess = 4;
|
||||
CommonPakData_t* data = &g_commonPakData[4];
|
||||
|
||||
do
|
||||
{
|
||||
if (*data->pakName)
|
||||
{
|
||||
const int index = data->pakId & PAK_MAX_HANDLES_MASK;
|
||||
EPakStatus status;
|
||||
|
||||
bool keepLoaded = true;
|
||||
data->keepLoaded = true;
|
||||
|
||||
if (g_pLoadedPakInfo[index].handle == data->pakId)
|
||||
{
|
||||
status = g_pLoadedPakInfo[index].status;
|
||||
keepLoaded = data->keepLoaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = PAK_STATUS_INVALID_PAKHANDLE;
|
||||
keepLoaded = true;
|
||||
}
|
||||
|
||||
if (!keepLoaded || status == PAK_STATUS_LOADED)
|
||||
{
|
||||
// SDK pak files must be unloaded before the engine pak files,
|
||||
// as we use assets within engine pak files.
|
||||
switch (numLeftToProcess)
|
||||
{
|
||||
#ifndef DEDICATED
|
||||
case CommonPakData_t::PAK_TYPE_UI_GM:
|
||||
s_customPakData.UnloadBasePak(CustomPakData_t::PAK_TYPE_UI_SDK);
|
||||
break;
|
||||
#endif // !DEDICATED
|
||||
|
||||
case CommonPakData_t::PAK_TYPE_COMMON:
|
||||
g_StudioMdlFallbackHandler.Clear();
|
||||
break;
|
||||
|
||||
case CommonPakData_t::PAK_TYPE_COMMON_GM:
|
||||
s_customPakData.UnloadBasePak(CustomPakData_t::PAK_TYPE_COMMON_SDK);
|
||||
break;
|
||||
|
||||
case CommonPakData_t::PAK_TYPE_LOBBY:
|
||||
s_customPakData.basePaksLoaded = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// The old gather props is set if a model couldn't be
|
||||
// loaded properly. If we unload level assets, we just
|
||||
// enable the new implementation again and re-evaluate
|
||||
// on the next level load. If we load a missing/bad
|
||||
// model again, we toggle the old implementation as
|
||||
// otherwise the fallback models won't render; the new
|
||||
// gather props solution does not attempt to obtain
|
||||
// studio hardware data on bad mdl handles. See
|
||||
// 'GatherStaticPropsSecondPass_PreInit()' for details.
|
||||
g_StudioMdlFallbackHandler.DisableLegacyGatherProps();
|
||||
|
||||
g_pakLoadApi->UnloadAsync(data->pakId);
|
||||
|
||||
Mod_UnloadPakFile(); // Unload mod pak files.
|
||||
|
||||
if (s_pLevelSetKV)
|
||||
{
|
||||
// Delete current level settings if we drop all paks..
|
||||
s_pLevelSetKV->DeleteThis();
|
||||
s_pLevelSetKV = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (status && (unsigned int)(status - 13) > 1)
|
||||
return;
|
||||
|
||||
data->keepLoaded = false;
|
||||
data->pakName[0] = '\0';
|
||||
|
||||
data->pakId = INVALID_PAK_HANDLE;
|
||||
}
|
||||
--numLeftToProcess;
|
||||
--data;
|
||||
} while (numLeftToProcess >= numToProcess);
|
||||
}
|
||||
|
||||
*g_pPakPrecacheJobFinished = true;
|
||||
CommonPakData_t* commonData = g_commonPakData;
|
||||
|
||||
int it = 0;
|
||||
|
||||
char* name;
|
||||
char* nameIt;
|
||||
|
||||
while (true)
|
||||
{
|
||||
name = g_commonPakData[it].pakName;
|
||||
nameIt = name;
|
||||
char c;
|
||||
int v20;
|
||||
do
|
||||
{
|
||||
c = (unsigned __int8)nameIt[(unsigned __int64)(commonData->basePakName - (const char*)name)];
|
||||
v20 = (unsigned __int8)*nameIt - c;
|
||||
if (v20)
|
||||
break;
|
||||
|
||||
++nameIt;
|
||||
} while (c);
|
||||
|
||||
if (!v20)
|
||||
goto CHECK_FOR_FAILURE;
|
||||
|
||||
V_strncpy(name, commonData->basePakName, MAX_PATH);
|
||||
|
||||
if (*commonData->pakName)
|
||||
break;
|
||||
|
||||
commonData->pakId = INVALID_PAK_HANDLE;
|
||||
LOOP_AGAIN_OR_FINISH:
|
||||
|
||||
++it;
|
||||
++commonData;
|
||||
if (it >= 5)
|
||||
{
|
||||
if (*g_pPakPrecacheJobFinished)
|
||||
{
|
||||
__int64 pMTVFTaskItem = *g_pMTVFTaskItem;
|
||||
if (pMTVFTaskItem)
|
||||
{
|
||||
if (!*(_BYTE*)(pMTVFTaskItem + 4))
|
||||
{
|
||||
if (*g_pPakHasPendingUnloadJobs || *g_pLoadedPakCount != *g_pRequestedPakCount)
|
||||
{
|
||||
if (!JT_AcquireFifoLockOrHelp(g_pPakFifoLock)
|
||||
&& !JT_HelpWithJobTypes((__int64(__fastcall*)(__int64, _DWORD*, __int64, _QWORD*))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64))
|
||||
{
|
||||
JT_HelpWithJobTypesOrSleep((unsigned __int8(__fastcall*)(_QWORD))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64, 0i64, 1);
|
||||
}
|
||||
|
||||
Mod_UnloadPendingAndPrecacheRequestedPaks();
|
||||
|
||||
if (ThreadInMainThread())
|
||||
{
|
||||
if (*g_bPakFifoLockAcquired)
|
||||
{
|
||||
*g_bPakFifoLockAcquired = 0;
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
}
|
||||
}
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
|
||||
pMTVFTaskItem = *g_pMTVFTaskItem;
|
||||
}
|
||||
|
||||
FileSystem()->ResetItemCacheSize(256);
|
||||
FileSystem()->PrecacheTaskItem(pMTVFTaskItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (it == CommonPakData_t::PAK_TYPE_LOBBY)
|
||||
s_customPakData.basePaksLoaded = true;
|
||||
|
||||
if (s_customPakData.basePaksLoaded && !s_customPakData.levelResourcesLoaded)
|
||||
{
|
||||
Mod_PreloadLevelPaks(s_CurrentLevelName.String());
|
||||
s_customPakData.levelResourcesLoaded = true;
|
||||
}
|
||||
|
||||
commonData->pakId = g_pakLoadApi->LoadAsync(name, AlignedMemAlloc(), 4, 0);
|
||||
|
||||
#ifndef DEDICATED
|
||||
if (it == CommonPakData_t::PAK_TYPE_UI_GM)
|
||||
s_customPakData.LoadBasePak("ui_sdk.rpak", CustomPakData_t::PAK_TYPE_UI_SDK);
|
||||
#endif // !DEDICATED
|
||||
if (it == CommonPakData_t::PAK_TYPE_COMMON_GM)
|
||||
s_customPakData.LoadBasePak("common_sdk.rpak", CustomPakData_t::PAK_TYPE_COMMON_SDK);
|
||||
|
||||
CHECK_FOR_FAILURE:
|
||||
|
||||
if (commonData->pakId != INVALID_PAK_HANDLE)
|
||||
{
|
||||
const int infoIndex = (commonData->pakId & PAK_MAX_HANDLES_MASK);
|
||||
|
||||
if (g_pLoadedPakInfo[infoIndex].handle != commonData->pakId || ((g_pLoadedPakInfo[infoIndex].status - 9) & 0xFFFFFFFB) != 0)
|
||||
{
|
||||
*g_pPakPrecacheJobFinished = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
goto LOOP_AGAIN_OR_FINISH;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -395,12 +430,12 @@ void Mod_ProcessPakQueue()
|
||||
// Input : *szLevelName -
|
||||
// Output : true on success, false on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
void Mod_LoadPakForMap(const char* pszLevelName)
|
||||
void Mod_LoadPakForMap(const char* const pszLevelName)
|
||||
{
|
||||
if (Mod_LevelHasChanged(pszLevelName))
|
||||
s_bLevelResourceInitialized = false;
|
||||
s_customPakData.levelResourcesLoaded = false;
|
||||
|
||||
s_LevelName = pszLevelName;
|
||||
s_CurrentLevelName = pszLevelName;
|
||||
|
||||
// Dedicated should not load loadscreens.
|
||||
#ifndef DEDICATED
|
||||
@ -413,11 +448,12 @@ void Mod_LoadPakForMap(const char* pszLevelName)
|
||||
// Input : *pszLevelName -
|
||||
// Output : KeyValues*
|
||||
//-----------------------------------------------------------------------------
|
||||
KeyValues* Mod_GetLevelSettings(const char* pszLevelName)
|
||||
KeyValues* Mod_GetLevelSettings(const char* const pszLevelName)
|
||||
{
|
||||
if (s_pLevelSetKV)
|
||||
{
|
||||
if (s_bLevelResourceInitialized)
|
||||
// If we didn't change the level, return the current one
|
||||
if (s_customPakData.levelResourcesLoaded)
|
||||
return s_pLevelSetKV;
|
||||
|
||||
s_pLevelSetKV->DeleteThis();
|
||||
@ -434,14 +470,14 @@ KeyValues* Mod_GetLevelSettings(const char* pszLevelName)
|
||||
// Purpose: loads required pakfile assets for specified BSP level
|
||||
// Input : &svSetFile -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Mod_PreloadLevelPaks(const char* pszLevelName)
|
||||
void Mod_PreloadLevelPaks(const char* const pszLevelName)
|
||||
{
|
||||
KeyValues* pSettingsKV = Mod_GetLevelSettings(pszLevelName);
|
||||
KeyValues* const pSettingsKV = Mod_GetLevelSettings(pszLevelName);
|
||||
|
||||
if (!pSettingsKV)
|
||||
return;
|
||||
|
||||
KeyValues* pPakListKV = pSettingsKV->FindKey("PakList");
|
||||
KeyValues* const pPakListKV = pSettingsKV->FindKey("PakList");
|
||||
|
||||
if (!pPakListKV)
|
||||
return;
|
||||
@ -454,12 +490,10 @@ void Mod_PreloadLevelPaks(const char* pszLevelName)
|
||||
continue;
|
||||
|
||||
snprintf(szPathBuffer, sizeof(szPathBuffer), "%s.rpak", pSubKey->GetName());
|
||||
PakHandle_t nPakId = g_pakLoadApi->LoadAsync(szPathBuffer, AlignedMemAlloc(), 4, 0);
|
||||
const PakHandle_t nPakId = s_customPakData.LoadAndAddPak(szPathBuffer);
|
||||
|
||||
if (nPakId == INVALID_PAK_HANDLE)
|
||||
Error(eDLL_T::ENGINE, NO_ERROR, "%s: unable to load pak '%s' results '%d'\n", __FUNCTION__, szPathBuffer, nPakId);
|
||||
else
|
||||
g_vLoadedPakHandle.AddToTail(nPakId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,14 +502,7 @@ void Mod_PreloadLevelPaks(const char* pszLevelName)
|
||||
//-----------------------------------------------------------------------------
|
||||
void Mod_UnloadPakFile(void)
|
||||
{
|
||||
for (const PakHandle_t& it : g_vLoadedPakHandle)
|
||||
{
|
||||
if (it >= 0)
|
||||
{
|
||||
g_pakLoadApi->UnloadPak(it);
|
||||
}
|
||||
}
|
||||
g_vLoadedPakHandle.Purge();
|
||||
s_customPakData.UnloadAndRemoveAll();
|
||||
|
||||
g_StudioMdlFallbackHandler.ClearBadModelHandleCache();
|
||||
g_StudioMdlFallbackHandler.ClearSuppresionList();
|
||||
@ -484,5 +511,5 @@ void Mod_UnloadPakFile(void)
|
||||
void VModel_BSP::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&v_Mod_LoadPakForMap, &Mod_LoadPakForMap, bAttach);
|
||||
DetourSetup(&v_Mod_ProcessPakQueue, &Mod_ProcessPakQueue, bAttach);
|
||||
DetourSetup(&v_Mod_QueuedPakCacheFrame, &Mod_QueuedPakCacheFrame, bAttach);
|
||||
}
|
||||
|
@ -1,29 +1,133 @@
|
||||
#pragma once
|
||||
#include "tier0/jobthread.h"
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
class KeyValues;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// this structure contains handles and names to the base pak files the engine
|
||||
// loads for a level, this is used for load/unload management during level
|
||||
// changes or engine shutdown
|
||||
//-----------------------------------------------------------------------------
|
||||
struct CommonPakData_t
|
||||
{
|
||||
enum EPakType
|
||||
{
|
||||
// the UI pak assigned to the current gamemode (range in GameMode_t)
|
||||
PAK_TYPE_UI_GM = 0,
|
||||
PAK_TYPE_COMMON,
|
||||
|
||||
// the base pak assigned to the current gamemode (range in GameMode_t)
|
||||
PAK_TYPE_COMMON_GM,
|
||||
PAK_TYPE_LOBBY,
|
||||
|
||||
// NOTE: this one is assigned to the name of the level, the prior ones are
|
||||
// all static!
|
||||
PAK_TYPE_LEVEL,
|
||||
|
||||
// the total number of pak files to watch and manage
|
||||
PAK_TYPE_COUNT
|
||||
};
|
||||
|
||||
CommonPakData_t()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
pakId = INVALID_PAK_HANDLE;
|
||||
keepLoaded = false;
|
||||
basePakName = nullptr;
|
||||
|
||||
memset(pakName, '\0', sizeof(pakName));
|
||||
}
|
||||
|
||||
PakHandle_t pakId;
|
||||
bool keepLoaded;
|
||||
|
||||
// the pak name that's being requested to be loaded for this particular slot
|
||||
char pakName[MAX_PATH];
|
||||
|
||||
// the actual base pak name, like "common_pve.rpak" as set when this array is
|
||||
// being initialized
|
||||
const char* basePakName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// this structure contains handles and names to the custom pak files that are
|
||||
// loaded with the settings KV for that level, these paks are loaded after the
|
||||
// common paks are loaded, but unloaded before the common paks are unloaded
|
||||
//-----------------------------------------------------------------------------
|
||||
struct CustomPakData_t
|
||||
{
|
||||
enum EPakType
|
||||
{
|
||||
// the pak that loads after CommonPakData_t::PAK_TYPE_UI_GM has loaded, and
|
||||
// unloads before CommonPakData_t::PAK_TYPE_UI_GM gets unloaded
|
||||
PAK_TYPE_UI_SDK = 0,
|
||||
|
||||
// the pak that loads after CommonPakData_t::PAK_TYPE_COMMON_GM has loaded,
|
||||
// and unloads before CommonPakData_t::PAK_TYPE_COMMON_GM gets unloaded
|
||||
PAK_TYPE_COMMON_SDK,
|
||||
|
||||
// the total number of base SDK pak files
|
||||
PAK_TYPE_COUNT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
// the absolute max number of custom paks, note that the engine's limit
|
||||
// could still be reached before this number as game scripts and other
|
||||
// code still loads paks such as gladiator cards or load screens
|
||||
MAX_CUSTOM_PAKS = (PAK_MAX_HANDLES - CommonPakData_t::PAK_TYPE_COUNT)
|
||||
};
|
||||
|
||||
CustomPakData_t()
|
||||
{
|
||||
for (size_t i = 0; i < V_ARRAYSIZE(handles); i++)
|
||||
{
|
||||
handles[i] = INVALID_PAK_HANDLE;
|
||||
}
|
||||
|
||||
// the first # handles are reserved for base SDK paks
|
||||
numHandles = PAK_TYPE_COUNT;
|
||||
|
||||
levelResourcesLoaded = false;
|
||||
basePaksLoaded = false;
|
||||
}
|
||||
|
||||
PakHandle_t LoadAndAddPak(const char* const pakFile);
|
||||
void UnloadAndRemoveAll();
|
||||
|
||||
PakHandle_t LoadBasePak(const char* const pakFile, const EPakType type);
|
||||
void UnloadBasePak(const EPakType type);
|
||||
|
||||
// Pak handles that have been loaded with the level
|
||||
// from within the level settings KV (located in
|
||||
// scripts/levels/settings/*.kv). On level unload,
|
||||
// each pak listed in this vector gets unloaded.
|
||||
PakHandle_t handles[MAX_CUSTOM_PAKS];
|
||||
size_t numHandles;
|
||||
|
||||
bool levelResourcesLoaded;
|
||||
bool basePaksLoaded;
|
||||
};
|
||||
|
||||
// array size = CommonPakData_t::PAK_TYPE_COUNT
|
||||
inline CommonPakData_t* g_commonPakData;
|
||||
|
||||
inline void(*v_Mod_LoadPakForMap)(const char* szLevelName);
|
||||
inline void(*v_Mod_ProcessPakQueue)(void);
|
||||
inline void(*v_Mod_QueuedPakCacheFrame)(void);
|
||||
|
||||
inline float* dword_14B383420;
|
||||
inline int32_t * dword_1634F445C;
|
||||
inline void** qword_167ED7BB8;
|
||||
inline bool* byte_16709DDDF;
|
||||
inline char** off_141874660;
|
||||
inline void** unk_141874555;
|
||||
inline void** unk_1418749B0;
|
||||
inline void** unk_141874550;
|
||||
inline int64_t* qword_167ED7BC0;
|
||||
inline int32_t * g_pNumPrecacheItemsMTVTF;
|
||||
inline bool* g_pPakPrecacheJobFinished;
|
||||
|
||||
inline __int64(*sub_14045BAC0)(__int64(__fastcall* a1)(__int64, _DWORD*, __int64, _QWORD*), JobFifoLock_s* pFifoLock, __int64 a3, __int64 a4);
|
||||
inline __int64(*sub_14045A1D0)(unsigned __int8(__fastcall* a1)(_QWORD), JobFifoLock_s* pFifoLock, __int64 a3, __int64 a4, volatile signed __int64* a5, char a6);
|
||||
inline void(*sub_140441220)(__int64 a1, __int64 a2);
|
||||
inline void(*Mod_UnloadPendingAndPrecacheRequestedPaks)(void);
|
||||
|
||||
extern bool s_bBasePaksInitialized;
|
||||
extern CUtlVector<CUtlString> g_InstalledMaps;
|
||||
extern std::mutex g_InstalledMapsMutex;
|
||||
|
||||
@ -40,40 +144,27 @@ class VModel_BSP : public IDetour
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("Mod_LoadPakForMap", v_Mod_LoadPakForMap);
|
||||
LogFunAdr("Mod_ProcessPakQueue", v_Mod_ProcessPakQueue);
|
||||
LogFunAdr("sub_14045BAC0", sub_14045BAC0);
|
||||
LogFunAdr("sub_14045A1D0", sub_14045A1D0);
|
||||
LogFunAdr("sub_140441220", sub_140441220);
|
||||
LogVarAdr("dword_14B383420", dword_14B383420);
|
||||
LogVarAdr("dword_1634F445C", dword_1634F445C);
|
||||
LogVarAdr("qword_167ED7BB8", qword_167ED7BB8);
|
||||
LogVarAdr("byte_16709DDDF", byte_16709DDDF);
|
||||
LogVarAdr("off_141874660", off_141874660);
|
||||
LogVarAdr("unk_141874555", unk_141874555);
|
||||
LogVarAdr("unk_1418749B0", unk_1418749B0);
|
||||
LogVarAdr("unk_141874550", unk_141874550);
|
||||
LogVarAdr("qword_167ED7BC0", qword_167ED7BC0);
|
||||
LogFunAdr("Mod_QueuedPakCacheFrame", v_Mod_QueuedPakCacheFrame);
|
||||
|
||||
LogFunAdr("Mod_UnloadPendingAndPrecacheRequestedPaks", Mod_UnloadPendingAndPrecacheRequestedPaks);
|
||||
|
||||
LogVarAdr("g_numPrecacheItemsMTVTF", g_pNumPrecacheItemsMTVTF);
|
||||
LogVarAdr("g_pakPrecacheJobFinished", g_pPakPrecacheJobFinished);
|
||||
|
||||
LogVarAdr("g_commonPakData", g_commonPakData);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 81 EC ?? ?? ?? ?? 0F B6 05 ?? ?? ?? ?? 4C 8D 05 ?? ?? ?? ?? 84 C0").GetPtr(v_Mod_LoadPakForMap);
|
||||
g_GameDll.FindPatternSIMD("40 53 48 83 EC ?? F3 0F 10 05 ?? ?? ?? ?? 32 DB").GetPtr(v_Mod_ProcessPakQueue);
|
||||
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 4C 89 44 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 60").GetPtr(sub_14045BAC0);
|
||||
g_GameDll.FindPatternSIMD("4C 89 4C 24 ?? 4C 89 44 24 ?? 48 89 54 24 ?? 48 89 4C 24 ?? 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(sub_14045A1D0);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 33 ED 48 8D 35 ?? ?? ?? ?? 48 39 2D ?? ?? ?? ??").GetPtr(sub_140441220);
|
||||
g_GameDll.FindPatternSIMD("40 53 48 83 EC ?? F3 0F 10 05 ?? ?? ?? ?? 32 DB").GetPtr(v_Mod_QueuedPakCacheFrame);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 33 ED 48 8D 35 ?? ?? ?? ?? 48 39 2D ?? ?? ?? ??").GetPtr(Mod_UnloadPendingAndPrecacheRequestedPaks);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
dword_14B383420 = CMemory(v_Mod_ProcessPakQueue).FindPattern("F3 0F 10").ResolveRelativeAddressSelf(0x4, 0x8).RCast<float*>();
|
||||
dword_1634F445C = CMemory(v_Mod_ProcessPakQueue).FindPattern("8B 05").ResolveRelativeAddressSelf(0x2, 0x6).RCast<int32_t*>();
|
||||
qword_167ED7BB8 = CMemory(v_Mod_ProcessPakQueue).Offset(0x10).FindPatternSelf("48 83").ResolveRelativeAddressSelf(0x3, 0x8).RCast<void**>();
|
||||
byte_16709DDDF = CMemory(v_Mod_ProcessPakQueue).Offset(0x20).FindPatternSelf("88 1D").ResolveRelativeAddressSelf(0x2, 0x6).RCast<bool*>();
|
||||
off_141874660 = CMemory(v_Mod_ProcessPakQueue).Offset(0x40).FindPatternSelf("4C 8D 15").ResolveRelativeAddressSelf(0x3, 0x7).RCast<char**>();
|
||||
unk_141874555 = CMemory(v_Mod_ProcessPakQueue).Offset(0x40).FindPatternSelf("4C 8D 1D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void**>();
|
||||
unk_1418749B0 = CMemory(v_Mod_ProcessPakQueue).Offset(0xA0).FindPatternSelf("48 8D 1D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void**>();
|
||||
unk_141874550 = CMemory(v_Mod_ProcessPakQueue).Offset(0x150).FindPatternSelf("48 8D 2D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void**>();
|
||||
qword_167ED7BC0 = CMemory(v_Mod_ProcessPakQueue).Offset(0x200).FindPatternSelf("48 83 3D").ResolveRelativeAddressSelf(0x3, 0x8).RCast<int64_t*>();
|
||||
g_pNumPrecacheItemsMTVTF = CMemory(v_Mod_QueuedPakCacheFrame).FindPattern("8B 05").ResolveRelativeAddressSelf(0x2, 0x6).RCast<int32_t*>();
|
||||
g_pPakPrecacheJobFinished = CMemory(v_Mod_QueuedPakCacheFrame).Offset(0x20).FindPatternSelf("88 1D").ResolveRelativeAddressSelf(0x2, 0x6).RCast<bool*>();
|
||||
|
||||
CMemory(v_Mod_QueuedPakCacheFrame).Offset(0xA0).FindPatternSelf("48 8D 2D").ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(g_commonPakData);
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
|
@ -35,8 +35,6 @@
|
||||
#ifndef CLIENT_DLL
|
||||
#include "engine/server/server.h"
|
||||
#endif // !CLIENT_DLL
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/stryder/stryder.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#ifndef DEDICATED
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "client/vengineclient_impl.h"
|
||||
#include "geforce/reflex.h"
|
||||
#endif // !DEDICATED
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
constexpr char DFS_ENABLE_PATH[] = "/vpk/enable.txt";
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "tier0/commandline.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
#include "rtech/pak/pakparse.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "engine/sys_engine.h"
|
||||
#include "geforce/reflex.h"
|
||||
|
@ -71,7 +71,11 @@ inline void*(*v_DispatchDrawCall)(int64_t a1, uint64_t a2, int a3, int a4, int64
|
||||
inline ssize_t(*v_SpinPresent)(void);
|
||||
inline void(*CMaterialSystem__GetStreamOverlay)(const char* mode, char* buf, size_t bufSize);
|
||||
inline const char*(*CMaterialSystem__DrawStreamOverlay)(void* thisptr, uint8_t* a2, void* unused, void* a4);
|
||||
#endif // !MATERIALSYSTEM_NODX
|
||||
|
||||
inline void(*v_StreamDB_Init)(const char* const pszLevelName);
|
||||
|
||||
#ifndef MATERIALSYSTEM_NODX
|
||||
inline void** s_pRenderContext; // NOTE: This is some CMaterial instance or array.
|
||||
|
||||
inline ssize_t* g_nTotalStreamingTextureMemory = nullptr;
|
||||
@ -102,6 +106,10 @@ class VMaterialSystem : public IDetour
|
||||
LogFunAdr("CMaterialSystem::DrawStreamOverlay", CMaterialSystem__DrawStreamOverlay);
|
||||
LogFunAdr("DispatchDrawCall", v_DispatchDrawCall);
|
||||
LogFunAdr("SpinPresent", v_SpinPresent);
|
||||
#endif // !MATERIALSYSTEM_NODX
|
||||
LogFunAdr("StreamDB_Init", v_StreamDB_Init);
|
||||
|
||||
#ifndef MATERIALSYSTEM_NODX
|
||||
LogVarAdr("g_nTotalStreamingTextureMemory", g_nTotalStreamingTextureMemory);
|
||||
LogVarAdr("g_nUnfreeStreamingTextureMemory", g_nUnfreeStreamingTextureMemory);
|
||||
LogVarAdr("g_nUnusableStreamingTextureMemory", g_nUnusableStreamingTextureMemory);
|
||||
@ -124,6 +132,8 @@ class VMaterialSystem : public IDetour
|
||||
g_GameDll.FindPatternSIMD("44 89 4C 24 ?? 44 89 44 24 ?? 48 89 4C 24 ?? 55 53 56").GetPtr(v_DispatchDrawCall);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 81 EC ?? ?? ?? ?? 8B 15 ?? ?? ?? ??").GetPtr(v_SpinPresent);
|
||||
#endif // !MATERIALSYSTEM_NODX
|
||||
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 54 41 56 41 57 48 83 EC 40 48 8B E9").GetPtr(v_StreamDB_Init);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
|
@ -7,10 +7,10 @@
|
||||
//=============================================================================//
|
||||
|
||||
#include "core/stdafx.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "tier0/commandline.h"
|
||||
#include "tier1/cvar.h"
|
||||
#include "tier2/fileutils.h"
|
||||
#include "rtech/rson.h"
|
||||
#include "localize/localize.h"
|
||||
#include "modsystem.h"
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "rtech/rson.h"
|
||||
#include "filesystem/filesystem.h"
|
||||
#include "public/vscript/ivscript.h"
|
||||
#include "vscript/ivscript.h"
|
||||
|
||||
#define MOD_STATUS_LIST_FILE "mods.vdf"
|
||||
#define MOD_SETTINGS_FILE "mod.vdf"
|
||||
|
@ -24,18 +24,6 @@ enum EPackedStoreTargets
|
||||
STORE_TARGET_CLIENT
|
||||
};
|
||||
|
||||
struct FileHandleTracker_t
|
||||
{
|
||||
int m_nFileNumber;
|
||||
int m_nCurOfs;
|
||||
HANDLE m_hFileHandle;
|
||||
};
|
||||
|
||||
struct pFileHandleTracker_t
|
||||
{
|
||||
FileHandleTracker_t self[1024];
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct VPKFileEntry_t
|
||||
{
|
||||
|
13
r5dev/public/rtech/iasync.h
Normal file
13
r5dev/public/rtech/iasync.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef RTECH_IASYNC_H
|
||||
#define RTECH_IASYNC_H
|
||||
|
||||
#define ASYNC_MAX_FILE_HANDLES 1024
|
||||
#define ASYNC_MAX_FILE_HANDLES_MASK (ASYNC_MAX_FILE_HANDLES-1)
|
||||
|
||||
// invalid async request
|
||||
#define FS_ASYNC_REQ_INVALID -2
|
||||
// invalid async file
|
||||
#define FS_ASYNC_FILE_INVALID -1
|
||||
|
||||
|
||||
#endif // RTECH_IASYNC_H
|
@ -1,22 +1,97 @@
|
||||
#ifndef RTECH_IPACKFILE_H
|
||||
#define RTECH_IPACKFILE_H
|
||||
#include "tier0/jobthread.h"
|
||||
#include "tier0/tslist.h"
|
||||
|
||||
#define PLATFORM_PAK_PATH "paks\\Win64\\"
|
||||
#define PLATFORM_PAK_OVERRIDE_PATH "paks\\Win32\\"
|
||||
#include "rtech/iasync.h"
|
||||
#include "rtech/rstdlib.h"
|
||||
|
||||
#define INVALID_PAK_HANDLE -1
|
||||
|
||||
#define PAK_MAX_TYPES 64
|
||||
// pak header versions
|
||||
#define PAK_HEADER_MAGIC (('k'<<24)+('a'<<16)+('P'<<8)+'R')
|
||||
#define PAK_HEADER_VERSION 8
|
||||
|
||||
// max amount of types at runtime in which assets will be tracked
|
||||
#define PAK_MAX_TYPES 64
|
||||
#define PAK_MAX_TYPES_MASK (PAK_MAX_TYPES-1)
|
||||
|
||||
// max amount of global pak assets at runtime
|
||||
#define PAK_MAX_ASSETS 0x40000
|
||||
#define PAK_MAX_ASSETS_MASK (PAK_MAX_ASSETS-1)
|
||||
|
||||
// max amount of segments a pak file could have
|
||||
#define PAK_MAX_SEGMENTS 20
|
||||
|
||||
// max amount of buffers in which segments get copied in
|
||||
#define PAK_SEGMENT_BUFFER_TYPES 4
|
||||
|
||||
// max amount of streaming files that could be opened per set for a pak, so if a
|
||||
// pak uses more than one set, this number would be used per set
|
||||
#define PAK_MAX_STREAMING_FILE_HANDLES_PER_SET 4
|
||||
|
||||
// max amount of paks that could be loaded at runtime
|
||||
#define PAK_MAX_HANDLES 512
|
||||
#define PAK_MAX_HANDLES_MASK (PAK_MAX_HANDLES-1)
|
||||
|
||||
// base pak directory containing paks sorted in platform specific subdirectories
|
||||
#define PAK_BASE_PATH "paks\\"
|
||||
#define PLATFORM_PAK_PATH PAK_BASE_PATH"Win64\\"
|
||||
|
||||
// pak override directory; the system will looks for pak files in this directory
|
||||
// first before falling back to PLATFORM_PAK_PATH
|
||||
#define PLATFORM_PAK_OVERRIDE_PATH PAK_BASE_PATH"Win64_override\\"
|
||||
|
||||
// some decode related masks, the names might not be correct, but it seems that
|
||||
// the input mask for decoder init is always 0xFFFFFF, and for output, 0x3FFFFF
|
||||
// seems to indicate its decoding the buffer in chunks (partially)?
|
||||
#define PAK_DECODE_MASK 0xFFFFFF
|
||||
#define PAK_DECODE_MASK_FULL 0xFFFFFFFFFFFFFFFF
|
||||
#define PAK_DECODE_OUTPUT_MASK_PARTIAL 0x3FFFFF
|
||||
|
||||
// the handle that should be returned when a pak failed to load or process
|
||||
#define INVALID_PAK_HANDLE -1
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
//-----------------------------------------------------------------------------
|
||||
struct PakFile_t;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Handle types
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef int PakHandle_t;
|
||||
typedef uint64_t PakGuid_t;
|
||||
|
||||
enum class EPakStatus : int32_t
|
||||
//-----------------------------------------------------------------------------
|
||||
// Page handle types
|
||||
//-----------------------------------------------------------------------------
|
||||
struct PakPageHeader_t
|
||||
{
|
||||
uint32_t segmentIdx;
|
||||
uint32_t pageAlignment;
|
||||
uint32_t dataSize;
|
||||
};
|
||||
|
||||
// ptr.index != UINT32_MAX
|
||||
// ptr.offset != UINT32_MAX
|
||||
// ptr.index < pak->GetPageCount()
|
||||
// ptr.offset <= pak->GetPageSize(ptr.index)
|
||||
#define IS_PAKPTR_VALID(pak, ptr) ((ptr)->index != UINT32_MAX && (ptr)->offset != UINT32_MAX && (ptr)->index < (pak)->GetPageCount() && (ptr)->offset <= (pak)->GetPageSize((ptr)->index))
|
||||
#define ASSERT_PAKPTR_VALID(pak, ptr) Assert(IS_PAKPTR_VALID(pak, ptr), "Invalid pak page pointer")
|
||||
|
||||
union PakPage_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t index;
|
||||
uint32_t offset;
|
||||
};
|
||||
void* ptr;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Enumerations
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EPakStatus : int32_t
|
||||
{
|
||||
PAK_STATUS_FREED = 0,
|
||||
PAK_STATUS_LOAD_PENDING = 1,
|
||||
@ -36,89 +111,104 @@ enum class EPakStatus : int32_t
|
||||
PAK_STATUS_BUSY = 15
|
||||
};
|
||||
|
||||
enum EPakStreamSet
|
||||
{
|
||||
STREAMING_SET_MANDATORY = 0,
|
||||
STREAMING_SET_OPTIONAL,
|
||||
|
||||
// number of streaming sets
|
||||
STREAMING_SET_COUNT
|
||||
};
|
||||
|
||||
struct PakAssetBinding_t
|
||||
{
|
||||
uint32_t m_extension; // For example '0x6C74616D' for the material asset.
|
||||
int m_version;
|
||||
const char* m_description; // Description/Name of asset.
|
||||
void* m_loadAssetFunction;
|
||||
void* m_unloadAssetFunction;
|
||||
void* m_replaceAssetFunction;
|
||||
void* m_allocAssetFunctions;
|
||||
int m_subHeaderSize;
|
||||
int m_nativeClassSize; // Native class size, for 'material' it would be CMaterialGlue full size.
|
||||
uint32_t m_headerAlignment;
|
||||
int unk3;
|
||||
enum EType
|
||||
{
|
||||
NONE = 0,
|
||||
|
||||
// not registered, assets with type 'NONE'
|
||||
// will be stubbed with this value!
|
||||
STUB,
|
||||
|
||||
// explicitly registered by pak or code
|
||||
REGISTERED
|
||||
};
|
||||
|
||||
// for example '0x6C74616D' for the material asset.
|
||||
uint32_t extension;
|
||||
uint32_t version;
|
||||
|
||||
// description or name of asset.
|
||||
const char* description;
|
||||
|
||||
// asset specific load callbacks
|
||||
void* loadAssetFunc;
|
||||
void* unloadAssetFunc;
|
||||
void* replaceAssetFunc;
|
||||
|
||||
CAlignedMemAlloc* allocator;
|
||||
|
||||
unsigned int headerSize;
|
||||
unsigned int nativeClassSize; // Native class size, for 'material' it would be CMaterialGlue full size.
|
||||
unsigned int headerAlignment;
|
||||
|
||||
// the type of this asset bind
|
||||
// NOTE: the asset bind will be stubbed if its 'NONE' in runtime!
|
||||
EType type;
|
||||
|
||||
// [ PIXIE ]: Should be the full size across Season 0-3.
|
||||
};
|
||||
|
||||
struct PakAsset_t
|
||||
{
|
||||
uint64_t m_guid;
|
||||
uint64_t m_padding;
|
||||
uint32_t m_headPageIdx;
|
||||
uint32_t m_headPageOffset;
|
||||
uint32_t m_cpuPageIdx;
|
||||
uint32_t m_cpuPageOffset;
|
||||
uint64_t m_starpakOffset;
|
||||
uint64_t m_starpakOptOffset;
|
||||
uint16_t m_pageEnd;
|
||||
uint16_t unk1;
|
||||
uint32_t m_relationsStartIdx;
|
||||
uint32_t m_usesStartIdx;
|
||||
uint32_t m_relationsCount;
|
||||
uint32_t m_usesCount;
|
||||
uint32_t m_assetHeaderSize;
|
||||
uint32_t m_version;
|
||||
uint32_t m_magic;
|
||||
// the guid of this asset, which will be used to index into, and retrieve
|
||||
// this asset from the hash table
|
||||
PakGuid_t guid;
|
||||
uint64_t padding; // Unknown.
|
||||
|
||||
PakPage_t headPtr;
|
||||
PakPage_t dataPtr;
|
||||
|
||||
// offset to the streaming data in the streaming set
|
||||
uint64_t streamingDataFileOffset[STREAMING_SET_COUNT];
|
||||
uint16_t pageEnd;
|
||||
|
||||
// the number of remaining dependencies that are yet to be resolved
|
||||
uint16_t numRemainingDependencies;
|
||||
uint32_t dependentsIndex;
|
||||
uint32_t dependenciesIndex;
|
||||
uint32_t dependentsCount;
|
||||
uint32_t dependenciesCount;
|
||||
|
||||
// size of the asset's header
|
||||
uint32_t headerSize;
|
||||
|
||||
// versions of the asset
|
||||
uint32_t version;
|
||||
uint32_t magic;
|
||||
|
||||
FORCEINLINE uint8_t HashTableIndexForAssetType() const
|
||||
{
|
||||
return (((0x1020601 * magic) >> 24) & PAK_MAX_TYPES_MASK);
|
||||
}
|
||||
};
|
||||
|
||||
struct PakAssetShort_t
|
||||
{
|
||||
uint64_t m_guid;
|
||||
uint64_t m_padding;
|
||||
PakGuid_t guid;
|
||||
uint32_t unk_8;
|
||||
uint32_t unk_C;
|
||||
void* m_head;
|
||||
void* m_cpu;
|
||||
};
|
||||
|
||||
struct PakGlobals_t
|
||||
{
|
||||
PakAssetBinding_t m_assetBindings[64]; // [ PIXIE ]: Max possible registered assets on Season 3, 0-2 I did not check yet.
|
||||
PakAssetShort_t m_assets[0x40000];
|
||||
// End size unknown.
|
||||
PakAssetBinding_t m_assetBindings[PAK_MAX_TYPES]; // [ PIXIE ]: Max possible registered assets on Season 3, 0-2 I did not check yet.
|
||||
PakAssetShort_t m_assets[PAK_MAX_ASSETS];
|
||||
// end size unknown, but there appears to be stuff below too
|
||||
};
|
||||
|
||||
struct PakFileHeader_t
|
||||
{
|
||||
uint32_t m_magic; // 'RPak'
|
||||
uint16_t m_version; // R2 = '7' R5 = '8'
|
||||
uint8_t m_flags[0x2]; //
|
||||
FILETIME m_fileTime; //
|
||||
uint64_t m_checksum; //
|
||||
uint64_t m_compressedSize; // Compressed size
|
||||
uint64_t m_embeddedStarpakOffset; //
|
||||
uint8_t unk0[0x8]; //
|
||||
uint64_t m_decompressedSize; // Decompressed size
|
||||
uint64_t m_embeddedStarpakSize; //
|
||||
uint8_t unk1[0x8]; //
|
||||
|
||||
uint16_t m_starpakReferenceSize; //
|
||||
uint16_t m_starpakOptReferenceSize; //
|
||||
uint16_t m_virtualSegmentCount; // * 0x10
|
||||
uint16_t m_memPageCount; // * 0xC
|
||||
|
||||
uint32_t m_patchIndex; //
|
||||
|
||||
uint32_t m_descriptorCount; //
|
||||
uint32_t m_assetEntryCount; // File entry count
|
||||
uint32_t m_guidDescriptorCount; //
|
||||
uint32_t m_relationsCounts; //
|
||||
|
||||
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
|
||||
{
|
||||
size_t m_sizeDisk;
|
||||
@ -131,107 +221,256 @@ struct PakPatchDataHeader_t
|
||||
int m_pageCount;
|
||||
};
|
||||
|
||||
struct PakFileHeader_t
|
||||
{
|
||||
inline uint32_t GetTotalStreamingNamesBufferSize() const
|
||||
{
|
||||
return(
|
||||
streamingFilesBufSize[STREAMING_SET_MANDATORY] +
|
||||
streamingFilesBufSize[STREAMING_SET_OPTIONAL]);
|
||||
}
|
||||
|
||||
inline uint64_t GetTotalEmbeddedStreamingDataSize() const
|
||||
{
|
||||
return (
|
||||
embeddedStreamingDataSize[STREAMING_SET_MANDATORY] +
|
||||
embeddedStreamingDataSize[STREAMING_SET_OPTIONAL]);
|
||||
}
|
||||
|
||||
inline uint64_t GetTotalHeaderSize() const
|
||||
{
|
||||
uint64_t headerSize = sizeof(PakFileHeader_t);
|
||||
|
||||
// if we have patches, we should include the patch header as well
|
||||
if (patchIndex > 0)
|
||||
headerSize += sizeof(PakPatchDataHeader_t);
|
||||
|
||||
// the streaming file paths belong to the header as well
|
||||
headerSize += GetTotalStreamingNamesBufferSize();
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
// file versions
|
||||
uint32_t magic; // 'RPak'
|
||||
uint16_t version; // R2 = '7' R5 = '8'
|
||||
|
||||
//
|
||||
uint8_t flags[0x2]; // TODO: make this an uint16_t!!!
|
||||
|
||||
// when this pak file was built
|
||||
FILETIME fileTime;
|
||||
uint64_t checksum;
|
||||
|
||||
// compressed size of the pak file, this includes the header
|
||||
uint64_t compressedSize;
|
||||
|
||||
// offset to the embedded mandatory and optional streaming data
|
||||
// NOTE: this should be NULL if external streaming sets are used
|
||||
uint64_t embeddedStreamingDataOffset[STREAMING_SET_COUNT];
|
||||
|
||||
// decompressed size of this pak, this includes the header
|
||||
// NOTE: if the pak is uncompressed, this will equal compressedSize
|
||||
uint64_t decompressedSize;
|
||||
|
||||
// size of the embedded mandatory and optional streaming data
|
||||
// NOTE: this should be NULL if external streaming sets are used
|
||||
uint64_t embeddedStreamingDataSize[STREAMING_SET_COUNT];
|
||||
|
||||
// size of the string array containing paths to external streaming files
|
||||
uint16_t streamingFilesBufSize[STREAMING_SET_COUNT];
|
||||
|
||||
// number of segments in this pak; absolute max = PAK_MAX_SEGMENTS
|
||||
uint16_t virtualSegmentCount;
|
||||
|
||||
// number of memory pages to allocate for this pak
|
||||
uint16_t memPageCount;
|
||||
|
||||
uint16_t patchIndex;
|
||||
|
||||
uint32_t descriptorCount;
|
||||
|
||||
// number of assets in this pak
|
||||
uint32_t assetCount;
|
||||
uint32_t guidDescriptorCount;
|
||||
uint32_t relationsCounts;
|
||||
|
||||
uint8_t unk2[0x10];
|
||||
|
||||
// size not verified. offsets every page by x amount, if not 0 start of first page has data corresponding for 'patching some page'
|
||||
uint32_t memPageOffset;
|
||||
|
||||
uint8_t unk3[0x8];
|
||||
}; static_assert(sizeof(PakFileHeader_t) == 0x80);
|
||||
|
||||
// segment flags
|
||||
#define SF_HEAD (0)
|
||||
#define SF_TEMP (1 << 0) // 0x1
|
||||
#define SF_CPU (1 << 1) // 0x2
|
||||
#define SF_DEV (1 << 8) // 0x80
|
||||
|
||||
struct PakSegmentHeader_t
|
||||
{
|
||||
int m_flags;
|
||||
int m_align;
|
||||
size_t m_size;
|
||||
int typeFlags;
|
||||
int dataAlignment;
|
||||
size_t dataSize;
|
||||
};
|
||||
|
||||
struct PakDecompState_t
|
||||
struct PakSegmentDescriptor_t // TODO: give this a better name!!!
|
||||
{
|
||||
uint64_t m_inputBuf;
|
||||
uint64_t m_outputBuf;
|
||||
uint64_t m_inputMask;
|
||||
uint64_t m_outputMask;
|
||||
uint64_t m_fileSize;
|
||||
uint64_t m_decompSize;
|
||||
uint64_t m_inputInvMask;
|
||||
uint64_t m_outputInvMask;
|
||||
uint32_t m_headerOffset;
|
||||
size_t assetTypeCount[PAK_MAX_TYPES];
|
||||
int64_t segmentSizes[PAK_MAX_SEGMENTS];
|
||||
|
||||
size_t segmentSizeForType[PAK_SEGMENT_BUFFER_TYPES];
|
||||
int segmentAlignmentForType[PAK_SEGMENT_BUFFER_TYPES];
|
||||
};
|
||||
|
||||
struct PakDecoder_t
|
||||
{
|
||||
const uint8_t* inputBuf;
|
||||
uint8_t* outputBuf;
|
||||
|
||||
uint64_t inputMask;
|
||||
uint64_t outputMask;
|
||||
|
||||
size_t fileSize;
|
||||
size_t decompSize;
|
||||
|
||||
uint64_t inputInvMask;
|
||||
uint64_t outputInvMask;
|
||||
|
||||
uint32_t headerOffset;
|
||||
uint32_t dword44;
|
||||
uint64_t m_fileBytePosition;
|
||||
uint64_t m_decompBytePosition;
|
||||
uint64_t m_bufferSizeNeeded;
|
||||
uint64_t m_currentByte;
|
||||
uint32_t m_currentByteBit;
|
||||
|
||||
uint64_t inBufBytePos;
|
||||
uint64_t outBufBytePos;
|
||||
|
||||
size_t bufferSizeNeeded;
|
||||
|
||||
// current byte and current bit of byte
|
||||
uint64_t currentByte;
|
||||
uint32_t currentBit;
|
||||
|
||||
uint32_t dword6C;
|
||||
uint64_t qword70;
|
||||
uint64_t m_compressedStreamSize;
|
||||
uint64_t m_decompStreamSize;
|
||||
|
||||
size_t compressedStreamSize;
|
||||
size_t decompStreamSize;
|
||||
};
|
||||
|
||||
struct PakFile_t;
|
||||
|
||||
class PakLoadedInfo_t
|
||||
{
|
||||
public:
|
||||
PakHandle_t m_handle; //0x0000
|
||||
EPakStatus m_status; //0x0004
|
||||
uint64_t m_nUnk1; //0x0008
|
||||
uint32_t m_nUnk2; //0x0010
|
||||
uint32_t m_assetCount; //0x0014
|
||||
char* m_fileName; //0x0018
|
||||
void* m_allocator; //0x0020
|
||||
uint64_t* m_assetGuids; //0x0028 size of the array is m_nAssetCount
|
||||
void* m_virtualSegmentBuffers[4]; //0x0030
|
||||
char pad_0050[16]; //0x0050
|
||||
void* m_pakInfo; //0x0060
|
||||
PakLoadedInfo_t* m_pUnknownLoadedPakInfo; //0x0068
|
||||
char pad_0070[4]; //0x0070
|
||||
int8_t m_nUnk3; //0x0074
|
||||
char pad_0075[51]; //0x0075
|
||||
uint32_t m_nUnk4; //0x00A8
|
||||
uint8_t m_nUnk5; //0x00AC
|
||||
uint64_t m_nUnkEnd; //0x00B0/0x00E8
|
||||
struct StreamingInfo_t
|
||||
{
|
||||
inline void Reset()
|
||||
{
|
||||
embeddedStarpakName = nullptr;
|
||||
streamFileNumber[0] = FS_ASYNC_FILE_INVALID;
|
||||
streamFileNumber[1] = FS_ASYNC_FILE_INVALID;
|
||||
streamFileNumber[2] = FS_ASYNC_FILE_INVALID;
|
||||
streamFileNumber[3] = FS_ASYNC_FILE_INVALID;
|
||||
streamFileCount = NULL;
|
||||
streamingDisabled = true;
|
||||
}
|
||||
|
||||
char* embeddedStarpakName;
|
||||
int streamFileNumber[PAK_MAX_STREAMING_FILE_HANDLES_PER_SET];
|
||||
int streamFileCount;
|
||||
bool streamingDisabled;
|
||||
char padding_maybe[3];
|
||||
};
|
||||
|
||||
PakHandle_t handle;
|
||||
EPakStatus status;
|
||||
uint64_t m_nUnk1;
|
||||
|
||||
// the log level of the pak, this is also used for errors if a pak failed
|
||||
// to load; the higher the level, the more important this pak file is
|
||||
int logLevel;
|
||||
|
||||
uint32_t assetCount;
|
||||
const char* fileName;
|
||||
CAlignedMemAlloc* allocator;
|
||||
PakGuid_t* assetGuids; //size of the array is m_nAssetCount
|
||||
void* segmentBuffers[PAK_SEGMENT_BUFFER_TYPES];
|
||||
_QWORD qword50;
|
||||
FILETIME fileTime;
|
||||
PakFile_t* pakFile;
|
||||
StreamingInfo_t streamInfo[STREAMING_SET_COUNT];
|
||||
uint32_t fileHandle;
|
||||
uint8_t m_nUnk5;
|
||||
uint64_t hModule;
|
||||
|
||||
}; //Size: 0x00B8/0x00E8
|
||||
|
||||
struct PakPage_t
|
||||
{
|
||||
uint32_t m_index;
|
||||
uint32_t m_offset;
|
||||
};
|
||||
|
||||
struct PakPageHeader_t
|
||||
{
|
||||
uint32_t m_virtualSegmentIndex;
|
||||
uint32_t m_pageAlignment;
|
||||
uint32_t m_dataSize;
|
||||
};
|
||||
|
||||
struct PakFileStream_t
|
||||
{
|
||||
struct Descriptor
|
||||
{
|
||||
size_t dataOffset;
|
||||
size_t compressedSize;
|
||||
size_t decompressedSize;
|
||||
|
||||
// NOTE: if this is set, the game sets 'PakMemoryData_t::m_processedPatchedDataSize'
|
||||
// to 'dataOffset'; else its getting set to 'sizeof(PakFileHeader_t)'.
|
||||
bool isCompressed;
|
||||
};
|
||||
|
||||
_QWORD qword0;
|
||||
_QWORD qword8;
|
||||
_DWORD fileHandle;
|
||||
_DWORD gap14[32];
|
||||
int fileHandle; // TODO: Unsigned?
|
||||
int gap14[32]; // TODO: Unsigned?
|
||||
_BYTE gap94[32];
|
||||
unsigned int unsigned_intB4;
|
||||
_DWORD dwordB8;
|
||||
_BYTE byteBC;
|
||||
_BYTE byteBD;
|
||||
bool finishedLoadingPatches;
|
||||
_BYTE gapBE;
|
||||
_BYTE byteBF;
|
||||
_BYTE gapC0[256];
|
||||
Descriptor m_descriptors[8];
|
||||
uint8_t* buffer;
|
||||
_QWORD qword1C8;
|
||||
_QWORD qword1D0;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
struct RBitRead // TODO: move to own file?
|
||||
typedef struct PakPatchFuncs_s
|
||||
{
|
||||
uint64_t m_dataBuf;
|
||||
int m_bitsRemaining;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
typedef bool (*PatchFunc_t)(PakFile_t* const pak, size_t* const numAvailableBytes);
|
||||
|
||||
enum EPatchCommands
|
||||
{
|
||||
PATCH_CMD0,
|
||||
PATCH_CMD1,
|
||||
PATCH_CMD2,
|
||||
PATCH_CMD3,
|
||||
PATCH_CMD4,
|
||||
PATCH_CMD5, // Same as cmd4.
|
||||
PATCH_CMD6,
|
||||
|
||||
// !!! NOT A CMD !!!
|
||||
PATCH_CMD_COUNT
|
||||
};
|
||||
|
||||
inline PatchFunc_t operator[](ssize_t i) const
|
||||
{
|
||||
Assert((i >= 0) && (i < SDK_ARRAYSIZE(patchFuncs)));
|
||||
return patchFuncs[i];
|
||||
}
|
||||
|
||||
PatchFunc_t patchFuncs[PATCH_CMD_COUNT];
|
||||
|
||||
} PakPatchFuncs_t;
|
||||
|
||||
struct PakMemoryData_t
|
||||
{
|
||||
uint64_t m_processedPatchedDataSize;
|
||||
char* m_patchData;
|
||||
uint64_t processedPatchedDataSize;
|
||||
char* patchData; // pointer to patch stream data
|
||||
|
||||
uint64_t m_patchDataPtr;
|
||||
RBitRead m_bitBuf;
|
||||
uint32_t m_patchDataOffset;
|
||||
char* patchDataPtr;
|
||||
RBitRead bitBuf;
|
||||
uint32_t patchDataOffset;
|
||||
|
||||
_BYTE patchCommands[64];
|
||||
|
||||
@ -241,70 +480,179 @@ struct PakMemoryData_t
|
||||
|
||||
_QWORD field_2A8;
|
||||
|
||||
size_t m_patchSrcSize;
|
||||
char* m_patchDstPtr;
|
||||
__int64 m_numBytesToProcess_maybe;
|
||||
// number of bytes remaining in the patch stream data
|
||||
size_t patchSrcSize;
|
||||
|
||||
unsigned __int8(__fastcall* patchFunc)(PakFile_t*, unsigned __int64*);
|
||||
// pointer to the location in the pak that a patch command is writing to
|
||||
char* patchDstPtr;
|
||||
|
||||
size_t numBytesToProcess_maybe;
|
||||
PakPatchFuncs_s::PatchFunc_t patchFunc;
|
||||
|
||||
uint64_t qword2D0;
|
||||
uint64_t qword2D8;
|
||||
PakHandle_t pakId;
|
||||
JobID_t unkJobID;
|
||||
int* qword2E0;
|
||||
uint8_t** m_pagePointers;
|
||||
uint8_t** memPageBuffers;
|
||||
|
||||
PakPatchFileHeader_t* m_patchHeaders;
|
||||
short* UnkPatchIndexes;
|
||||
PakPatchFileHeader_t* patchHeaders;
|
||||
unsigned short* patchIndices;
|
||||
|
||||
char* m_streamingFilePaths;
|
||||
char* m_optStreamingFilePaths;
|
||||
char* streamingFilePaths[STREAMING_SET_COUNT];
|
||||
|
||||
PakSegmentHeader_t* m_segmentHeaders;
|
||||
PakPageHeader_t* m_pageHeaders;
|
||||
PakSegmentHeader_t* segmentHeaders;
|
||||
PakPageHeader_t* pageHeaders;
|
||||
|
||||
PakPage_t* m_virtualPointers;
|
||||
PakAsset_t* m_assetEntries;
|
||||
PakPage_t* virtualPointers;
|
||||
PakAsset_t* assetEntries;
|
||||
|
||||
PakPage_t* m_guidDescriptors;
|
||||
uint32_t* m_fileRelations;
|
||||
PakPage_t* guidDescriptors;
|
||||
uint32_t* fileRelations;
|
||||
|
||||
char gap5E0[32];
|
||||
|
||||
PakPatchDataHeader_t* m_patchDataHeader;
|
||||
PakAsset_t** m_ppAssetEntries;
|
||||
PakPatchDataHeader_t* patchDataHeader;
|
||||
PakAsset_t** ppAssetEntries;
|
||||
|
||||
_BYTE gap370[520];
|
||||
int someAssetCount;
|
||||
int numShiftedPointers;
|
||||
|
||||
const char* m_fileName;
|
||||
PakFileHeader_t m_pakHeader;
|
||||
// array of sizes/offsets in the SF_HEAD segment buffer
|
||||
__int64 unkAssetTypeBindingSizes[PAK_MAX_TYPES];
|
||||
|
||||
const char* fileName;
|
||||
PakFileHeader_t pakHeader;
|
||||
};
|
||||
|
||||
struct PakFile_t
|
||||
{
|
||||
int m_numPointers;
|
||||
int m_numAssets;
|
||||
int m_pageCount;
|
||||
int m_pageStart;
|
||||
int numProcessedPointers;
|
||||
uint32_t processedAssetCount;
|
||||
int processedPageCount;
|
||||
int firstPageIdx;
|
||||
|
||||
uint32_t m_patchCount;
|
||||
uint32_t patchCount;
|
||||
uint32_t dword14;
|
||||
|
||||
PakFileStream_t m_fileStream;
|
||||
uint64_t m_inputBytePos;
|
||||
PakFileStream_t fileStream;
|
||||
uint64_t inputBytePos;
|
||||
uint8_t byte1F8;
|
||||
char gap1F9[4];
|
||||
uint8_t byte1FD;
|
||||
short flags_1FE;
|
||||
PakDecompState_t m_pakDecompState;
|
||||
void* m_decompBuffer;
|
||||
size_t m_maxCopySize;
|
||||
bool isOffsetted_MAYBE;
|
||||
bool isCompressed;
|
||||
PakDecoder_t pakDecoder;
|
||||
uint8_t* decompBuffer;
|
||||
size_t maxCopySize;
|
||||
uint64_t qword298;
|
||||
|
||||
PakMemoryData_t m_memoryData;
|
||||
PakMemoryData_t memoryData;
|
||||
|
||||
inline const char* GetName() const
|
||||
{
|
||||
return memoryData.fileName;
|
||||
}
|
||||
|
||||
inline const PakFileHeader_t& GetHeader() const
|
||||
{
|
||||
return memoryData.pakHeader;
|
||||
}
|
||||
|
||||
inline uint32_t GetAssetCount() const
|
||||
{
|
||||
return GetHeader().assetCount;
|
||||
}
|
||||
|
||||
inline uint32_t GetPointerCount() const
|
||||
{
|
||||
return GetHeader().descriptorCount;
|
||||
}
|
||||
|
||||
// --- pages ---
|
||||
inline uint16_t GetPageCount() const
|
||||
{
|
||||
return GetHeader().memPageCount;
|
||||
}
|
||||
|
||||
inline bool IsPageOffsetValid(uint32_t index, uint32_t offset) const
|
||||
{
|
||||
// validate page index
|
||||
if (index == UINT32_MAX || index > GetPageCount())
|
||||
return false;
|
||||
|
||||
// !TODO! find some other way of validating offset within page
|
||||
// commented because otherwise we incorrectly return false a lot.
|
||||
// because of pointer shifting, the offset can't be easily validated like this
|
||||
//
|
||||
//if (offset == UINT32_MAX || && offset > GetPageSize(index))
|
||||
// return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline const PakPageHeader_t* GetPageHeader(const uint32_t i) const
|
||||
{
|
||||
assert(i != UINT32_MAX && i < GetPageCount());
|
||||
|
||||
return &memoryData.pageHeaders[i];
|
||||
}
|
||||
|
||||
inline uint32_t GetPageSize(const uint32_t i) const
|
||||
{
|
||||
assert(i != UINT32_MAX && i < GetPageCount());
|
||||
return memoryData.pageHeaders[i].dataSize;
|
||||
}
|
||||
|
||||
inline void* GetPointerForPageOffset(const uint32_t index, const uint32_t offset) const
|
||||
{
|
||||
assert(IsPageOffsetValid(index, offset));
|
||||
|
||||
return memoryData.memPageBuffers[index] + offset;
|
||||
}
|
||||
|
||||
inline void* GetPointerForPageOffset(const PakPage_t& ptr) const
|
||||
{
|
||||
assert(IsPageOffsetValid(ptr.index, ptr.offset));
|
||||
|
||||
return memoryData.memPageBuffers[ptr.index] + ptr.offset;
|
||||
}
|
||||
|
||||
inline void* GetPointerForPageOffset(const PakPage_t* ptr) const
|
||||
{
|
||||
assert(IsPageOffsetValid(ptr->index, ptr->offset));
|
||||
|
||||
return memoryData.memPageBuffers[ptr->index] + ptr->offset;
|
||||
}
|
||||
|
||||
// --- segments ---
|
||||
inline uint16_t GetSegmentCount() const
|
||||
{
|
||||
return GetHeader().virtualSegmentCount;
|
||||
}
|
||||
|
||||
inline const PakSegmentHeader_t* GetSegmentHeader(const uint32_t i) const
|
||||
{
|
||||
assert(i < GetSegmentCount());
|
||||
|
||||
return &memoryData.segmentHeaders[i];
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(PakFile_t) == 2208); // S3+
|
||||
struct UnknownPakStruct_t
|
||||
{
|
||||
uint32_t unk_0;
|
||||
int unk_4;
|
||||
int unk_8;
|
||||
char gap_C[0x9D404];
|
||||
int unk_array_9D410[512];
|
||||
char gap_9DC04[0x7F800];
|
||||
};
|
||||
|
||||
static_assert(sizeof(PakDecompState_t) == 136);
|
||||
|
||||
static_assert(sizeof(UnknownPakStruct_t) == 0x11D410);
|
||||
static_assert(sizeof(PakFile_t) == 2208); // S3+
|
||||
static_assert(sizeof(PakLoadedInfo_t) == 184);
|
||||
static_assert(sizeof(PakDecoder_t) == 136);
|
||||
static_assert(sizeof(PakPatchFileHeader_t) == 16);
|
||||
|
||||
#endif // RTECH_IPACKFILE_H
|
||||
|
@ -22,46 +22,45 @@ public:
|
||||
RSON_ARRAY = 0x1000,
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
struct Field_t;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
//
|
||||
//-------------------------------------------------------------------------
|
||||
union Value_t
|
||||
{
|
||||
inline Field_t* GetSubKey() const { return pSubKey; };
|
||||
inline const char* GetString() const { return pszString; };
|
||||
inline int64_t GetInt() const { return integerValue; };
|
||||
|
||||
Field_t* pSubKey;
|
||||
char* pszString;
|
||||
__int64 integerValue;
|
||||
int64_t integerValue;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// used for the root node of rson tree
|
||||
//-------------------------------------------------------------------------
|
||||
struct Node_t
|
||||
{
|
||||
eFieldType m_Type;
|
||||
int m_nValueCount;
|
||||
Value_t m_Value;
|
||||
|
||||
Field_t* GetFirstSubKey()
|
||||
{
|
||||
if (m_Type & eFieldType::RSON_OBJECT)
|
||||
return m_Value.pSubKey;
|
||||
return NULL;
|
||||
};
|
||||
inline Field_t* GetFirstSubKey() const;
|
||||
|
||||
// does not support finding a key in a different level of the tree
|
||||
Field_t* FindKey(const char* pszKeyName)
|
||||
{
|
||||
if ((m_Type & eFieldType::RSON_OBJECT) == 0)
|
||||
return NULL;
|
||||
|
||||
for (Field_t* pKey = GetFirstSubKey(); pKey != nullptr; pKey = pKey->GetNextKey())
|
||||
{
|
||||
if (!_stricmp(pKey->m_pszName, pszKeyName))
|
||||
return pKey;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
inline Field_t* FindKey(const char* const pszKeyName) const;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// used for every other field of the rson tree
|
||||
//-------------------------------------------------------------------------
|
||||
struct Field_t
|
||||
{
|
||||
char* m_pszName;
|
||||
@ -69,20 +68,48 @@ public:
|
||||
Field_t* m_pNext;
|
||||
Field_t* m_pPrev;
|
||||
|
||||
Field_t* GetNextKey() { return m_pNext; };
|
||||
Field_t* GetLastKey() { return m_pPrev; };
|
||||
// Inlines
|
||||
inline const char* GetString() const { return (m_Node.m_Type == RSON_STRING) ? m_Node.m_Value.GetString() : NULL; };
|
||||
inline Field_t* GetNextKey() const { return m_pNext; };
|
||||
inline Field_t* GetLastKey() const { return m_pPrev; };
|
||||
|
||||
Field_t* GetFirstSubKey() { return m_Node.GetFirstSubKey(); };
|
||||
|
||||
Field_t* FindKey(const char* pszKeyName) { return m_Node.FindKey(pszKeyName); };
|
||||
|
||||
const char* GetString() { return (m_Node.m_Type == RSON_STRING) ? m_Node.m_Value.pszString : NULL; };
|
||||
inline Field_t* GetFirstSubKey() const { return m_Node.GetFirstSubKey(); };
|
||||
inline Field_t* FindKey(const char* pszKeyName) const { return m_Node.FindKey(pszKeyName); };
|
||||
};
|
||||
|
||||
public:
|
||||
static Node_t* LoadFromBuffer(const char* pszBufferName, char* pBuffer, eFieldType rootType);
|
||||
static Node_t* LoadFromFile(const char* pszFilePath, const char* pPathID = nullptr);
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RSON::Field_t* RSON::Node_t::GetFirstSubKey() const
|
||||
{
|
||||
if (m_Type & eFieldType::RSON_OBJECT)
|
||||
return m_Value.pSubKey;
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
RSON::Field_t* RSON::Node_t::FindKey(const char* const pszKeyName) const
|
||||
{
|
||||
if ((m_Type & eFieldType::RSON_OBJECT) == 0)
|
||||
return NULL;
|
||||
|
||||
for (Field_t* pKey = GetFirstSubKey(); pKey != nullptr; pKey = pKey->GetNextKey())
|
||||
{
|
||||
if (!_stricmp(pKey->m_pszName, pszKeyName))
|
||||
return pKey;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
inline RSON::Node_t* (*RSON_LoadFromBuffer)(const char* bufName, char* buf, RSON::eFieldType rootType, __int64 a4, void* a5);
|
||||
inline void (*RSON_Free)(RSON::Node_t* rson, CAlignedMemAlloc* allocator);
|
97
r5dev/public/rtech/rstdlib.h
Normal file
97
r5dev/public/rtech/rstdlib.h
Normal file
@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
|
||||
class RHashMap;
|
||||
|
||||
/* ==== RTECH =========================================================================================================================================================== */
|
||||
// [ PIXIE ]: I'm very unsure about this, but it really seems like it
|
||||
inline int(*v_RHashMap_FindSlot)(RHashMap* const thisptr);
|
||||
inline void(*v_RHashMap_FreeSlot)(RHashMap* const thisptr, const int slotNum);
|
||||
|
||||
|
||||
class RHashMap
|
||||
{
|
||||
public:
|
||||
inline int FindSlot(void)
|
||||
{
|
||||
return v_RHashMap_FindSlot(this);
|
||||
}
|
||||
|
||||
inline void FreeSlot(const unsigned int slotNum)
|
||||
{
|
||||
v_RHashMap_FreeSlot(this, slotNum);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_index;
|
||||
int m_slotsLeft;
|
||||
int m_structSize;
|
||||
int m_searchMask;
|
||||
void* m_buffer;
|
||||
int m_slotsUsed;
|
||||
int padding_perhaps;
|
||||
};
|
||||
|
||||
class RHashMap_MT
|
||||
{
|
||||
public:
|
||||
inline int FindSlot(void)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
const int slot = m_mgr.FindSlot();
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
inline void FreeSlot(const unsigned int slotNum)
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_lock);
|
||||
m_mgr.FreeSlot(slotNum);
|
||||
ReleaseSRWLockExclusive(&m_lock);
|
||||
}
|
||||
|
||||
private:
|
||||
RHashMap m_mgr;
|
||||
SRWLOCK m_lock;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
class RBitRead
|
||||
{
|
||||
public:
|
||||
FORCEINLINE uint64_t ReadBits(const uint32_t numBits)
|
||||
{
|
||||
Assert(numBits <= 64, "RBitRead::ReadBits: numBits must be less than or equal to 64.");
|
||||
return m_dataBuf & ((1ull << numBits) - 1);
|
||||
}
|
||||
|
||||
FORCEINLINE void DiscardBits(const uint32_t numBits)
|
||||
{
|
||||
Assert(numBits <= 64, "RBitRead::DiscardBits: numBits must be less than or equal to 64.");
|
||||
this->m_dataBuf >>= numBits;
|
||||
this->m_bitsRemaining += numBits;
|
||||
}
|
||||
|
||||
uint64_t m_dataBuf;
|
||||
int m_bitsRemaining;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_ReSTD : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("RHashMap::FindSlot", v_RHashMap_FindSlot);
|
||||
LogFunAdr("RHashMap::FreeSlot", v_RHashMap_FreeSlot);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("44 8B 51 0C 4C 8B C1").GetPtr(v_RHashMap_FindSlot);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 44 8B 59 0C").GetPtr(v_RHashMap_FreeSlot);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { };
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -1,35 +1,85 @@
|
||||
#ifndef JOBTHREAD_H
|
||||
#define JOBTHREAD_H
|
||||
|
||||
typedef uint32_t JobID_t;
|
||||
typedef uint8_t JobTypeID_t;
|
||||
|
||||
struct JobFifoLock_s
|
||||
{
|
||||
};
|
||||
|
||||
typedef uint32_t JobID_t;
|
||||
struct JobContext_s
|
||||
{
|
||||
void* callbackArg; // Argument to job callback function.
|
||||
void* callbackFunc; // Job callback function.
|
||||
JobTypeID_t jobTypeId;
|
||||
bool field_11;
|
||||
__int16 field_12;
|
||||
int field_14;
|
||||
JobID_t jobId;
|
||||
int field_1C;
|
||||
int field_20;
|
||||
int field_24; // Bit fields?
|
||||
__int64 field_28;
|
||||
__int64 unknownMask;
|
||||
__int64 unknownInt;
|
||||
};
|
||||
|
||||
// Array size = 2048*sizeof(JobContext_s)
|
||||
inline JobContext_s* job_JT_Context = nullptr;
|
||||
|
||||
extern bool JT_IsJobDone(const JobID_t jobId);
|
||||
extern JobID_t JTGuts_AddJob(JobTypeID_t jobTypeId, JobID_t jobId, void* callbackFunc, void* callbackArg);
|
||||
|
||||
|
||||
inline void(*JT_ParallelCall)(void);
|
||||
inline void*(*JT_HelpWithAnything)(bool bShouldLoadPak);
|
||||
inline bool(*JT_AcquireFifoLock)(struct JobFifoLock_s* pFifo);
|
||||
|
||||
inline bool(*JT_HelpWithJobTypes)(__int64(__fastcall* callback)(__int64, _DWORD*, __int64, _QWORD*), JobFifoLock_s* pFifoLock, __int64 a3, __int64 a4);
|
||||
inline __int64(*JT_HelpWithJobTypesOrSleep)(unsigned __int8(__fastcall* a1)(_QWORD), JobFifoLock_s* pFifoLock, __int64 a3, __int64 a4, volatile signed __int64* a5, char a6);
|
||||
|
||||
inline bool(*JT_AcquireFifoLockOrHelp)(struct JobFifoLock_s* pFifo);
|
||||
inline void(*JT_ReleaseFifoLock)(struct JobFifoLock_s* pFifo);
|
||||
|
||||
inline void(*JT_EndJobGroup)(const JobID_t jobId);
|
||||
inline unsigned int (*JT_AllocateJob)(); // Returns an index to the 'job_JT_Context' array
|
||||
inline JobID_t(*JTGuts_AddJob_Internal)(JobTypeID_t jobTypeId, JobID_t jobId, void* callbackfunc, void* callbackArg, int jobIndex, JobContext_s* context);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class VJobThread : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("JT_ParallelCall", JT_ParallelCall);
|
||||
|
||||
LogFunAdr("JT_HelpWithAnything", JT_HelpWithAnything);
|
||||
LogFunAdr("JT_AcquireFifoLock", JT_AcquireFifoLock);
|
||||
LogFunAdr("JT_HelpWithJobTypes", JT_HelpWithJobTypes);
|
||||
LogFunAdr("JT_HelpWithJobTypesOrSleep", JT_HelpWithJobTypesOrSleep);
|
||||
|
||||
LogFunAdr("JT_AcquireFifoLockOrHelp", JT_AcquireFifoLockOrHelp);
|
||||
LogFunAdr("JT_ReleaseFifoLock", JT_ReleaseFifoLock);
|
||||
|
||||
LogFunAdr("JT_EndJobGroup", JT_EndJobGroup);
|
||||
LogFunAdr("JT_AllocateJob", JT_AllocateJob);
|
||||
LogFunAdr("JTGuts_AddJob_Internal", JTGuts_AddJob_Internal);
|
||||
LogVarAdr("job_JT_Context", job_JT_Context);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 8B C4 48 89 58 08 48 89 78 10 55 48 8D 68 A1 48 81 EC ?? ?? ?? ?? 0F 29 70 E8 48 8D 1D ?? ?? ?? ??").GetPtr(JT_ParallelCall);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 80 3D ?? ?? ?? ?? ??").GetPtr(JT_HelpWithAnything);
|
||||
g_GameDll.FindPatternSIMD("48 83 EC 08 65 48 8B 04 25 ?? ?? ?? ?? 4C 8B C1").GetPtr(JT_AcquireFifoLock);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 4C 89 4C 24 ?? 4C 89 44 24 ?? 55 56 57 41 54 41 55 41 56 41 57 48 83 EC 60").GetPtr(JT_HelpWithJobTypes);
|
||||
g_GameDll.FindPatternSIMD("4C 89 4C 24 ?? 4C 89 44 24 ?? 48 89 54 24 ?? 48 89 4C 24 ?? 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 6C 24 ??").GetPtr(JT_HelpWithJobTypesOrSleep);
|
||||
g_GameDll.FindPatternSIMD("48 83 EC 08 65 48 8B 04 25 ?? ?? ?? ?? 4C 8B C1").GetPtr(JT_AcquireFifoLockOrHelp);
|
||||
g_GameDll.FindPatternSIMD("48 83 EC 28 44 8B 11").GetPtr(JT_ReleaseFifoLock);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 65 48 8B 04 25 ?? ?? ?? ?? BA ?? ?? ?? ??").GetPtr(JT_AllocateJob);
|
||||
g_GameDll.FindPatternSIMD("8B D1 48 8D 05 ?? ?? ?? ?? 81 E2 ?? ?? ?? ?? 48 C1 E2 06 48 03 D0 E9 ?? ?? ?? ??").GetPtr(JT_EndJobGroup);
|
||||
g_GameDll.FindPatternSIMD("48 89 74 24 ? 57 48 83 EC 20 0F B6 F1").GetPtr(JTGuts_AddJob_Internal);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
CMemory(JT_EndJobGroup).FindPattern("48 8D").ResolveRelativeAddressSelf(3, 7).GetPtr(job_JT_Context);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
|
@ -64,8 +64,10 @@ inline void ThreadPause()
|
||||
FORCEINLINE int32 ThreadInterlockedIncrement(int32 volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedIncrement((volatile long*)p); }
|
||||
FORCEINLINE int32 ThreadInterlockedDecrement(int32 volatile* p) { Assert((size_t)p % 4 == 0); return _InterlockedDecrement((volatile long*)p); }
|
||||
|
||||
FORCEINLINE int64 ThreadInterlockedIncrement64(int64 volatile* p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedIncrement64((volatile int64*)p); }
|
||||
FORCEINLINE int64 ThreadInterlockedDecrement64(int64 volatile* p) { AssertDbg((size_t)p % 8 == 0); return _InterlockedDecrement64((volatile int64*)p); }
|
||||
FORCEINLINE int64 ThreadInterlockedIncrement64(int64 volatile* p) { Assert((size_t)p % 8 == 0); return _InterlockedIncrement64((volatile int64*)p); }
|
||||
FORCEINLINE int64 ThreadInterlockedDecrement64(int64 volatile* p) { Assert((size_t)p % 8 == 0); return _InterlockedDecrement64((volatile int64*)p); }
|
||||
|
||||
FORCEINLINE int32 ThreadInterlockedExchangeAdd(int32 volatile* p, int32 value) { Assert((size_t)p % 4 == 0); return _InterlockedExchangeAdd((volatile long*)p, value); }
|
||||
|
||||
FORCEINLINE int32 ThreadInterlockedCompareExchange(LONG volatile* pDest, int32 value, int32 comperand)
|
||||
{
|
||||
|
@ -3,28 +3,51 @@ add_module( "lib" "rtech_game" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
|
||||
start_sources()
|
||||
|
||||
add_sources( SOURCE_GROUP "Private"
|
||||
"rtech_game.cpp"
|
||||
"rtech_game.h"
|
||||
add_sources( SOURCE_GROUP "Async"
|
||||
"async/asyncio.cpp"
|
||||
"async/asyncio.h"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Pak"
|
||||
"pak/pakparse.cpp"
|
||||
"pak/pakparse.h"
|
||||
|
||||
"pak/pakalloc.cpp"
|
||||
"pak/pakalloc.h"
|
||||
|
||||
"pak/pakdecode.cpp"
|
||||
"pak/pakdecode.h"
|
||||
|
||||
"pak/pakpatch.cpp"
|
||||
"pak/pakpatch.h"
|
||||
|
||||
"pak/pakstate.cpp"
|
||||
"pak/pakstate.h"
|
||||
|
||||
"pak/pakstream.cpp"
|
||||
"pak/pakstream.h"
|
||||
|
||||
"pak/paktools.cpp"
|
||||
"pak/paktools.h"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Public"
|
||||
"${ENGINE_SOURCE_DIR}/public/rtech/iasync.h"
|
||||
"${ENGINE_SOURCE_DIR}/public/rtech/ipakfile.h"
|
||||
)
|
||||
|
||||
end_sources()
|
||||
|
||||
add_module( "lib" "rtech_tools" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
add_module( "lib" "rson" "vpc" ${FOLDER_CONTEXT} TRUE TRUE )
|
||||
|
||||
start_sources()
|
||||
|
||||
add_sources( SOURCE_GROUP "Source"
|
||||
"rtech_utils.cpp"
|
||||
"rtech_utils.h"
|
||||
add_sources( SOURCE_GROUP "RSON"
|
||||
"rdf/rson.cpp"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Public"
|
||||
"${ENGINE_SOURCE_DIR}/public/rtech/ipakfile.h"
|
||||
"${ENGINE_SOURCE_DIR}/public/rtech/rson.h"
|
||||
)
|
||||
|
||||
end_sources()
|
||||
|
80
r5dev/rtech/async/asyncio.cpp
Normal file
80
r5dev/rtech/async/asyncio.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: async file loading, unloading and the management thereof
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "rtech/pak/paktools.h"
|
||||
#include "asyncio.h"
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// open a file and add it to the async file handle array
|
||||
//----------------------------------------------------------------------------------
|
||||
int FS_OpenAsyncFile(const char* const filePath, const int logLevel, size_t* const fileSizeOut)
|
||||
{
|
||||
const CHAR* fileToLoad = filePath;
|
||||
char overridePath[1024];
|
||||
|
||||
// is this a pak file and do we have an override
|
||||
if (strstr(fileToLoad, PLATFORM_PAK_PATH) &&
|
||||
Pak_GetOverride(fileToLoad, overridePath, sizeof(overridePath)))
|
||||
{
|
||||
fileToLoad = overridePath;
|
||||
}
|
||||
|
||||
const HANDLE hFile = CreateFileA(fileToLoad, GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, 0);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return FS_ASYNC_FILE_INVALID;
|
||||
|
||||
if (fileSizeOut)
|
||||
{
|
||||
// get the size of the file we just opened
|
||||
LARGE_INTEGER fileSize;
|
||||
|
||||
if (GetFileSizeEx(hFile, &fileSize))
|
||||
*fileSizeOut = fileSize.QuadPart;
|
||||
}
|
||||
|
||||
const int fileIdx = g_pAsyncFileSlotMgr->FindSlot();
|
||||
const int slotNum = (fileIdx & ASYNC_MAX_FILE_HANDLES_MASK);
|
||||
|
||||
AsyncHandleTracker_t& tracker = g_pAsyncFileSlots[slotNum];
|
||||
|
||||
tracker.m_nFileNumber = fileIdx;
|
||||
tracker.m_hFileHandle = hFile;
|
||||
tracker.m_nCurOfs = 1;
|
||||
|
||||
if (async_debug_level->GetInt() >= logLevel)
|
||||
Msg(eDLL_T::RTECH, "%s: Opened file: '%s' to slot #%d\n", __FUNCTION__, fileToLoad, slotNum);
|
||||
|
||||
return fileIdx;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// close a file and remove it from the async file handle array
|
||||
//----------------------------------------------------------------------------------
|
||||
void FS_CloseAsyncFile(const short fileHandle)
|
||||
{
|
||||
const int slotNum = fileHandle & ASYNC_MAX_FILE_HANDLES_MASK;
|
||||
AsyncHandleTracker_t& tracker = g_pAsyncFileSlots[slotNum];
|
||||
|
||||
if (ThreadInterlockedExchangeAdd(&tracker.m_nCurOfs, 0xFFFFFFFF) <= 1)
|
||||
{
|
||||
CloseHandle(tracker.m_hFileHandle);
|
||||
tracker.m_hFileHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
g_pAsyncFileSlotMgr->FreeSlot(slotNum);
|
||||
|
||||
if (async_debug_close->GetBool())
|
||||
Msg(eDLL_T::RTECH, "%s: Closed file from slot #%d\n", __FUNCTION__, slotNum);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
void V_AsyncIO::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&v_FS_OpenAsyncFile, &FS_OpenAsyncFile, bAttach);
|
||||
DetourSetup(&v_FS_CloseAsyncFile, &FS_CloseAsyncFile, bAttach);
|
||||
}
|
104
r5dev/rtech/async/asyncio.h
Normal file
104
r5dev/rtech/async/asyncio.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef RTECH_ASYNCIO_H
|
||||
#define RTECH_ASYNCIO_H
|
||||
#include "rtech/iasync.h"
|
||||
#include "rtech/rstdlib.h"
|
||||
|
||||
struct AsyncHandleTracker_t
|
||||
{
|
||||
int m_nFileNumber;
|
||||
int m_nCurOfs;
|
||||
HANDLE m_hFileHandle;
|
||||
};
|
||||
|
||||
struct AsyncHandleStatus_t
|
||||
{
|
||||
enum EStatus : uint8_t
|
||||
{
|
||||
// the file is still pending, or being read at this moment
|
||||
FS_ASYNC_PENDING = 0,
|
||||
|
||||
// the file is ready to be used
|
||||
FS_ASYNC_READY,
|
||||
|
||||
// there was an error while reading the file
|
||||
FS_ASYNC_ERROR,
|
||||
|
||||
// async read operations were canceled
|
||||
FS_ASYNC_CANCELLED
|
||||
};
|
||||
|
||||
int slot;
|
||||
int unk2;
|
||||
int unk3;
|
||||
int unk4;
|
||||
__int64 unk5;
|
||||
|
||||
// pointer to user defined data
|
||||
void* userData;
|
||||
|
||||
void* unkFunctionPointer;
|
||||
void* unkStatusPointer;
|
||||
int unk6;
|
||||
int unkFlag0;
|
||||
__int16 unkFlag2;
|
||||
__int16 unkFlag3;
|
||||
__int16 unk8;
|
||||
EStatus readStatus;
|
||||
};
|
||||
static_assert(sizeof(AsyncHandleStatus_t) == 0x40);
|
||||
|
||||
extern int FS_OpenAsyncFile(const char* const filePath, const int logLevel, size_t* const fileSizeOut);
|
||||
extern void FS_CloseAsyncFile(const short fileHandle);
|
||||
|
||||
inline int(*v_FS_OpenAsyncFile)(const char* const filePath, const int logLevel, size_t* const outFileSize);
|
||||
inline void(*v_FS_CloseAsyncFile)(short fileHandle);
|
||||
|
||||
inline int(*v_FS_ReadAsyncFile)(int a1, __int64 a2, unsigned __int64 a3, void* a4, void* a5, void* a6, int a7);
|
||||
inline uint8_t(*v_FS_CheckAsyncRequest)(AsyncHandleStatus_t* pakStatus, size_t* bytesProcessed, const char** stateString);
|
||||
|
||||
inline AsyncHandleTracker_t* g_pAsyncFileSlots; // bufSize=1024*sizeof(FileHandleTracker_t).
|
||||
inline RHashMap_MT* g_pAsyncFileSlotMgr; // Manages 'g_pakFileSlots'.
|
||||
inline AsyncHandleStatus_t* g_pAsyncStatusSlots; // bufSize=256*sizeof(PakStatus_t).
|
||||
inline RHashMap_MT* g_pAsyncStatusSlotMgr; // Manages 'g_pakStatusSlots'.
|
||||
|
||||
class V_AsyncIO : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("FS_OpenAsyncFile", v_FS_OpenAsyncFile);
|
||||
LogFunAdr("FS_CloseAsyncFile", v_FS_CloseAsyncFile);
|
||||
|
||||
LogFunAdr("FS_ReadAsyncFile", v_FS_ReadAsyncFile);
|
||||
LogFunAdr("FS_CheckAsyncRequest", v_FS_CheckAsyncRequest);
|
||||
|
||||
LogVarAdr("g_asyncFileSlots", g_pAsyncFileSlots);
|
||||
LogVarAdr("g_asyncFileSlotMgr", g_pAsyncFileSlotMgr);
|
||||
|
||||
LogVarAdr("g_asyncStatusSlots", g_pAsyncStatusSlots);
|
||||
LogVarAdr("g_asyncStatusSlotMgr", g_pAsyncStatusSlotMgr);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 85 08 01 ?? ??").FollowNearCallSelf().GetPtr(v_FS_OpenAsyncFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B D9 48 8D 35 ?? ?? ?? ??").GetPtr(v_FS_CloseAsyncFile);
|
||||
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 4C 89 64 24 ?? 41 55 41 56 41 57 48 83 EC 20 8B C1").GetPtr(v_FS_ReadAsyncFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 0F B6 79").GetPtr(v_FS_CheckAsyncRequest);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
extern void(*v_StreamDB_Init)(const char* const pszLevelName);
|
||||
const CMemory streamDbBase(v_StreamDB_Init);
|
||||
|
||||
g_pAsyncFileSlots = streamDbBase.Offset(0x70).FindPatternSelf("4C 8D", CMemory::Direction::DOWN, 512, 1).ResolveRelativeAddress(0x3, 0x7).RCast<AsyncHandleTracker_t*>();
|
||||
g_pAsyncFileSlotMgr = streamDbBase.Offset(0x70).FindPatternSelf("48 8D 0D", CMemory::Direction::DOWN, 512, 2).ResolveRelativeAddress(0x3, 0x7).RCast<RHashMap_MT*>();
|
||||
|
||||
g_pAsyncStatusSlots = g_GameDll.FindPatternSIMD("0F B6 C9 48 8D 05 ?? ?? ?? ??").FindPatternSelf("48 8D 05").ResolveRelativeAddress(0x3, 0x7).RCast<AsyncHandleStatus_t*>();
|
||||
g_pAsyncStatusSlotMgr = streamDbBase.Offset(0x190).FindPatternSelf("48 8D 0D", CMemory::Direction::DOWN, 512, 2).ResolveRelativeAddress(0x3, 0x7).RCast<RHashMap_MT*>();
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
|
||||
|
||||
#endif // !ASYNCIO_H
|
109
r5dev/rtech/pak/pakalloc.cpp
Normal file
109
r5dev/rtech/pak/pakalloc.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: pak page allocation and alignment
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstate.h"
|
||||
#include "pakalloc.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// aligns the segment headers for each asset type
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_AlignSegmentHeaders(PakFile_t* const pak, PakSegmentDescriptor_t* const desc)
|
||||
{
|
||||
uint64_t headersSize = 0;
|
||||
uint8_t headerSegmentAlignment = static_cast<int8_t>(desc->segmentAlignmentForType[SF_HEAD]);
|
||||
|
||||
for (uint8_t i = 0; i < PAK_MAX_TYPES; ++i)
|
||||
{
|
||||
const PakAssetBinding_t& binding = g_pPakGlobals->m_assetBindings[i];
|
||||
|
||||
if (desc->assetTypeCount[i])
|
||||
{
|
||||
// asset header alignment really shouldn't be above 255
|
||||
// if this needs raising, headerSegmentAlignment should be made wider
|
||||
assert(binding.headerAlignment <= UINT8_MAX);
|
||||
|
||||
const size_t alignedSize = ALIGN_VALUE(headersSize, static_cast<size_t>(binding.headerAlignment));
|
||||
|
||||
pak->memoryData.unkAssetTypeBindingSizes[i] = alignedSize;
|
||||
headersSize = alignedSize + (desc->assetTypeCount[i] * binding.nativeClassSize);
|
||||
|
||||
desc->segmentSizeForType[SF_HEAD] = headersSize;
|
||||
|
||||
headerSegmentAlignment = static_cast<uint8_t>(max(headerSegmentAlignment, binding.headerAlignment));
|
||||
desc->segmentAlignmentForType[SF_HEAD] = headerSegmentAlignment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// aligns each individual non-header segment
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_AlignSegments(PakFile_t* const pak, PakSegmentDescriptor_t* const desc)
|
||||
{
|
||||
for (uint16_t i = 0; i < pak->GetSegmentCount(); ++i)
|
||||
{
|
||||
const PakSegmentHeader_t* const segHeader = pak->GetSegmentHeader(i);
|
||||
|
||||
const uint8_t segmentType = segHeader->typeFlags & (SF_TEMP | SF_CPU);
|
||||
|
||||
if (segmentType != SF_HEAD) // if not a header segment
|
||||
{
|
||||
// should this be a hard error on release?
|
||||
// segment alignment must not be 0 and must be a power of two
|
||||
assert(segHeader->dataAlignment > 0 && IsPowerOfTwo(segHeader->dataAlignment));
|
||||
|
||||
const size_t alignedSegmentSize = ALIGN_VALUE(desc->segmentSizeForType[segmentType], static_cast<size_t>(segHeader->dataAlignment));
|
||||
//const size_t sizeAligned = ~(m_align - 1) & (m_align - 1 + segmentSizeForType[segmentType]);
|
||||
|
||||
desc->segmentSizes[i] = alignedSegmentSize;
|
||||
desc->segmentSizeForType[segmentType] = alignedSegmentSize + segHeader->dataSize;
|
||||
|
||||
// check if this segment's alignment is higher than the previous highest for this type
|
||||
// if so, increase the alignment to accommodate this segment
|
||||
desc->segmentAlignmentForType[segmentType] = max(desc->segmentAlignmentForType[segmentType], segHeader->dataAlignment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// copy's pages into pre-allocated and aligned segments
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_CopyPagesToSegments(PakFile_t* const pak, PakLoadedInfo_t* const loadedInfo, PakSegmentDescriptor_t* const desc)
|
||||
{
|
||||
for (uint32_t i = 0; i < pak->GetPageCount(); ++i)
|
||||
{
|
||||
const PakPageHeader_t* const pageHeader = pak->GetPageHeader(i);
|
||||
const uint32_t segmentIndex = pageHeader->segmentIdx;
|
||||
|
||||
const PakSegmentHeader_t* const segHeader = pak->GetSegmentHeader(segmentIndex);
|
||||
const int typeFlags = segHeader->typeFlags;
|
||||
|
||||
// check if header page
|
||||
if ((typeFlags & (SF_TEMP | SF_CPU)) != 0)
|
||||
{
|
||||
// align the segment's current size to the alignment of the new page to get copied in
|
||||
// this ensures that the location holding the page is aligned as required
|
||||
//
|
||||
// since the segment will always have alignment equal to or greater than the page, and that alignment will always be a power of 2
|
||||
// the page does not have to be aligned to the same alignment as the segment, as aligning it to its own alignment is sufficient as long as
|
||||
// every subsequent page does the same thing
|
||||
const size_t alignedSegmentSize = ALIGN_VALUE(desc->segmentSizes[segmentIndex], static_cast<size_t>(pageHeader->pageAlignment));
|
||||
|
||||
// get a pointer to the newly aligned location within the segment for this page
|
||||
pak->memoryData.memPageBuffers[i] = reinterpret_cast<uint8_t*>(loadedInfo->segmentBuffers[typeFlags & (SF_TEMP | SF_CPU)]) + alignedSegmentSize;
|
||||
|
||||
// update the segment size to reflect the new alignment and page size
|
||||
desc->segmentSizes[segmentIndex] = alignedSegmentSize + pak->memoryData.pageHeaders[i].dataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
// all headers go into one segment and are dealt with separately in Pak_ProcessPakFile
|
||||
// since headers must be copied individually into a buffer that is big enough for the "native class" version of the header
|
||||
// instead of just the file version
|
||||
pak->memoryData.memPageBuffers[i] = reinterpret_cast<uint8_t*>(loadedInfo->segmentBuffers[SF_HEAD]);
|
||||
}
|
||||
}
|
||||
}
|
28
r5dev/rtech/pak/pakalloc.h
Normal file
28
r5dev/rtech/pak/pakalloc.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef RTECH_PAKALLOC_H
|
||||
#define RTECH_PAKALLOC_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
extern void Pak_AlignSegmentHeaders(PakFile_t* const pak, PakSegmentDescriptor_t* const desc);
|
||||
extern void Pak_AlignSegments(PakFile_t* const pak, PakSegmentDescriptor_t* const desc);
|
||||
extern void Pak_CopyPagesToSegments(PakFile_t* const pak, PakLoadedInfo_t* const loadedInfo, PakSegmentDescriptor_t* const desc);
|
||||
|
||||
// something with sorting pages?
|
||||
inline void (*sub_140442740)(PakAsset_t** assetEntries, PakAsset_t** assetEntry, __int64 idx, PakFile_t* pak);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_PakAlloc : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 56 57 41 54 41 56 41 57 48 83 EC 40 48 8B C2 49 8B D9").GetPtr(sub_140442740);
|
||||
}
|
||||
virtual void GetVar(void) const { }
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { };
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // RTECH_PAKALLOC_H
|
557
r5dev/rtech/pak/pakdecode.cpp
Normal file
557
r5dev/rtech/pak/pakdecode.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: decoder initialization and pak decoding
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakdecode.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// lookup table for default pak decoder
|
||||
//-----------------------------------------------------------------------------
|
||||
static const unsigned char /*141313180*/ s_defaultDecoderLUT[] =
|
||||
{
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0B,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0xF7,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF3,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0E,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0x09,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF1,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0D,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0xF7,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF2,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0F,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0x0A,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF0,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0C,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x09,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0E,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0B,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0A,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x10,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0C,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x09,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0F,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0D,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0A,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0xFF,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x07,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x07,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0B,
|
||||
0x00, 0x08, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x09, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E,
|
||||
0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x0D,
|
||||
0x00, 0x08, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0F,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x4A, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00,
|
||||
0xCA, 0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x2A, 0x01, 0x00, 0x00,
|
||||
0x4A, 0x01, 0x00, 0x00, 0x6A, 0x01, 0x00, 0x00, 0x8A, 0x01, 0x00, 0x00, 0xAA, 0x01, 0x00, 0x00,
|
||||
0xAA, 0x03, 0x00, 0x00, 0xAA, 0x05, 0x00, 0x00, 0xAA, 0x25, 0x00, 0x00, 0xAA, 0x25, 0x02, 0x00,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x09, 0x09, 0x0D, 0x11, 0x15,
|
||||
0x00, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x2A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05,
|
||||
0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF,
|
||||
0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE,
|
||||
0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C,
|
||||
0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37,
|
||||
0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xF1, 0x1D, 0xC1, 0xF6, 0x7F, 0x00, 0x00,
|
||||
0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA,
|
||||
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37,
|
||||
0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0,
|
||||
0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA,
|
||||
0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6,
|
||||
0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D,
|
||||
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF,
|
||||
0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE,
|
||||
0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C,
|
||||
0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F,
|
||||
0x4C, 0x39, 0x56, 0x75, 0x42, 0x52, 0x65, 0x75, 0x70, 0x35, 0x31, 0x77, 0x4C, 0x51, 0x64, 0x61,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// initialize standard pak decoder context
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t Pak_InitDefaultDecoder(PakDecoder_t* const decoder, const uint8_t* const fileBuffer,
|
||||
const uint64_t inputMask, const size_t dataSize, const size_t dataOffset, const size_t headerSize)
|
||||
{
|
||||
uint64_t v8; // r9
|
||||
unsigned __int64 v9; // r11
|
||||
unsigned __int64 v10; // r8
|
||||
int v11; // er8
|
||||
__int64 v12; // rbx
|
||||
unsigned int v13; // ebp
|
||||
unsigned __int64 v14; // rbx
|
||||
uint64_t v15; // rax
|
||||
unsigned int v16; // er9
|
||||
unsigned __int64 v17; // r12
|
||||
unsigned __int64 v18; // r11
|
||||
unsigned __int64 v19; // r10
|
||||
unsigned __int64 v20; // rax
|
||||
int v21; // ebp
|
||||
unsigned __int64 v22; // r10
|
||||
unsigned int v23; // er9
|
||||
uint64_t v24; // rax
|
||||
__int64 v25; // rsi
|
||||
uint64_t v26; // rdx
|
||||
size_t result; // rax
|
||||
uint64_t v28; // rdx
|
||||
|
||||
decoder->inputBuf = fileBuffer;
|
||||
decoder->fileSize = dataOffset + dataSize;
|
||||
decoder->outputBuf = nullptr;
|
||||
decoder->outputMask = NULL;
|
||||
decoder->dword44 = NULL;
|
||||
decoder->inputMask = inputMask;
|
||||
|
||||
v8 = dataOffset + headerSize + 8;
|
||||
v9 = *(_QWORD*)((inputMask & (dataOffset + headerSize)) + fileBuffer);
|
||||
|
||||
decoder->outBufBytePos = headerSize;
|
||||
decoder->inBufBytePos = v8;
|
||||
|
||||
v10 = v9;
|
||||
v9 >>= 6;
|
||||
v11 = v10 & 0x3F;
|
||||
decoder->decompSize = (1i64 << v11) | v9 & ((1i64 << v11) - 1);
|
||||
v12 = *(_QWORD*)((inputMask & v8) + fileBuffer) << (64 - ((unsigned __int8)v11 + 6));
|
||||
decoder->inBufBytePos = v8 + ((unsigned __int64)(unsigned int)(v11 + 6) >> 3);
|
||||
v13 = ((v11 + 6) & 7) + 13;
|
||||
v14 = (0xFFFFFFFFFFFFFFFFui64 >> ((v11 + 6) & 7)) & ((v9 >> v11) | v12);
|
||||
v15 = inputMask & decoder->inBufBytePos;
|
||||
v16 = (((_BYTE)v14 - 1) & 0x3F) + 1;
|
||||
v17 = 0xFFFFFFFFFFFFFFFFui64 >> (64 - (unsigned __int8)v16);
|
||||
decoder->inputInvMask = v17;
|
||||
v18 = 0xFFFFFFFFFFFFFFFFui64 >> (64 - ((((v14 >> 6) - 1) & 0x3F) + 1));
|
||||
decoder->outputInvMask = v18;
|
||||
v19 = (v14 >> 13) | (*(_QWORD*)(v15 + fileBuffer) << (64 - (unsigned __int8)v13));
|
||||
v20 = v13;
|
||||
v21 = v13 & 7;
|
||||
decoder->inBufBytePos += v20 >> 3;
|
||||
v22 = (0xFFFFFFFFFFFFFFFFui64 >> v21) & v19;
|
||||
|
||||
if (v17 == -1i64)
|
||||
{
|
||||
decoder->headerOffset = 0;
|
||||
decoder->bufferSizeNeeded = dataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
v23 = v16 >> 3;
|
||||
v24 = inputMask & decoder->inBufBytePos;
|
||||
decoder->headerOffset = v23 + 1;
|
||||
v25 = *(_QWORD*)(v24 + fileBuffer) & ((1i64 << (8 * ((unsigned __int8)v23 + 1))) - 1);
|
||||
decoder->inBufBytePos += v23 + 1;
|
||||
decoder->bufferSizeNeeded = v25;
|
||||
}
|
||||
|
||||
decoder->bufferSizeNeeded += dataOffset;
|
||||
v26 = decoder->bufferSizeNeeded;
|
||||
decoder->currentByte = v22;
|
||||
decoder->currentBit = v21;
|
||||
decoder->qword70 = v17 + dataOffset - 6;
|
||||
result = decoder->decompSize;
|
||||
decoder->dword6C = 0;
|
||||
decoder->compressedStreamSize = v26;
|
||||
decoder->decompStreamSize = result;
|
||||
|
||||
if ((((unsigned __int8)(v14 >> 6) - 1) & 0x3F) != -1i64 && result - 1 > v18)
|
||||
{
|
||||
v28 = v26 - decoder->headerOffset;
|
||||
decoder->decompStreamSize = v18 + 1;
|
||||
decoder->compressedStreamSize = v28;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// decode input pak data
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_DefaultDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen)
|
||||
{
|
||||
char result; // al
|
||||
uint64_t m_decompBytePosition; // r15
|
||||
uint8_t* m_outputBuf; // r11
|
||||
uint32_t m_currentBit; // ebp
|
||||
uint64_t m_currentByte; // rsi
|
||||
uint64_t m_fileBytePosition; // rdi
|
||||
size_t qword70; // r12
|
||||
const uint8_t* m_inputBuf; // r13
|
||||
uint32_t dword6C; // ecx
|
||||
uint64_t v13; // rsi
|
||||
unsigned __int64 i; // rax
|
||||
unsigned __int64 v15; // r8
|
||||
__int64 v16; // r9
|
||||
int v17; // ecx
|
||||
unsigned __int64 v18; // rax
|
||||
uint64_t v19; // rsi
|
||||
__int64 v20; // r14
|
||||
int v21; // ecx
|
||||
unsigned __int64 v22; // r11
|
||||
int v23; // edx
|
||||
uint64_t m_outputMask; // rax
|
||||
int v25; // r8d
|
||||
unsigned int v26; // r13d
|
||||
uint64_t v27; // r10
|
||||
uint8_t* v28; // rax
|
||||
uint8_t* v29; // r10
|
||||
size_t m_decompSize; // r9
|
||||
uint64_t m_inputInvMask; // r10
|
||||
uint64_t m_headerOffset; // r8
|
||||
uint64_t v33; // rax
|
||||
uint64_t v34; // rax
|
||||
uint64_t v35; // rax
|
||||
size_t v36; // rcx
|
||||
__int64 v37; // rdx
|
||||
size_t v38; // r14
|
||||
size_t v39; // r11
|
||||
uint64_t v40; // cl
|
||||
uint64_t v41; // rsi
|
||||
__int64 v42; // rcx
|
||||
uint64_t v43; // r8
|
||||
int v44; // r11d
|
||||
unsigned __int8 v45; // r9
|
||||
uint64_t v46; // rcx
|
||||
uint64_t v47; // rcx
|
||||
__int64 v48; // r9
|
||||
__int64 m; // r8
|
||||
__int64 v50; // r9d
|
||||
__int64 v51; // r8
|
||||
__int64 v52; // rdx
|
||||
__int64 k; // r8
|
||||
signed __int64 v54; // r10
|
||||
__int64 v55; // rdx
|
||||
unsigned int v56; // r14d
|
||||
const uint8_t* v57; // rdx
|
||||
uint8_t* v58; // r8
|
||||
uint64_t v59; // al
|
||||
uint64_t v60; // rsi
|
||||
__int64 v61; // rax
|
||||
uint64_t v62; // r9
|
||||
int v63; // r10d
|
||||
unsigned __int8 v64; // cl
|
||||
uint64_t v65; // rax
|
||||
unsigned int v66; // r14d
|
||||
unsigned int j; // ecx
|
||||
__int64 v68; // rax
|
||||
uint64_t v69; // rcx
|
||||
uint8_t* v70; // [rsp+0h] [rbp-58h]
|
||||
uint32_t v71; // [rsp+60h] [rbp+8h]
|
||||
const uint8_t* v74; // [rsp+78h] [rbp+20h]
|
||||
|
||||
if (inLen < decoder->bufferSizeNeeded)
|
||||
return false;
|
||||
|
||||
m_decompBytePosition = decoder->outBufBytePos;
|
||||
|
||||
if (outLen < decoder->outputInvMask + (m_decompBytePosition & ~decoder->outputInvMask) + 1 && outLen < decoder->decompSize)
|
||||
return false;
|
||||
|
||||
m_outputBuf = decoder->outputBuf;
|
||||
m_currentBit = decoder->currentBit;
|
||||
m_currentByte = decoder->currentByte;
|
||||
m_fileBytePosition = decoder->inBufBytePos;
|
||||
qword70 = decoder->qword70;
|
||||
m_inputBuf = decoder->inputBuf;
|
||||
|
||||
if (decoder->compressedStreamSize < qword70)
|
||||
qword70 = decoder->compressedStreamSize;
|
||||
|
||||
dword6C = decoder->dword6C;
|
||||
v74 = m_inputBuf;
|
||||
v70 = m_outputBuf;
|
||||
v71 = dword6C;
|
||||
if (!m_currentBit)
|
||||
goto LABEL_11;
|
||||
|
||||
v13 = (*(_QWORD*)&m_inputBuf[m_fileBytePosition & decoder->inputMask] << (64 - (unsigned __int8)m_currentBit)) | m_currentByte;
|
||||
for (i = m_currentBit; ; i = m_currentBit)
|
||||
{
|
||||
m_currentBit &= 7u;
|
||||
m_fileBytePosition += i >> 3;
|
||||
dword6C = v71;
|
||||
m_currentByte = (0xFFFFFFFFFFFFFFFFui64 >> m_currentBit) & v13;
|
||||
LABEL_11:
|
||||
v15 = (unsigned __int64)dword6C << 8;
|
||||
v16 = dword6C;
|
||||
v17 = s_defaultDecoderLUT[(unsigned __int8)m_currentByte + 512 + v15];
|
||||
v18 = (unsigned __int8)m_currentByte + v15;
|
||||
m_currentBit += v17;
|
||||
v19 = m_currentByte >> v17;
|
||||
v20 = (unsigned int)(char)s_defaultDecoderLUT[v18];
|
||||
if ((s_defaultDecoderLUT[v18] & 0x80u) != 0)
|
||||
{
|
||||
v56 = -(int)v20;
|
||||
v57 = &m_inputBuf[m_fileBytePosition & decoder->inputMask];
|
||||
v71 = 1;
|
||||
v58 = &m_outputBuf[m_decompBytePosition & decoder->outputMask];
|
||||
if (v56 == s_defaultDecoderLUT[v16 + 1248])
|
||||
{
|
||||
if ((~m_fileBytePosition & decoder->inputInvMask) < 0xF || (decoder->outputInvMask & ~m_decompBytePosition) < 15 || decoder->decompSize - m_decompBytePosition < 0x10)
|
||||
v56 = 1;
|
||||
v59 = v19;
|
||||
v60 = v19 >> 3;
|
||||
v61 = v59 & 7;
|
||||
v62 = v60;
|
||||
if (v61)
|
||||
{
|
||||
v63 = s_defaultDecoderLUT[v61 + 1232];
|
||||
v64 = s_defaultDecoderLUT[v61 + 1240];
|
||||
}
|
||||
else
|
||||
{
|
||||
v62 = v60 >> 4;
|
||||
v65 = v60 & 0xF;
|
||||
m_currentBit += 4;
|
||||
v63 = *(_DWORD*)&s_defaultDecoderLUT[4 * v65 + 1152];
|
||||
v64 = s_defaultDecoderLUT[v65 + 1216];
|
||||
}
|
||||
m_currentBit += v64 + 3;
|
||||
v19 = v62 >> v64;
|
||||
v66 = v63 + (v62 & ((1 << v64) - 1)) + v56;
|
||||
for (j = v66 >> 3; j; --j)
|
||||
{
|
||||
v68 = *(_QWORD*)v57;
|
||||
v57 += 8;
|
||||
*(_QWORD*)v58 = v68;
|
||||
v58 += 8;
|
||||
}
|
||||
if ((v66 & 4) != 0)
|
||||
{
|
||||
*(_DWORD*)v58 = *(_DWORD*)v57;
|
||||
v58 += 4;
|
||||
v57 += 4;
|
||||
}
|
||||
if ((v66 & 2) != 0)
|
||||
{
|
||||
*(_WORD*)v58 = *(_WORD*)v57;
|
||||
v58 += 2;
|
||||
v57 += 2;
|
||||
}
|
||||
if ((v66 & 1) != 0)
|
||||
*v58 = *v57;
|
||||
m_fileBytePosition += v66;
|
||||
m_decompBytePosition += v66;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(_QWORD*)v58 = *(_QWORD*)v57;
|
||||
*((_QWORD*)v58 + 1) = *((_QWORD*)v57 + 1);
|
||||
m_fileBytePosition += v56;
|
||||
m_decompBytePosition += 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)));
|
||||
m_currentBit += (((unsigned int)(v21 - 31) >> 3) & 6) + s_defaultDecoderLUT[v22 + 1088] + v21 + ((v19 >> 4) & ((24 * (((unsigned int)(v21 - 31) >> 3) & 2)) >> 4));
|
||||
m_outputMask = decoder->outputMask;
|
||||
v25 = 16 * (v23 + ((v23 - 1) & (v19 >> ((((unsigned int)(v21 - 31) >> 3) & 6) + s_defaultDecoderLUT[v22 + 1088]))));
|
||||
v19 >>= (((unsigned int)(v21 - 31) >> 3) & 6) + s_defaultDecoderLUT[v22 + 1088] + v21 + ((v19 >> 4) & ((24 * (((unsigned int)(v21 - 31) >> 3) & 2)) >> 4));
|
||||
v26 = v25 + s_defaultDecoderLUT[v22 + 1024] - 16;
|
||||
v27 = m_outputMask & (m_decompBytePosition - v26);
|
||||
v28 = &v70[m_decompBytePosition & m_outputMask];
|
||||
v29 = &v70[v27];
|
||||
if ((_DWORD)v20 == 17)
|
||||
{
|
||||
v40 = v19;
|
||||
v41 = v19 >> 3;
|
||||
v42 = v40 & 7;
|
||||
v43 = v41;
|
||||
if (v42)
|
||||
{
|
||||
v44 = s_defaultDecoderLUT[v42 + 1232];
|
||||
v45 = s_defaultDecoderLUT[v42 + 1240];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentBit += 4;
|
||||
v46 = v41 & 0xF;
|
||||
v43 = v41 >> 4;
|
||||
v44 = *(_DWORD*)&s_defaultDecoderLUT[4 * v46 + 1152];
|
||||
v45 = s_defaultDecoderLUT[v46 + 1216];
|
||||
if (v74 && m_currentBit + v45 >= 61)
|
||||
{
|
||||
v47 = m_fileBytePosition++ & decoder->inputMask;
|
||||
v43 |= (unsigned __int64)v74[v47] << (61 - (unsigned __int8)m_currentBit);
|
||||
m_currentBit -= 8;
|
||||
}
|
||||
}
|
||||
m_currentBit += v45 + 3;
|
||||
v19 = v43 >> v45;
|
||||
v48 = ((unsigned int)v43 & ((1 << v45) - 1)) + v44 + 17;
|
||||
m_decompBytePosition += v48;
|
||||
if (v26 < 8)
|
||||
{
|
||||
v50 = v48 - 13;
|
||||
m_decompBytePosition -= 13i64;
|
||||
if (v26 == 1)
|
||||
{
|
||||
v51 = *v29;
|
||||
//++dword_14D40B2BC;
|
||||
v52 = 0i64;
|
||||
for (k = 0x101010101010101i64 * v51; (unsigned int)v52 < v50; v52 = (unsigned int)(v52 + 8))
|
||||
*(_QWORD*)&v28[v52] = k;
|
||||
}
|
||||
else
|
||||
{
|
||||
//++dword_14D40B2B8;
|
||||
if (v50)
|
||||
{
|
||||
v54 = v29 - v28;
|
||||
v55 = v50;
|
||||
do
|
||||
{
|
||||
*v28 = v28[v54];
|
||||
++v28;
|
||||
--v55;
|
||||
} while (v55);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//++dword_14D40B2AC;
|
||||
for (m = 0i64; (unsigned int)m < (unsigned int)v48; m = (unsigned int)(m + 8))
|
||||
*(_QWORD*)&v28[m] = *(_QWORD*)&v29[m];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_decompBytePosition += v20;
|
||||
*(_QWORD*)v28 = *(_QWORD*)v29;
|
||||
*((_QWORD*)v28 + 1) = *((_QWORD*)v29 + 1);
|
||||
}
|
||||
m_inputBuf = v74;
|
||||
}
|
||||
if (m_fileBytePosition >= qword70)
|
||||
break;
|
||||
LABEL_29:
|
||||
m_outputBuf = v70;
|
||||
v13 = (*(_QWORD*)&m_inputBuf[m_fileBytePosition & decoder->inputMask] << (64 - (unsigned __int8)m_currentBit)) | v19;
|
||||
}
|
||||
if (m_decompBytePosition != decoder->decompStreamSize)
|
||||
goto LABEL_25;
|
||||
m_decompSize = decoder->decompSize;
|
||||
if (m_decompBytePosition == m_decompSize)
|
||||
{
|
||||
result = 1;
|
||||
goto LABEL_69;
|
||||
}
|
||||
m_inputInvMask = decoder->inputInvMask;
|
||||
m_headerOffset = decoder->headerOffset;
|
||||
v33 = m_inputInvMask & -(__int64)m_fileBytePosition;
|
||||
v19 >>= 1;
|
||||
++m_currentBit;
|
||||
if (m_headerOffset > v33)
|
||||
{
|
||||
m_fileBytePosition += v33;
|
||||
v34 = decoder->qword70;
|
||||
if (m_fileBytePosition > v34)
|
||||
decoder->qword70 = m_inputInvMask + v34 + 1;
|
||||
}
|
||||
v35 = m_fileBytePosition & decoder->inputMask;
|
||||
m_fileBytePosition += m_headerOffset;
|
||||
v36 = m_decompBytePosition + decoder->outputInvMask + 1;
|
||||
v37 = *(_QWORD*)&m_inputBuf[v35] & ((1i64 << (8 * (unsigned __int8)m_headerOffset)) - 1);
|
||||
v38 = v37 + decoder->bufferSizeNeeded;
|
||||
v39 = v37 + decoder->compressedStreamSize;
|
||||
decoder->bufferSizeNeeded = v38;
|
||||
decoder->compressedStreamSize = v39;
|
||||
if (v36 >= m_decompSize)
|
||||
{
|
||||
v36 = m_decompSize;
|
||||
decoder->compressedStreamSize = m_headerOffset + v39;
|
||||
}
|
||||
decoder->decompStreamSize = v36;
|
||||
if (inLen >= v38 && outLen >= v36)
|
||||
{
|
||||
LABEL_25:
|
||||
qword70 = decoder->qword70;
|
||||
if (m_fileBytePosition >= qword70)
|
||||
{
|
||||
m_fileBytePosition = ~decoder->inputInvMask & (m_fileBytePosition + 7);
|
||||
qword70 += decoder->inputInvMask + 1;
|
||||
decoder->qword70 = qword70;
|
||||
}
|
||||
if (decoder->compressedStreamSize < qword70)
|
||||
qword70 = decoder->compressedStreamSize;
|
||||
goto LABEL_29;
|
||||
}
|
||||
v69 = decoder->qword70;
|
||||
if (m_fileBytePosition >= v69)
|
||||
{
|
||||
m_fileBytePosition = ~m_inputInvMask & (m_fileBytePosition + 7);
|
||||
decoder->qword70 = v69 + m_inputInvMask + 1;
|
||||
}
|
||||
decoder->dword6C = v71;
|
||||
result = 0;
|
||||
decoder->currentByte = v19;
|
||||
decoder->currentBit = m_currentBit;
|
||||
LABEL_69:
|
||||
decoder->outBufBytePos = m_decompBytePosition;
|
||||
decoder->inBufBytePos = m_fileBytePosition;
|
||||
return result;
|
||||
}
|
10
r5dev/rtech/pak/pakdecode.h
Normal file
10
r5dev/rtech/pak/pakdecode.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef RTECH_PAKDECODE_H
|
||||
#define RTECH_PAKDECODE_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
extern size_t Pak_InitDefaultDecoder(PakDecoder_t* const decoder, const uint8_t* const fileBuffer,
|
||||
const uint64_t inputMask, const size_t dataSize, const size_t dataOffset, const size_t headerSize);
|
||||
|
||||
extern bool Pak_DefaultDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen);
|
||||
|
||||
#endif // RTECH_PAKDECODE_H
|
936
r5dev/rtech/pak/pakparse.cpp
Normal file
936
r5dev/rtech/pak/pakparse.cpp
Normal file
@ -0,0 +1,936 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// 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"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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_pPakGlobals->m_assets[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];
|
||||
volatile uint32_t* v5 = reinterpret_cast<volatile uint32_t*>(*(reinterpret_cast<uint64_t*>(g_pPakGlobals) + 0x17 * (pak->memoryData.pakId & PAK_MAX_HANDLES_MASK) + 0x160212));
|
||||
|
||||
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_pPakGlobals->m_assets[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"
|
||||
"current: '0x%llX'\n",
|
||||
i, asset->dependenciesCount,
|
||||
pak->memoryData.fileName,
|
||||
asset->guid,
|
||||
targetGuid,
|
||||
currentGuid);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
currentIndex = pak->memoryData.qword2E0[a];
|
||||
}
|
||||
}
|
||||
|
||||
// finally write the pointer to the guid entry
|
||||
*pCurrentGuid = g_pPakGlobals->m_assets[currentIndex].m_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 __fastcall Rebuild_14043E030(PakFile_t* const pak)
|
||||
{
|
||||
__int64 numAssets; // rsi
|
||||
PakAsset_t* pakAsset; // rdi
|
||||
__int64 _numAssets; // r14
|
||||
unsigned int assetBind; // ebp
|
||||
__int64 v13; // rcx
|
||||
__int64 qword2D8_low; // rdi
|
||||
JobID_t qword2D8_high; // ebp
|
||||
JobTypeID_t v16; // si
|
||||
|
||||
pak->numProcessedPointers = Pak_ProcessRemainingPagePointers(pak);
|
||||
|
||||
numAssets = (unsigned int)pak->processedAssetCount;
|
||||
if ((_DWORD)numAssets != pak->memoryData.pakHeader.assetCount)
|
||||
{
|
||||
pakAsset = &pak->memoryData.assetEntries[numAssets];
|
||||
_numAssets = (unsigned int)numAssets;
|
||||
if ((int)pakAsset->pageEnd <= pak->processedPageCount)
|
||||
{
|
||||
while ((unsigned __int16)*word_167ED7BDE <= 0xC8u)
|
||||
{
|
||||
assetBind = pakAsset->HashTableIndexForAssetType();
|
||||
pak->memoryData.qword2E0[_numAssets] = (int)sub_14043D3C0(pak, pakAsset);
|
||||
_InterlockedIncrement16(word_167ED7BDE);
|
||||
v13 = assetBind;
|
||||
if (g_pPakGlobals->m_assetBindings[(unsigned __int64)assetBind].loadAssetFunc)
|
||||
{
|
||||
qword2D8_low = pak->memoryData.pakId;
|
||||
qword2D8_high = pak->memoryData.unkJobID;
|
||||
v16 = *((_BYTE*)&*g_pPakGlobals + v13 + 13207872);
|
||||
|
||||
JTGuts_AddJob(v16, qword2D8_high, (void*)qword2D8_low, (void*)_numAssets);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_InterlockedExchangeAdd16((volatile signed __int16*)&pakAsset->numRemainingDependencies, 0xFFFFu) == 1)
|
||||
sub_14043D150(pak, pakAsset, (unsigned int)numAssets, assetBind);
|
||||
_InterlockedDecrement16(word_167ED7BDE);
|
||||
}
|
||||
numAssets = (unsigned int)++pak->processedAssetCount;
|
||||
if ((_DWORD)numAssets == pak->memoryData.pakHeader.assetCount)
|
||||
{
|
||||
JT_EndJobGroup(pak->memoryData.unkJobID);
|
||||
return;
|
||||
}
|
||||
_numAssets = (unsigned int)numAssets;
|
||||
pakAsset = &pak->memoryData.assetEntries[numAssets];
|
||||
|
||||
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 && 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)
|
||||
{
|
||||
PakFileHeader_t* pakHeader; // r8
|
||||
PakFileStream_t* fileStream; // rsi
|
||||
PakMemoryData_t* memoryData; // r14
|
||||
__int64 dwordB8; // rcx
|
||||
unsigned int v6; // eax // [was: int]
|
||||
__int64 v7; // rax
|
||||
char v8; // r13
|
||||
//signed __int64 index_Maybe; // rdi
|
||||
//char v10; // r15
|
||||
//__int64 v11; // rdx
|
||||
//const char* v12; // rbp
|
||||
size_t bytesProcessed; // eax
|
||||
char byteBF; // al
|
||||
unsigned __int64 v16; // r9
|
||||
unsigned __int8 v17; // cl
|
||||
unsigned __int64 v18; // r8
|
||||
uint8_t byte1F8; // al
|
||||
uint8_t byte1FD; // cl
|
||||
PakFileStream_t::Descriptor* v22; // rdi
|
||||
size_t dataOffset; // rax
|
||||
PakDecoder_t* decodeContext; // rbp
|
||||
size_t decompressedSize; // rax
|
||||
size_t compressedSize; // rdx
|
||||
uint64_t qword1D0; // rcx
|
||||
__int64 v28; // rax
|
||||
unsigned int numBitsRemaining; // r8d
|
||||
int v35; // ecx
|
||||
int v39; // r10d
|
||||
int v40; // r9d
|
||||
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
|
||||
char c; // al
|
||||
char* it; // rcx
|
||||
char* i; // rdx
|
||||
int v56; // edi
|
||||
unsigned int patchCount; // r15
|
||||
unsigned __int64 v58; // rdx
|
||||
char pakPatchPath[MAX_PATH]; // [rsp+40h] [rbp-148h] BYREF
|
||||
unsigned __int64 v62; // [rsp+190h] [rbp+8h]
|
||||
size_t numBytesToProcess; // [rsp+198h] [rbp+10h] BYREF
|
||||
|
||||
fileStream = &pak->fileStream;
|
||||
memoryData = &pak->memoryData;
|
||||
dwordB8 = (unsigned int)pak->fileStream.dwordB8;
|
||||
|
||||
if ((_DWORD)dwordB8)
|
||||
v62 = dwordB8 << 19;
|
||||
else
|
||||
v62 = sizeof(PakFileHeader_t);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const char* statusMsg = "(no reason)";
|
||||
const uint8_t currentStatus = g_pakLoadApi->CheckAsyncRequest((unsigned char)fileStream->gap14[v7], &bytesProcessed, &statusMsg);
|
||||
|
||||
if (currentStatus == AsyncHandleStatus_t::FS_ASYNC_PENDING)
|
||||
goto LABEL_18;
|
||||
|
||||
if (currentStatus == AsyncHandleStatus_t::FS_ASYNC_ERROR)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "Error reading pak file \"%s\" -- %s\n", pak->memoryData.fileName, statusMsg);
|
||||
|
||||
fileStream->qword1D0 += bytesProcessed;
|
||||
if (v8)
|
||||
{
|
||||
byteBF = fileStream->byteBF++;
|
||||
pakHeader = &pak->memoryData.pakHeader;
|
||||
v16 = (unsigned __int64)fileStream->unsigned_intB4 << 19;
|
||||
|
||||
if (v8 == 2)
|
||||
{
|
||||
v18 = v16 & fileStream->qword1C8;
|
||||
fileStream->qword1D0 = bytesProcessed + v16;
|
||||
pakHeader = (PakFileHeader_t*)&fileStream->buffer[v18];
|
||||
}
|
||||
|
||||
v17 = byteBF & 7;
|
||||
|
||||
fileStream->m_descriptors[v17].dataOffset = v16 + sizeof(PakFileHeader_t);
|
||||
fileStream->m_descriptors[v17].compressedSize = v16 + pakHeader->compressedSize;
|
||||
fileStream->m_descriptors[v17].decompressedSize = pakHeader->decompressedSize;
|
||||
fileStream->m_descriptors[v17].isCompressed = pakHeader->flags[1] & 1;
|
||||
}
|
||||
goto LABEL_17;
|
||||
}
|
||||
LABEL_18:
|
||||
byte1F8 = pak->byte1F8;
|
||||
if (byte1F8 != fileStream->byteBF)
|
||||
{
|
||||
byte1FD = pak->byte1FD;
|
||||
do
|
||||
{
|
||||
v22 = &fileStream->m_descriptors[byte1F8 & 7];
|
||||
|
||||
if (byte1FD)
|
||||
{
|
||||
pak->byte1FD = 0;
|
||||
pak->inputBytePos = v22->dataOffset;
|
||||
|
||||
if (v22->isCompressed)
|
||||
{
|
||||
pak->isOffsetted_MAYBE = 0;
|
||||
pak->isCompressed = 1;
|
||||
dataOffset = sizeof(PakFileHeader_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
pak->isOffsetted_MAYBE = 1;
|
||||
pak->isCompressed = 0;
|
||||
dataOffset = v22->dataOffset;
|
||||
}
|
||||
|
||||
memoryData->processedPatchedDataSize = dataOffset;
|
||||
|
||||
if (!pak->isCompressed)
|
||||
{
|
||||
LABEL_35:
|
||||
compressedSize = v22->compressedSize;
|
||||
qword1D0 = compressedSize;
|
||||
if (fileStream->qword1D0 < compressedSize)
|
||||
qword1D0 = fileStream->qword1D0;
|
||||
goto LABEL_41;
|
||||
}
|
||||
|
||||
decodeContext = &pak->pakDecoder;
|
||||
|
||||
decompressedSize = Pak_InitDefaultDecoder(&pak->pakDecoder, fileStream->buffer,
|
||||
PAK_DECODE_MASK, v22->compressedSize - (v22->dataOffset - sizeof(PakFileHeader_t)),
|
||||
v22->dataOffset - sizeof(PakFileHeader_t), sizeof(PakFileHeader_t));
|
||||
|
||||
if (decompressedSize != v22->decompressedSize)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE,
|
||||
"Error reading pak file \"%s\" -- decompressed size %zu doesn't match expected value %zu\n",
|
||||
pak->memoryData.fileName,
|
||||
decompressedSize + sizeof(PakFileHeader_t),
|
||||
pak->memoryData.pakHeader.decompressedSize);
|
||||
|
||||
pak->pakDecoder.outputBuf = pak->decompBuffer;
|
||||
pak->pakDecoder.outputMask = PAK_DECODE_OUTPUT_MASK_PARTIAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
decodeContext = &pak->pakDecoder;
|
||||
}
|
||||
|
||||
if (!pak->isCompressed)
|
||||
goto LABEL_35;
|
||||
|
||||
qword1D0 = pak->pakDecoder.outBufBytePos;
|
||||
|
||||
if (qword1D0 != pak->pakDecoder.decompSize)
|
||||
{
|
||||
Pak_DefaultDecode(decodeContext, fileStream->qword1D0, memoryData->processedPatchedDataSize + 0x400000);
|
||||
qword1D0 = pak->pakDecoder.outBufBytePos;
|
||||
pak->inputBytePos = pak->pakDecoder.inBufBytePos;
|
||||
}
|
||||
compressedSize = v22->compressedSize;
|
||||
|
||||
LABEL_41:
|
||||
if (pak->inputBytePos != compressedSize || memoryData->processedPatchedDataSize != qword1D0)
|
||||
goto LABEL_45;
|
||||
|
||||
byte1FD = 1;
|
||||
byte1F8 = pak->byte1F8 + 1;
|
||||
pak->byte1FD = 1;
|
||||
pak->byte1F8 = byte1F8;
|
||||
} while (byte1F8 != fileStream->byteBF);
|
||||
}
|
||||
|
||||
qword1D0 = memoryData->processedPatchedDataSize;
|
||||
LABEL_45:
|
||||
v28 = memoryData->field_2A8;
|
||||
numBytesToProcess = qword1D0 - memoryData->processedPatchedDataSize;
|
||||
|
||||
if (memoryData->patchSrcSize + v28)
|
||||
{
|
||||
do
|
||||
{
|
||||
// if there are no bytes left to process in this patch operation
|
||||
if (!memoryData->numBytesToProcess_maybe)
|
||||
{
|
||||
RBitRead& bitbuf = memoryData->bitBuf;
|
||||
|
||||
numBitsRemaining = bitbuf.m_bitsRemaining; // number of "free" bits in the bitbuf (how many to fetch)
|
||||
|
||||
// fetch remaining bits
|
||||
bitbuf.m_dataBuf |= *(_QWORD*)memoryData->patchData << (64 - (unsigned __int8)numBitsRemaining);
|
||||
|
||||
// advance patch data buffer by the number of bytes that have just been fetched
|
||||
memoryData->patchData = &memoryData->patchData[numBitsRemaining >> 3];
|
||||
|
||||
// store the number of bits remaining to complete the data read
|
||||
bitbuf.m_bitsRemaining = numBitsRemaining & 7; // number of bits above a whole byte
|
||||
|
||||
const unsigned __int8 index1 = static_cast<unsigned __int8>(bitbuf.ReadBits(6));
|
||||
v35 = memoryData->PATCH_field_68[index1]; // number of bits to discard from bitbuf
|
||||
__int8 cmd = memoryData->patchCommands[index1];
|
||||
|
||||
bitbuf.DiscardBits(v35);
|
||||
|
||||
// get the next patch function to execute
|
||||
memoryData->patchFunc = g_pakPatchApi[cmd];
|
||||
|
||||
if (cmd <= 3u)
|
||||
{
|
||||
const unsigned __int8 index2 = static_cast<unsigned __int8>(bitbuf.ReadBits(8));
|
||||
v39 = memoryData->PATCH_unk3[index2];
|
||||
v40 = memoryData->PATCH_unk2[index2]; // number of stored bits for the data size
|
||||
|
||||
bitbuf.DiscardBits(v39);
|
||||
|
||||
memoryData->numBytesToProcess_maybe = (1ull << v40) + bitbuf.ReadBits(v40);
|
||||
|
||||
bitbuf.DiscardBits(v40);
|
||||
}
|
||||
else
|
||||
{
|
||||
memoryData->numBytesToProcess_maybe = s_patchCmdToBytesToProcess[cmd];
|
||||
}
|
||||
}
|
||||
|
||||
} while (pak->memoryData.patchFunc(pak, &numBytesToProcess) && memoryData->patchSrcSize + memoryData->field_2A8);
|
||||
}
|
||||
|
||||
if (pak->isOffsetted_MAYBE)
|
||||
pak->inputBytePos = memoryData->processedPatchedDataSize;
|
||||
|
||||
if (!fileStream->finishedLoadingPatches)
|
||||
{
|
||||
v42 = fileStream->unsigned_intB4;
|
||||
v43 = fileStream->dwordB8;
|
||||
|
||||
if ((unsigned int)(pak->inputBytePos >> 19) < v42)
|
||||
v42 = (unsigned int)pak->inputBytePos >> 19; // New cast added
|
||||
|
||||
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] = v_FS_ReadAsyncFile(
|
||||
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->patchCount >= pak->memoryData.pakHeader.patchIndex)
|
||||
{
|
||||
FS_CloseAsyncFile((short)fileStream->fileHandle);
|
||||
fileStream->fileHandle = INVALID_PAK_HANDLE;
|
||||
fileStream->qword0 = 0i64;
|
||||
fileStream->finishedLoadingPatches = true;
|
||||
|
||||
return memoryData->patchSrcSize == 0;
|
||||
}
|
||||
|
||||
if (!pak->dword14)
|
||||
return memoryData->patchSrcSize == 0;
|
||||
|
||||
sprintf(pakPatchPath, PLATFORM_PAK_PATH"%s", pak->memoryData.fileName);
|
||||
patchCount = pak->patchCount++;
|
||||
|
||||
// get path of next patch rpak to load
|
||||
if (pak->memoryData.patchIndices[patchCount])
|
||||
{
|
||||
c = pakPatchPath[0];
|
||||
it = pakPatchPath;
|
||||
|
||||
for (i = nullptr; c; ++it)
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
i = it;
|
||||
}
|
||||
else if (c == '\\' || c == '/')
|
||||
{
|
||||
i = nullptr;
|
||||
}
|
||||
c = it[1];
|
||||
}
|
||||
if (i)
|
||||
it = i;
|
||||
|
||||
// replace extension '.rpak' with '(xx).rpak'
|
||||
snprintf(it, &pakPatchPath[sizeof(pakPatchPath)] - it,
|
||||
"(%02u).rpak", pak->memoryData.patchIndices[patchCount]);
|
||||
}
|
||||
|
||||
v56 = FS_OpenAsyncFile(pakPatchPath, 5i64, &numBytesToProcess);
|
||||
|
||||
if (v56 == FS_ASYNC_FILE_INVALID)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't open file \"%s\".\n", pakPatchPath);
|
||||
|
||||
if (numBytesToProcess < pak->memoryData.patchHeaders[patchCount].m_sizeDisk)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "File \"%s\" appears truncated; read size: %zu < expected size: %zu.\n",
|
||||
pakPatchPath, numBytesToProcess, pak->memoryData.patchHeaders[patchCount].m_sizeDisk);
|
||||
|
||||
FS_CloseAsyncFile((short)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->memoryData.patchHeaders[patchCount].m_sizeDisk;
|
||||
LABEL_84:
|
||||
if (v43 == v44)
|
||||
return memoryData->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->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)
|
||||
{
|
||||
Rebuild_14043E030(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_pPakGlobals->m_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_pPakGlobals->m_assetBindings[assetTypeIdx].nativeClassSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool res = SetupNextPageForPatching(a1, pak);
|
||||
|
||||
if (res)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!JT_IsJobDone(pak->memoryData.unkJobID))
|
||||
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 v36 = pak->memoryData.qword2E0[i];
|
||||
|
||||
if (dword_167A40B3C[6 * g_pPakGlobals->m_assets[v36].unk_8] == j)
|
||||
{
|
||||
if (*qword_167ED7BC8)
|
||||
{
|
||||
uint64_t v38 = 0;
|
||||
if ((*qword_167ED7BC8)->unk_0)
|
||||
{
|
||||
int* v39 = (*qword_167ED7BC8)->unk_array_9D410;
|
||||
while (*v39 != v36)
|
||||
{
|
||||
++v38;
|
||||
++v39;
|
||||
if (v38 >= (*qword_167ED7BC8)->unk_0)
|
||||
goto LABEL_41;
|
||||
}
|
||||
goto LABEL_42;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("allocating thing\n");
|
||||
*qword_167ED7BC8 = reinterpret_cast<UnknownPakStruct_t*>(AlignedMemAlloc()->Alloc(0x11D410, 8));
|
||||
(*qword_167ED7BC8)->unk_0 = 0;
|
||||
(*qword_167ED7BC8)->unk_4 = 0;
|
||||
(*qword_167ED7BC8)->unk_8 = 0;
|
||||
}
|
||||
LABEL_41:
|
||||
(*qword_167ED7BC8)->unk_array_9D410[(*qword_167ED7BC8)->unk_0] = v36;
|
||||
++(*qword_167ED7BC8)->unk_0;
|
||||
}
|
||||
}
|
||||
LABEL_42:
|
||||
++i;
|
||||
}
|
||||
if (*qword_167ED7BC8)
|
||||
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_pPakGlobals->m_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)
|
||||
{
|
||||
DevWarning(eDLL_T::RTECH,
|
||||
"Unexpected asset version for \"%s\" (%.4s) asset with guid 0x%llX (asset %i in pakfile '%s'). Expected %i, found %i.\n",
|
||||
assetBinding->description,
|
||||
reinterpret_cast<char*>(&asset->magic),
|
||||
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->m_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 (*g_pUseAssetStreamingSystem)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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(&sub_14043E030, &Rebuild_14043E030, bAttach);
|
||||
}
|
||||
|
||||
// Symbols taken from R2 dll's.
|
||||
PakLoadFuncs_t* g_pakLoadApi = nullptr;
|
136
r5dev/rtech/pak/pakparse.h
Normal file
136
r5dev/rtech/pak/pakparse.h
Normal file
@ -0,0 +1,136 @@
|
||||
#ifndef RTECH_PAKPARSE_H
|
||||
#define RTECH_PAKPARSE_H
|
||||
#include "tier0/tslist.h"
|
||||
#include "tier0/jobthread.h"
|
||||
#include "launcher/launcher.h"
|
||||
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "rtech/async/asyncio.h"
|
||||
|
||||
// This function returns the pak handle of the patch master RPak
|
||||
inline PakHandle_t(*v_Pak_Initialize)(int mode);
|
||||
|
||||
inline PakHandle_t(*v_Pak_LoadAsync)(const char* fileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk);
|
||||
inline EPakStatus(*v_Pak_WaitAsync)(PakHandle_t handle, void* finishCallback);
|
||||
inline void(*v_Pak_UnloadAsync)(PakHandle_t handle);
|
||||
inline void(*v_Pak_RegisterAsset)(int, int, const char*, void*, void*, void*, void*, int, int, uint32_t, int, int);
|
||||
|
||||
inline bool(*v_Pak_StartLoadingPak)(PakLoadedInfo_t* loadedInfo);
|
||||
inline bool(*v_Pak_ProcessPakFile)(PakFile_t* const pak);
|
||||
inline bool(*v_Pak_ProcessAssets)(PakLoadedInfo_t* pakInfo);
|
||||
inline void(*v_Pak_ResolveAssetRelations)(PakFile_t* const pak, const PakAsset_t* const asset);
|
||||
|
||||
// TODO: name these!
|
||||
inline void (*sub_14043E030)(PakFile_t* pak);
|
||||
inline __int64 (*sub_14043D3C0)(PakFile_t* a1, PakAsset_t* a2);
|
||||
inline void (*sub_14043D150)(PakFile_t* pak_arg, PakAsset_t* asset_arg, unsigned int asset_idx_arg, unsigned int a4);
|
||||
inline void (*sub_14045B310)(unsigned int a1, __int64 a2);
|
||||
inline void (*sub_14043D870)(PakLoadedInfo_t* a1, int a2);
|
||||
|
||||
inline short* word_167ED7BDE = nullptr;
|
||||
|
||||
// potentially PakAssetShort_t
|
||||
inline int* dword_167A40B3C = nullptr;
|
||||
inline UnknownPakStruct_t** qword_167ED7BC8 = nullptr; // ptr to buffer with size 0x11D410
|
||||
|
||||
typedef struct PakLoadFuncs_s
|
||||
{
|
||||
void* Initialize; // Returns the pak handle of the patch master RPak once initialized.
|
||||
void* RegisterAsset;
|
||||
char unknown0[8];
|
||||
PakHandle_t(*LoadAsync)(const char* pakFileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk);
|
||||
void* LoadAsyncAndWait;
|
||||
void (*UnloadAsync)(PakHandle_t handle);
|
||||
void* UnloadAsyncAndWait;
|
||||
char unknown2[16];
|
||||
void* Func7;
|
||||
void* Func8;
|
||||
EPakStatus(*WaitAsync)(PakHandle_t handle, void* finishCallback);
|
||||
void* Func10;
|
||||
void* Func11;
|
||||
void* FindByGUID;
|
||||
void* FindByName;
|
||||
char unknown3[8];
|
||||
void* Func14;
|
||||
void* Func15;
|
||||
void* Func16;
|
||||
void* Func17;
|
||||
void* Func18;
|
||||
void* IncrementStreamingAssetCount;
|
||||
void* DecrementStreamingAssetCount;
|
||||
void* IsFullStreamingInstall;
|
||||
char unknown4[48];
|
||||
int (*OpenAsyncFile)(const char* const fileName, int logLevel, size_t* const outFileSize);
|
||||
void (*CloseAsyncFile)(short fileHandle);
|
||||
void* Func24;
|
||||
void* Func25;
|
||||
void* ReadAsyncFile;
|
||||
void* ReadAsyncFileWithUserData;
|
||||
uint8_t (*CheckAsyncRequest)(unsigned char idx, size_t* const bytesProcessed, const char** const statusMsg);
|
||||
uint8_t (*WaitAndCheckAsyncRequest)(unsigned char idx, size_t* const bytesProcessed, const char** const statusMsg);
|
||||
void* WaitForAsyncFileRead;
|
||||
void* Func31;
|
||||
void* Func32;
|
||||
void* Func33;
|
||||
} PakLoadFuncs_t;
|
||||
|
||||
extern PakLoadFuncs_t* g_pakLoadApi;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_PakParse : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("Pak_Initialize", v_Pak_Initialize);
|
||||
|
||||
LogFunAdr("Pak_LoadAsync", v_Pak_LoadAsync);
|
||||
LogFunAdr("Pak_WaitAsync", v_Pak_WaitAsync);
|
||||
LogFunAdr("Pak_UnloadAsync", v_Pak_UnloadAsync);
|
||||
|
||||
LogFunAdr("Pak_RegisterAsset", v_Pak_RegisterAsset);
|
||||
|
||||
LogFunAdr("Pak_StartLoadingPak", v_Pak_StartLoadingPak);
|
||||
|
||||
LogFunAdr("Pak_ProcessPakFile", v_Pak_ProcessPakFile);
|
||||
LogFunAdr("Pak_ProcessAssets", v_Pak_ProcessAssets);
|
||||
LogFunAdr("Pak_ResolveAssetRelations", v_Pak_ResolveAssetRelations);
|
||||
|
||||
LogVarAdr("word_167ED7BDE", word_167ED7BDE);
|
||||
LogVarAdr("g_pakLoadApi", g_pakLoadApi);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B D9 E8 ?? ?? ?? ??").GetPtr(v_Pak_Initialize);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 03 8B 0B").FollowNearCallSelf().GetPtr(v_Pak_LoadAsync);
|
||||
g_GameDll.FindPatternSIMD("40 53 55 48 83 EC 38 48 89 74 24 ??").GetPtr(v_Pak_WaitAsync);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 85 FF 74 0C").FollowNearCallSelf().GetPtr(v_Pak_UnloadAsync);
|
||||
g_GameDll.FindPatternSIMD("48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 8B 44 24 ?? 4C 8D 35 ?? ?? ?? ??").GetPtr(v_Pak_RegisterAsset);
|
||||
|
||||
g_GameDll.FindPatternSIMD("48 89 4C 24 ?? 56 41 55").GetPtr(v_Pak_StartLoadingPak);
|
||||
g_GameDll.FindPatternSIMD("40 53 55 56 41 54 41 56 48 81 EC ?? ?? ?? ??").GetPtr(v_Pak_ProcessPakFile);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 84 C0 0F 84 ?? ?? ?? ?? 48 8B CF E8 ?? ?? ?? ?? 44 0F B7 05 ?? ?? ?? ??").FollowNearCallSelf().GetPtr(v_Pak_ProcessAssets);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 48 8B 86 ?? ?? ?? ?? 42 8B 0C B0").FollowNearCallSelf().GetPtr(v_Pak_ResolveAssetRelations);
|
||||
|
||||
g_GameDll.FindPatternSIMD("40 53 56 48 83 EC 58 44 8B 09").GetPtr(sub_14043E030);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 54 41 55 41 56 41 57 48 83 EC 20 44 8B 0D ?? ?? ?? ?? 4C 8B E9").GetPtr(sub_14043D3C0);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 41 8B E9").GetPtr(sub_14043D150);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 83 7A 14 01").GetPtr(sub_14045B310);
|
||||
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? EB 14 48 8D 0D ?? ?? ?? ??").FollowNearCallSelf().GetPtr(sub_14043D870);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
g_pakLoadApi = CMemory(v_LauncherMain).Offset(0x820).FindPatternSelf("48 89").ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakLoadFuncs_t*>();
|
||||
|
||||
CMemory(sub_14043E030).FindPatternSelf("66 44 39").ResolveRelativeAddressSelf(0x4, 0x8).GetPtr(word_167ED7BDE);
|
||||
int* va_dword_167A40B3C = CMemory(v_Pak_ProcessAssets).Offset(0x200).FindPatternSelf("44 39 BC").Offset(4).RCast<int*>();
|
||||
dword_167A40B3C = reinterpret_cast<int*>(g_GameDll.GetModuleBase() + *va_dword_167A40B3C);
|
||||
|
||||
CMemory(v_Pak_ProcessAssets).Offset(0x200).FindPatternSelf("48 8B 15").ResolveRelativeAddressSelf(0x3, 0x7).GetPtr(qword_167ED7BC8);
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // RTECH_PAKPARSE_H
|
250
r5dev/rtech/pak/pakpatch.cpp
Normal file
250
r5dev/rtech/pak/pakpatch.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: pak page patching
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakpatch.h"
|
||||
|
||||
bool PATCH_CMD_0(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
unsigned __int64 m_numBytesToProcess_maybe; // r9
|
||||
unsigned __int64 v4; // rdi
|
||||
unsigned __int64 v6; // rcx
|
||||
unsigned __int64 v7; // r8
|
||||
uint64_t m_processedPatchedDataSize; // rax
|
||||
uint64_t v9; // rdx
|
||||
size_t m_maxCopySize; // rax
|
||||
size_t m_patchSrcSize; // rsi
|
||||
char* m_patchDstPtr; // rcx
|
||||
size_t v13; // r14
|
||||
char* m_decompBuffer; // rdx
|
||||
size_t v15; // r8
|
||||
|
||||
m_numBytesToProcess_maybe = pak->memoryData.numBytesToProcess_maybe;
|
||||
v4 = *numAvailableBytes;
|
||||
v6 = *numAvailableBytes;
|
||||
v7 = pak->memoryData.field_2A8;
|
||||
|
||||
if (m_numBytesToProcess_maybe < *numAvailableBytes)
|
||||
v6 = m_numBytesToProcess_maybe;
|
||||
|
||||
if (v7)
|
||||
{
|
||||
m_processedPatchedDataSize = pak->memoryData.processedPatchedDataSize;
|
||||
|
||||
if (v6 <= v7)
|
||||
{
|
||||
pak->memoryData.processedPatchedDataSize = v6 + m_processedPatchedDataSize;
|
||||
pak->memoryData.field_2A8 = v7 - v6;
|
||||
pak->memoryData.numBytesToProcess_maybe = m_numBytesToProcess_maybe - v6;
|
||||
*numAvailableBytes = v4 - v6;
|
||||
return pak->memoryData.numBytesToProcess_maybe == 0;
|
||||
}
|
||||
|
||||
pak->memoryData.field_2A8 = 0i64;
|
||||
pak->memoryData.processedPatchedDataSize = v7 + m_processedPatchedDataSize;
|
||||
v6 -= v7;
|
||||
pak->memoryData.numBytesToProcess_maybe = m_numBytesToProcess_maybe - v7;
|
||||
v4 -= v7;
|
||||
}
|
||||
|
||||
v9 = pak->memoryData.processedPatchedDataSize;
|
||||
m_maxCopySize = pak->maxCopySize;
|
||||
m_patchSrcSize = pak->memoryData.patchSrcSize;
|
||||
|
||||
if (v6 < m_patchSrcSize)
|
||||
m_patchSrcSize = v6;
|
||||
|
||||
m_patchDstPtr = pak->memoryData.patchDstPtr;
|
||||
v13 = (m_maxCopySize & ~v9) + 1; // maxCopySize minus processedPatchedDataSize with a minimum of 1
|
||||
m_decompBuffer = (char*)pak->decompBuffer + (m_maxCopySize & v9);
|
||||
|
||||
if (m_patchSrcSize > v13)
|
||||
{
|
||||
memcpy(m_patchDstPtr, m_decompBuffer, v13);
|
||||
m_decompBuffer = (char*)pak->decompBuffer;
|
||||
v15 = m_patchSrcSize - v13;
|
||||
m_patchDstPtr = &pak->memoryData.patchDstPtr[v13];
|
||||
}
|
||||
else
|
||||
{
|
||||
v15 = m_patchSrcSize;
|
||||
}
|
||||
|
||||
memcpy(m_patchDstPtr, m_decompBuffer, v15);
|
||||
pak->memoryData.processedPatchedDataSize += m_patchSrcSize;
|
||||
pak->memoryData.patchSrcSize -= m_patchSrcSize;
|
||||
pak->memoryData.patchDstPtr += m_patchSrcSize;
|
||||
pak->memoryData.numBytesToProcess_maybe -= m_patchSrcSize;
|
||||
*numAvailableBytes = v4 - m_patchSrcSize;
|
||||
|
||||
|
||||
return pak->memoryData.numBytesToProcess_maybe == 0;
|
||||
}
|
||||
|
||||
bool PATCH_CMD_1(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
unsigned __int64 m_numBytesToProcess_maybe; // r8
|
||||
size_t v3; // r9
|
||||
uint64_t m_processedPatchedDataSize; // rax
|
||||
|
||||
m_numBytesToProcess_maybe = pak->memoryData.numBytesToProcess_maybe;
|
||||
v3 = *numAvailableBytes;
|
||||
m_processedPatchedDataSize = pak->memoryData.processedPatchedDataSize;
|
||||
|
||||
if (*numAvailableBytes > m_numBytesToProcess_maybe)
|
||||
{
|
||||
pak->memoryData.numBytesToProcess_maybe = 0i64;
|
||||
pak->memoryData.processedPatchedDataSize += m_numBytesToProcess_maybe;
|
||||
*numAvailableBytes = v3 - m_numBytesToProcess_maybe;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pak->memoryData.processedPatchedDataSize += v3;
|
||||
pak->memoryData.numBytesToProcess_maybe -= v3;
|
||||
*numAvailableBytes = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PATCH_CMD_2(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
NOTE_UNUSED(numAvailableBytes);
|
||||
|
||||
unsigned __int64 m_numBytesToProcess_maybe;
|
||||
unsigned __int64 v3;
|
||||
const char* m_patchDataPtr;
|
||||
|
||||
m_numBytesToProcess_maybe = pak->memoryData.numBytesToProcess_maybe;
|
||||
v3 = pak->memoryData.field_2A8;
|
||||
|
||||
if (v3)
|
||||
{
|
||||
m_patchDataPtr = pak->memoryData.patchDataPtr;
|
||||
|
||||
if (m_numBytesToProcess_maybe <= v3)
|
||||
{
|
||||
pak->memoryData.numBytesToProcess_maybe = 0i64;
|
||||
pak->memoryData.patchDataPtr += m_numBytesToProcess_maybe;
|
||||
pak->memoryData.field_2A8 = v3 - m_numBytesToProcess_maybe;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pak->memoryData.field_2A8 = 0i64;
|
||||
m_numBytesToProcess_maybe -= v3;
|
||||
pak->memoryData.patchDataPtr += v3;
|
||||
pak->memoryData.numBytesToProcess_maybe = m_numBytesToProcess_maybe;
|
||||
}
|
||||
|
||||
const size_t patchSrcSize = min(m_numBytesToProcess_maybe, pak->memoryData.patchSrcSize);
|
||||
|
||||
memcpy(pak->memoryData.patchDstPtr, pak->memoryData.patchDataPtr, patchSrcSize);
|
||||
|
||||
pak->memoryData.patchDataPtr += patchSrcSize;
|
||||
pak->memoryData.patchSrcSize -= patchSrcSize;
|
||||
pak->memoryData.patchDstPtr += patchSrcSize;
|
||||
pak->memoryData.numBytesToProcess_maybe -= patchSrcSize;
|
||||
|
||||
return pak->memoryData.numBytesToProcess_maybe == 0;
|
||||
}
|
||||
|
||||
bool PATCH_CMD_3(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
size_t patchSrcSize = pak->memoryData.patchSrcSize;
|
||||
|
||||
size_t v9 = min(*numAvailableBytes, pak->memoryData.numBytesToProcess_maybe);
|
||||
|
||||
patchSrcSize = min(v9, patchSrcSize);
|
||||
|
||||
memcpy(pak->memoryData.patchDstPtr, pak->memoryData.patchDataPtr, patchSrcSize);
|
||||
pak->memoryData.patchDataPtr += patchSrcSize;
|
||||
pak->memoryData.processedPatchedDataSize += patchSrcSize;
|
||||
pak->memoryData.patchSrcSize -= patchSrcSize;
|
||||
pak->memoryData.patchDstPtr += patchSrcSize;
|
||||
pak->memoryData.numBytesToProcess_maybe -= patchSrcSize;
|
||||
*numAvailableBytes = *numAvailableBytes - patchSrcSize;
|
||||
|
||||
return pak->memoryData.numBytesToProcess_maybe == 0;
|
||||
}
|
||||
|
||||
bool PATCH_CMD_4_5(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
const size_t v2 = *numAvailableBytes;
|
||||
if (!v2)
|
||||
return false;
|
||||
|
||||
*pak->memoryData.patchDstPtr = *(_BYTE*)pak->memoryData.patchDataPtr++;
|
||||
++pak->memoryData.processedPatchedDataSize;
|
||||
--pak->memoryData.patchSrcSize;
|
||||
++pak->memoryData.patchDstPtr;
|
||||
pak->memoryData.patchFunc = PATCH_CMD_0;
|
||||
*numAvailableBytes = v2 - 1;
|
||||
|
||||
return PATCH_CMD_0(pak, numAvailableBytes);
|
||||
}
|
||||
|
||||
bool PATCH_CMD_6(PakFile_t* const pak, size_t* const numAvailableBytes)
|
||||
{
|
||||
const size_t v2 = *numAvailableBytes;
|
||||
size_t v3 = 2;
|
||||
|
||||
if (*numAvailableBytes < 2)
|
||||
{
|
||||
if (!*numAvailableBytes)
|
||||
return false;
|
||||
|
||||
v3 = *numAvailableBytes;
|
||||
}
|
||||
|
||||
const void* const patchDataPtr = (const void*)pak->memoryData.patchDataPtr;
|
||||
const size_t patchSrcSize = pak->memoryData.patchSrcSize;
|
||||
char* const patchDstPtr = pak->memoryData.patchDstPtr;
|
||||
|
||||
if (v3 > patchSrcSize)
|
||||
{
|
||||
memcpy(patchDstPtr, patchDataPtr, patchSrcSize);
|
||||
pak->memoryData.patchDataPtr += patchSrcSize;
|
||||
pak->memoryData.processedPatchedDataSize += patchSrcSize;
|
||||
pak->memoryData.patchSrcSize -= patchSrcSize;
|
||||
pak->memoryData.patchDstPtr += patchSrcSize;
|
||||
pak->memoryData.patchFunc = PATCH_CMD_4_5;
|
||||
*numAvailableBytes = v2 - patchSrcSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(patchDstPtr, patchDataPtr, v3);
|
||||
pak->memoryData.patchDataPtr += v3;
|
||||
pak->memoryData.processedPatchedDataSize += v3;
|
||||
pak->memoryData.patchSrcSize -= v3;
|
||||
pak->memoryData.patchDstPtr += v3;
|
||||
|
||||
if (v2 >= 2)
|
||||
{
|
||||
pak->memoryData.patchFunc = PATCH_CMD_0;
|
||||
*numAvailableBytes = v2 - v3;
|
||||
|
||||
return PATCH_CMD_0(pak, numAvailableBytes);
|
||||
}
|
||||
|
||||
pak->memoryData.patchFunc = PATCH_CMD_4_5;
|
||||
*numAvailableBytes = NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const PakPatchFuncs_t g_pakPatchApi
|
||||
{
|
||||
PATCH_CMD_0,
|
||||
PATCH_CMD_1,
|
||||
PATCH_CMD_2,
|
||||
PATCH_CMD_3,
|
||||
PATCH_CMD_4_5,
|
||||
PATCH_CMD_4_5,
|
||||
PATCH_CMD_6,
|
||||
};
|
7
r5dev/rtech/pak/pakpatch.h
Normal file
7
r5dev/rtech/pak/pakpatch.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef RTECH_PATCHAPI_H
|
||||
#define RTECH_PATCHAPI_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
extern const PakPatchFuncs_t g_pakPatchApi;
|
||||
|
||||
#endif // RTECH_PATCHAPI_H
|
8
r5dev/rtech/pak/pakstate.cpp
Normal file
8
r5dev/rtech/pak/pakstate.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: pak runtime memory and management
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstate.h"
|
||||
|
73
r5dev/rtech/pak/pakstate.h
Normal file
73
r5dev/rtech/pak/pakstate.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef RTECH_PAKSTATE_H
|
||||
#define RTECH_PAKSTATE_H
|
||||
#include "tier0/tslist.h"
|
||||
#include "tier0/jobthread.h"
|
||||
#include "launcher/launcher.h"
|
||||
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
inline PakGlobals_t* g_pPakGlobals;
|
||||
inline PakLoadedInfo_t* g_pLoadedPakInfo;
|
||||
|
||||
inline JobID_t* g_pPakLoadJobID;
|
||||
|
||||
inline int16_t* g_pLoadedPakCount;
|
||||
inline int16_t* g_pRequestedPakCount;
|
||||
|
||||
inline JobFifoLock_s* g_pPakFifoLock;
|
||||
inline void* g_pPakFifoLockWrapper; // Pointer to functor that takes the global pak fifolock as argument.
|
||||
inline bool* g_bPakFifoLockAcquired;
|
||||
|
||||
// bool as int64
|
||||
inline int64_t* g_pPakHasPendingUnloadJobs;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_PakState : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogVarAdr("g_pakGlobals", g_pPakGlobals);
|
||||
LogVarAdr("g_loadedPakInfo", g_pLoadedPakInfo);
|
||||
|
||||
LogVarAdr("g_pakLoadJobID", g_pPakLoadJobID);
|
||||
|
||||
LogVarAdr("g_loadedPakCount", g_pLoadedPakCount);
|
||||
LogVarAdr("g_requestedPakCount", g_pRequestedPakCount);
|
||||
|
||||
LogVarAdr("g_pakFifoLock", g_pPakFifoLock);
|
||||
LogVarAdr("g_pakFifoLockWrapper", g_pPakFifoLockWrapper);
|
||||
LogVarAdr("g_pakFifoLockAcquired", g_bPakFifoLockAcquired);
|
||||
|
||||
LogVarAdr("g_pakHasPendingUnloadJobs", g_pPakHasPendingUnloadJobs);
|
||||
}
|
||||
virtual void GetFun(void) const { }
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
extern void(*v_Pak_UnloadAsync)(PakHandle_t);
|
||||
const CMemory pakUnloadBase(v_Pak_UnloadAsync);
|
||||
|
||||
g_pLoadedPakInfo = pakUnloadBase.FindPattern("48 8D 05", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakLoadedInfo_t*>();
|
||||
g_pRequestedPakCount = pakUnloadBase.FindPattern("66 89", CMemory::Direction::DOWN, 450).ResolveRelativeAddressSelf(0x3, 0x7).RCast<int16_t*>();
|
||||
g_pLoadedPakCount = &*g_pRequestedPakCount - 1; // '-1' shifts it back with sizeof(int16_t).
|
||||
|
||||
g_pPakGlobals = g_GameDll.FindPatternSIMD("48 8D 1D ?? ?? ?? ?? 45 8D 5A 0E").ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakGlobals_t*>(); /*48 8D 1D ? ? ? ? 45 8D 5A 0E*/
|
||||
g_pPakLoadJobID = reinterpret_cast<JobID_t*>(&*g_pLoadedPakCount - 2);
|
||||
|
||||
const CMemory jtBase(JT_HelpWithAnything);
|
||||
|
||||
g_pPakFifoLock = jtBase.Offset(0x155).FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<JobFifoLock_s*>();
|
||||
g_pPakFifoLockWrapper = jtBase.Offset(0x1BC).FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void*>();
|
||||
g_bPakFifoLockAcquired = jtBase.Offset(0x50).FindPatternSelf("C6 05").ResolveRelativeAddressSelf(0x2, 0x7).RCast<bool*>();
|
||||
|
||||
extern EPakStatus(*v_Pak_WaitAsync)(PakHandle_t, void*);
|
||||
const CMemory pakWaitBase(v_Pak_WaitAsync);
|
||||
|
||||
pakWaitBase.Offset(0x80).FindPatternSelf("48 39").ResolveRelativeAddressSelf(3, 7).GetPtr(g_pPakHasPendingUnloadJobs);
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { };
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif // RTECH_PAKSTATE_H
|
152
r5dev/rtech/pak/pakstream.cpp
Normal file
152
r5dev/rtech/pak/pakstream.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: pak stream data loading and unloading
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "tier0/commandline.h"
|
||||
#include "rtech/async/asyncio.h"
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstream.h"
|
||||
#include "pakparse.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// determines whether or not to emulate the streaming install, this basically
|
||||
// tells the system to not load streaming sets at all. note that this only
|
||||
// applies to optional streaming sets, mandatory ones must be available!
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool Pak_ShouldEmulateStreamingInstall()
|
||||
{
|
||||
static bool initialized = false;
|
||||
static bool shouldEmulate = false;
|
||||
|
||||
// don't run the command line check every query
|
||||
if (initialized)
|
||||
return shouldEmulate;
|
||||
|
||||
const char* value = nullptr;
|
||||
|
||||
if (CommandLine()->CheckParm("-emulate_streaming_install", &value))
|
||||
{
|
||||
if (value && atoi(value))
|
||||
shouldEmulate = true;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
return shouldEmulate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns whether the optional streaming sets are finished downloading
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool Pak_OptionalStreamingDataDownloaded()
|
||||
{
|
||||
return (!Pak_ShouldEmulateStreamingInstall() && Pak_StreamingDownloadFinished());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// opens all associated streaming assets for this pak
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_OpenAssociatedStreamingFiles(PakLoadedInfo_t* const loadedInfo, PakLoadedInfo_t::StreamingInfo_t& streamInfo,
|
||||
const uint16_t fileNamesBufSize, const EPakStreamSet set)
|
||||
{
|
||||
assert(set < STREAMING_SET_COUNT);
|
||||
|
||||
const PakMemoryData_t& memoryData = loadedInfo->pakFile->memoryData;
|
||||
uint16_t numStreamFiles = 0;
|
||||
|
||||
// load all streaming sets
|
||||
for (uint64_t lenRead = 0; lenRead < fileNamesBufSize && numStreamFiles < PAK_MAX_STREAMING_FILE_HANDLES_PER_SET;)
|
||||
{
|
||||
// read streaming path and advance buffer
|
||||
const char* const streamingFilePath = &memoryData.streamingFilePaths[set][lenRead];
|
||||
|
||||
// check if we processed all strings, the buffer is aligned to 4 bytes,
|
||||
// so its possible we reach padding before the end of the buffer
|
||||
if (!*streamingFilePath)
|
||||
break;
|
||||
|
||||
// must advance over null character as well for the next read
|
||||
lenRead += strnlen(streamingFilePath, fileNamesBufSize - lenRead) + 1;
|
||||
|
||||
const int fileNumber = FS_OpenAsyncFile(streamingFilePath, loadedInfo->logLevel, nullptr);
|
||||
|
||||
// make sure we successfully loaded mandatory streaming files, as we
|
||||
// would otherwise error in the game itself
|
||||
if (set == STREAMING_SET_MANDATORY && fileNumber == -1)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "Error opening streaming file '%s'\n", streamingFilePath);
|
||||
|
||||
streamInfo.streamFileNumber[numStreamFiles++] = fileNumber;
|
||||
}
|
||||
|
||||
streamInfo.streamFileCount = numStreamFiles;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// allocates the pak string to be used for embedded streaming data
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_EnableEmbeddedStreamingData(PakLoadedInfo_t* const loadedInfo, PakLoadedInfo_t::StreamingInfo_t& streamInfo)
|
||||
{
|
||||
const char* const baseName = V_UnqualifiedFileName(loadedInfo->fileName);
|
||||
const size_t baseNameLen = strlen(baseName);
|
||||
|
||||
// if the path isn't specified, we have to prepend one
|
||||
const bool hasPath = (baseName != loadedInfo->fileName);
|
||||
|
||||
const size_t basePathLen = hasPath ? 0 : strlen(PAK_BASE_PATH);
|
||||
const size_t totalBufLen = basePathLen + baseNameLen + 1;
|
||||
|
||||
char* const embeddedName = reinterpret_cast<char* const>(loadedInfo->allocator->Alloc(totalBufLen, sizeof(char)));
|
||||
assert(embeddedName);
|
||||
|
||||
// copy the base path if none was found in the file name
|
||||
if (!hasPath)
|
||||
memcpy(embeddedName, PAK_BASE_PATH, basePathLen);
|
||||
|
||||
memcpy(embeddedName + basePathLen, baseName, baseNameLen);
|
||||
|
||||
// at this point we shouldn't have read loose streaming data, we only
|
||||
// should be looking for embedded if there are no external ones !!!
|
||||
assert(streamInfo.streamFileCount == 0);
|
||||
|
||||
streamInfo.streamFileCount = 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// parse and open all streaming files
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_LoadStreamingData(PakLoadedInfo_t* const loadedInfo)
|
||||
{
|
||||
const PakFileHeader_t& pakHeader = loadedInfo->pakFile->GetHeader();
|
||||
|
||||
for (int i = 0; i < STREAMING_SET_COUNT; i++)
|
||||
{
|
||||
PakLoadedInfo_t::StreamingInfo_t& streamInfo = loadedInfo->streamInfo[i];
|
||||
streamInfo.Reset();
|
||||
|
||||
const bool optional = (i == STREAMING_SET_OPTIONAL);
|
||||
|
||||
// NOTE: mandatory streaming data must be available at this point!
|
||||
const bool disableStreaming = optional ? !Pak_OptionalStreamingDataDownloaded() : false;
|
||||
streamInfo.streamingDisabled = disableStreaming;
|
||||
|
||||
// don't attempt to open the streaming file if it isn't downloaded yet
|
||||
if (disableStreaming)
|
||||
continue;
|
||||
|
||||
const uint16_t filesBufLen = pakHeader.streamingFilesBufSize[i];
|
||||
const uint64_t embeddedStreamingDataSize = pakHeader.embeddedStreamingDataSize[i];
|
||||
|
||||
if (filesBufLen > 0)
|
||||
{
|
||||
// embedded streaming data won't be loaded if the pak is linked to
|
||||
// external streaming files; mistake while building the pak?
|
||||
assert(!embeddedStreamingDataSize);
|
||||
|
||||
Pak_OpenAssociatedStreamingFiles(loadedInfo, streamInfo, filesBufLen, EPakStreamSet(i));
|
||||
}
|
||||
else if (embeddedStreamingDataSize > 0)
|
||||
{
|
||||
Pak_EnableEmbeddedStreamingData(loadedInfo, streamInfo);
|
||||
}
|
||||
}
|
||||
}
|
56
r5dev/rtech/pak/pakstream.h
Normal file
56
r5dev/rtech/pak/pakstream.h
Normal file
@ -0,0 +1,56 @@
|
||||
#ifndef RTECH_PAKSTREAM_H
|
||||
#define RTECH_PAKSTREAM_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
extern void Pak_OpenAssociatedStreamingFiles(PakLoadedInfo_t* const loadedInfo, PakLoadedInfo_t::StreamingInfo_t& streamInfo,
|
||||
const uint16_t fileNamesBufSize, const EPakStreamSet set);
|
||||
|
||||
extern void Pak_EnableEmbeddedStreamingData(PakLoadedInfo_t* const loadedInfo, PakLoadedInfo_t::StreamingInfo_t& streamInfo);
|
||||
extern void Pak_LoadStreamingData(PakLoadedInfo_t* const loadedInfo);
|
||||
|
||||
// bool set as int64.
|
||||
inline int64_t* g_pUseAssetStreamingSystem = nullptr;
|
||||
inline int64_t* g_pNumStreamableAssets = nullptr;
|
||||
inline float* g_pStreamingDownloadProgress = nullptr;
|
||||
|
||||
// inlines
|
||||
inline void(*v_Pak_IncrementStreamingAssetCount)(void);
|
||||
inline void(*v_Pak_DecrementStreamingAssetCount)(void);
|
||||
|
||||
inline bool Pak_StreamingEnabled() { return *g_pUseAssetStreamingSystem != NULL; }
|
||||
inline int64_t Pak_GetNumStreamableAssets() { return *g_pNumStreamableAssets; }
|
||||
|
||||
inline float Pak_GetStreamingDownloadProgress() { return *g_pStreamingDownloadProgress; }
|
||||
inline bool Pak_StreamingDownloadFinished() { return Pak_GetStreamingDownloadProgress() == 1.0f; }
|
||||
|
||||
class V_PakStream : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("Pak_IncrementStreamingAssetCount", v_Pak_IncrementStreamingAssetCount);
|
||||
LogFunAdr("Pak_DecrementStreamingAssetCount", v_Pak_DecrementStreamingAssetCount);
|
||||
|
||||
LogVarAdr("g_useAssetStreamingSystem", g_pUseAssetStreamingSystem);
|
||||
LogVarAdr("g_numStreamableAssets", g_pNumStreamableAssets);
|
||||
LogVarAdr("g_streamingDownloadProgress", g_pStreamingDownloadProgress);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("F0 48 FF 05 ?? ?? ?? ?? C3").GetPtr(v_Pak_IncrementStreamingAssetCount);
|
||||
g_GameDll.FindPatternSIMD("F0 48 FF 0D ?? ?? ?? ?? C3").GetPtr(v_Pak_DecrementStreamingAssetCount);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
extern PakHandle_t(*v_Pak_Initialize)(int mode);
|
||||
CMemory(v_Pak_Initialize).Offset(0x120).FindPatternSelf("48 89 05").ResolveRelativeAddressSelf(3, 7).GetPtr(g_pUseAssetStreamingSystem);
|
||||
|
||||
g_GameDll.FindPatternSIMD("F3 0F 10 05 ?? ?? ?? ?? C3 CC CC CC CC CC CC CC 48 89 5C 24 ?? 57 48 81 EC ?? ?? ?? ??")
|
||||
.ResolveRelativeAddress(0x4, 0x8).GetPtr(g_pStreamingDownloadProgress);
|
||||
|
||||
CMemory(v_Pak_IncrementStreamingAssetCount).ResolveRelativeAddress(4, 8).GetPtr(g_pNumStreamableAssets); // 167ED7BB8
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const { };
|
||||
};
|
||||
|
||||
#endif // RTECH_PAKSTREAM_H
|
147
r5dev/rtech/pak/paktools.cpp
Normal file
147
r5dev/rtech/pak/paktools.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: general pak tools
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstate.h"
|
||||
#include "paktools.h"
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// checks if an override file exists and returns whether it should be loaded instead
|
||||
//----------------------------------------------------------------------------------
|
||||
bool Pak_GetOverride(const char* const pakFilePath, char* const outPath, const size_t outBufLen)
|
||||
{
|
||||
// check the overrides path
|
||||
snprintf(outPath, outBufLen, PLATFORM_PAK_OVERRIDE_PATH"%s", V_UnqualifiedFileName(pakFilePath));
|
||||
return FileExists(outPath);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// checks if a pak file exists
|
||||
//----------------------------------------------------------------------------------
|
||||
int Pak_FileExists(const char* const pakFilePath)
|
||||
{
|
||||
char fullPath[1024];
|
||||
if (Pak_GetOverride(pakFilePath, fullPath, sizeof(fullPath)))
|
||||
return true;
|
||||
|
||||
// check the platform's default path
|
||||
snprintf(fullPath, sizeof(fullPath), PLATFORM_PAK_PATH"%s", pakFilePath);
|
||||
|
||||
return FileExists(fullPath);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns pak status as string
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* Pak_StatusToString(const EPakStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case EPakStatus::PAK_STATUS_FREED: return "PAK_STATUS_FREED";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PENDING: return "PAK_STATUS_LOAD_PENDING";
|
||||
case EPakStatus::PAK_STATUS_REPAK_RUNNING: return "PAK_STATUS_REPAK_RUNNING";
|
||||
case EPakStatus::PAK_STATUS_REPAK_DONE: return "PAK_STATUS_REPAK_DONE";
|
||||
case EPakStatus::PAK_STATUS_LOAD_STARTING: return "PAK_STATUS_LOAD_STARTING";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PAKHDR: return "PAK_STATUS_LOAD_PAKHDR";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PATCH_INIT: return "PAK_STATUS_LOAD_PATCH_INIT";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PATCH_EDIT_STREAM: return "PAK_STATUS_LOAD_PATCH_EDIT_STREAM";
|
||||
case EPakStatus::PAK_STATUS_LOAD_ASSETS: return "PAK_STATUS_LOAD_ASSETS";
|
||||
case EPakStatus::PAK_STATUS_LOADED: return "PAK_STATUS_LOADED";
|
||||
case EPakStatus::PAK_STATUS_UNLOAD_PENDING: return "PAK_STATUS_UNLOAD_PENDING";
|
||||
case EPakStatus::PAK_STATUS_FREE_PENDING: return "PAK_STATUS_FREE_PENDING";
|
||||
case EPakStatus::PAK_STATUS_CANCELING: return "PAK_STATUS_CANCELING";
|
||||
case EPakStatus::PAK_STATUS_ERROR: return "PAK_STATUS_ERROR";
|
||||
case EPakStatus::PAK_STATUS_INVALID_PAKHANDLE: return "PAK_STATUS_INVALID_PAKHANDLE";
|
||||
case EPakStatus::PAK_STATUS_BUSY: return "PAK_STATUS_BUSY";
|
||||
default: return "PAK_STATUS_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// compute a guid from input string data
|
||||
//-----------------------------------------------------------------------------
|
||||
PakGuid_t Pak_StringToGuid(const char* const string)
|
||||
{
|
||||
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*)string;
|
||||
|
||||
v1 = a1;
|
||||
v2 = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// gets information about loaded pak file via pak id
|
||||
//-----------------------------------------------------------------------------
|
||||
const PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId)
|
||||
{
|
||||
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
|
||||
{
|
||||
const PakLoadedInfo_t* const info = &g_pLoadedPakInfo[i];
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (info->handle != pakId)
|
||||
continue;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for handle '%d'\n", __FUNCTION__, pakId);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// gets information about loaded pak file via pak name
|
||||
//-----------------------------------------------------------------------------
|
||||
const PakLoadedInfo_t* Pak_GetPakInfo(const char* const pakName)
|
||||
{
|
||||
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
|
||||
{
|
||||
const PakLoadedInfo_t* const info = &g_pLoadedPakInfo[i];
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (!info->fileName || !*info->fileName)
|
||||
continue;
|
||||
|
||||
if (strcmp(pakName, info->fileName) != 0)
|
||||
continue;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
Warning(eDLL_T::RTECH, "%s - Failed to retrieve pak info for name '%s'\n", __FUNCTION__, pakName);
|
||||
return nullptr;
|
||||
}
|
14
r5dev/rtech/pak/paktools.h
Normal file
14
r5dev/rtech/pak/paktools.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef RTECH_PAKTOOLS_H
|
||||
#define RTECH_PAKTOOLS_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
extern bool Pak_GetOverride(const char* const pakFilePath, char* const outPath, const size_t outBufLen);
|
||||
extern int Pak_FileExists(const char* const pakFilePath);
|
||||
|
||||
extern const char* Pak_StatusToString(const EPakStatus status);
|
||||
extern PakGuid_t Pak_StringToGuid(const char* const string);
|
||||
|
||||
extern const PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId);
|
||||
extern const PakLoadedInfo_t* Pak_GetPakInfo(const char* const pakName);
|
||||
|
||||
#endif // !RTECH_PAKTOOLS_H
|
@ -2,7 +2,7 @@
|
||||
#include <tier0/memstd.h>
|
||||
#include "tier1/utlbuffer.h"
|
||||
#include <filesystem/filesystem.h>
|
||||
#include "vpc/rson.h"
|
||||
#include "rtech/rson.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: loads an RSON from a buffer
|
@ -1,593 +0,0 @@
|
||||
//=============================================================================//
|
||||
//
|
||||
// Purpose: RTech game utilities
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "core/stdafx.h"
|
||||
#include "engine/host_cmd.h"
|
||||
#include "engine/host_state.h"
|
||||
#include "engine/cmodel_bsp.h"
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "rtech/rtech_utils.h"
|
||||
|
||||
// Pak handles that have been loaded with the level
|
||||
// from within the level settings KV (located in
|
||||
// scripts/levels/settings/*.kv). On level unload,
|
||||
// each pak listed in this vector gets unloaded.
|
||||
CUtlVector<PakHandle_t> g_vLoadedPakHandle;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: process guid relations for asset
|
||||
// Input : *pak -
|
||||
// *asset -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_ProcessGuidRelationsForAsset(PakFile_t* pak, PakAsset_t* asset)
|
||||
{
|
||||
static const int GLOBAL_MUL = 0x17;
|
||||
|
||||
PakPage_t* pGuidDescriptors = &pak->m_memoryData.m_guidDescriptors[asset->m_usesStartIdx];
|
||||
volatile uint32_t* v5 = reinterpret_cast<volatile uint32_t*>(*(reinterpret_cast<uint64_t*>(g_pPakGlobals) + GLOBAL_MUL * (pak->m_memoryData.qword2D8 & 0x1FF) + 0x160212));
|
||||
const bool bDebug = rtech_debug->GetBool();
|
||||
|
||||
if (bDebug)
|
||||
Msg(eDLL_T::RTECH, "Processing GUID relations for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i\n", asset->m_guid, pak->m_memoryData.m_fileName, asset->m_usesCount);
|
||||
|
||||
for (uint32_t i = 0; i < asset->m_usesCount; i++)
|
||||
{
|
||||
void** pCurrentGuid = reinterpret_cast<void**>(pak->m_memoryData.m_pagePointers[pGuidDescriptors[i].m_index] + pGuidDescriptors[i].m_offset);
|
||||
|
||||
// Get current guid.
|
||||
const uint64_t currentGuid = reinterpret_cast<uint64_t>(*pCurrentGuid);
|
||||
|
||||
// Get asset index.
|
||||
int assetIdx = currentGuid & 0x3FFFF;
|
||||
uint64_t assetIdxEntryGuid = g_pPakGlobals->m_assets[assetIdx].m_guid;
|
||||
|
||||
const int64_t v9 = 2i64 * InterlockedExchangeAdd(v5, 1u);
|
||||
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 2])) = currentGuid;
|
||||
*reinterpret_cast<uint64_t*>(const_cast<uint32_t*>(&v5[2 * v9 + 4])) = asset->m_guid;
|
||||
|
||||
std::function<bool(bool)> fnCheckAsset = [&](bool shouldCheckTwo)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (shouldCheckTwo && assetIdxEntryGuid == 2)
|
||||
{
|
||||
if (pak->m_memoryData.m_pakHeader.m_assetEntryCount)
|
||||
return false;
|
||||
}
|
||||
|
||||
assetIdx++;
|
||||
|
||||
// Check if we have a deadlock and report it if we have rtech_debug enabled.
|
||||
if (bDebug && assetIdx >= 0x40000)
|
||||
{
|
||||
if (assetIdx == 0x40000) // Only log it once.
|
||||
Warning(eDLL_T::RTECH, "Possible deadlock detected while processing asset '0x%-16llX' in pak '%-32s'. Uses: %-4i | assetIdxEntryGuid: '0x%-16llX' | currentGuid: '0x%-16llX'\n", asset->m_guid, pak->m_memoryData.m_fileName, asset->m_usesCount, assetIdxEntryGuid, currentGuid);
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
DebugBreak();
|
||||
}
|
||||
|
||||
assetIdx &= 0x3FFFF;
|
||||
assetIdxEntryGuid = g_pPakGlobals->m_assets[assetIdx].m_guid;
|
||||
|
||||
if (assetIdxEntryGuid == currentGuid)
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
if (assetIdxEntryGuid != currentGuid)
|
||||
{
|
||||
// Are we some special asset with the guid 2?
|
||||
if (!fnCheckAsset(true))
|
||||
{
|
||||
PakAsset_t* assetEntries = pak->m_memoryData.m_assetEntries;
|
||||
uint64_t a = 0;
|
||||
|
||||
for (; assetEntries->m_guid != currentGuid; a++, assetEntries++)
|
||||
{
|
||||
if (a >= pak->m_memoryData.m_pakHeader.m_assetEntryCount)
|
||||
{
|
||||
fnCheckAsset(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assetIdx = pak->m_memoryData.qword2E0[a];
|
||||
}
|
||||
}
|
||||
|
||||
// Finally write the pointer to the guid entry.
|
||||
*pCurrentGuid = g_pPakGlobals->m_assets[assetIdx].m_head;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: load user-requested pak files on-demand
|
||||
// Input : *fileName -
|
||||
// *allocator -
|
||||
// nIdx -
|
||||
// bUnk -
|
||||
// Output : pak file handle on success, INVALID_PAK_HANDLE on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
PakHandle_t Pak_LoadAsync(const char* fileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk)
|
||||
{
|
||||
PakHandle_t pakHandle = INVALID_PAK_HANDLE;
|
||||
|
||||
CUtlString pakBasePath;
|
||||
CUtlString pakOverridePath;
|
||||
|
||||
pakBasePath.Format(PLATFORM_PAK_PATH "%s", fileName);
|
||||
pakOverridePath.Format(PLATFORM_PAK_OVERRIDE_PATH "%s", fileName);
|
||||
|
||||
if (FileExists(pakOverridePath.Get()) || FileExists(pakBasePath.Get()))
|
||||
{
|
||||
Msg(eDLL_T::RTECH, "Loading pak file: '%s'\n", fileName);
|
||||
pakHandle = v_Pak_LoadAsync(fileName, allocator, nIdx, bUnk);
|
||||
|
||||
if (pakHandle == INVALID_PAK_HANDLE)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed read '%s' results '%u'\n", __FUNCTION__, fileName, pakHandle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: Failed; file '%s' doesn't exist\n", __FUNCTION__, fileName);
|
||||
}
|
||||
|
||||
return pakHandle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: unloads loaded pak files
|
||||
// Input : handle -
|
||||
//-----------------------------------------------------------------------------
|
||||
void Pak_UnloadPak(PakHandle_t handle)
|
||||
{
|
||||
PakLoadedInfo_t* pakInfo = g_pRTech->GetPakLoadedInfo(handle);
|
||||
|
||||
if (pakInfo && pakInfo->m_fileName)
|
||||
{
|
||||
Msg(eDLL_T::RTECH, "Unloading pak file: '%s'\n", pakInfo->m_fileName);
|
||||
|
||||
if (strcmp(pakInfo->m_fileName, "mp_lobby.rpak") == 0)
|
||||
s_bBasePaksInitialized = false;
|
||||
}
|
||||
|
||||
v_Pak_UnloadPak(handle);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: open a file and add it to the file handle array
|
||||
// Input : *filePath -
|
||||
// unused -
|
||||
// *fileSizeOut -
|
||||
// Output : slot index in the array to which the file was added in
|
||||
//----------------------------------------------------------------------------------
|
||||
int32_t Pak_OpenFile(const CHAR* filePath, int64_t unused, LONGLONG* fileSizeOut)
|
||||
{
|
||||
const CHAR* szFileToLoad = filePath;
|
||||
CUtlString pakBasePath(filePath);
|
||||
|
||||
if (pakBasePath.Find(PLATFORM_PAK_PATH) != -1)
|
||||
{
|
||||
pakBasePath = pakBasePath.Replace(PLATFORM_PAK_PATH, PLATFORM_PAK_OVERRIDE_PATH);
|
||||
|
||||
if (FileExists(pakBasePath.Get()))
|
||||
{
|
||||
szFileToLoad = pakBasePath.Get();
|
||||
}
|
||||
}
|
||||
|
||||
const HANDLE hFile = CreateFileA(szFileToLoad, GENERIC_READ,
|
||||
FILE_SHARE_READ | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, 0);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if (rtech_debug->GetBool())
|
||||
Msg(eDLL_T::RTECH, "Opened file: '%s'\n", szFileToLoad);
|
||||
|
||||
if (fileSizeOut)
|
||||
{
|
||||
LARGE_INTEGER fileSize{};
|
||||
if (GetFileSizeEx(hFile, &fileSize))
|
||||
*fileSizeOut = fileSize.QuadPart;
|
||||
}
|
||||
|
||||
AcquireSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*s_pFileArrayMutex));
|
||||
const int32_t fileIdx = RTech_FindFreeSlotInFiles(s_pFileArray);
|
||||
ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&*s_pFileArrayMutex));
|
||||
|
||||
const int32_t fileHandleIdx = (fileIdx & 0x3FF); // Something with ArraySize.
|
||||
|
||||
s_pFileHandles->self[fileHandleIdx].m_nFileNumber = fileIdx;
|
||||
s_pFileHandles->self[fileHandleIdx].m_hFileHandle = hFile;
|
||||
s_pFileHandles->self[fileHandleIdx].m_nCurOfs = 1;
|
||||
|
||||
return fileIdx;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: loads and processes a pak file (handles decompression and patching)
|
||||
// Input : *pak -
|
||||
// Output : true if patch source size == 0, false otherwise
|
||||
// TODO: !!! FINISH REBUILD !!!
|
||||
//----------------------------------------------------------------------------------
|
||||
/*bool __fastcall Pak_ProcessPakFile(PakFile_t* pak)
|
||||
{
|
||||
PakFileHeader_t* pakHeader; // r8
|
||||
__int64 dwordB8; // rcx
|
||||
int v6; // eax
|
||||
__int64 v7; // rax
|
||||
char v8; // r13
|
||||
signed __int64 index_Maybe; // rdi
|
||||
char v10; // r15
|
||||
__int64 v11; // rdx
|
||||
const char* v12; // rbp
|
||||
unsigned int v13; // eax
|
||||
__int64 v14; // r12
|
||||
char byteBF; // al
|
||||
unsigned __int64 v16; // r9
|
||||
unsigned __int8 v17; // cl
|
||||
unsigned __int64 v18; // r8
|
||||
__int64 v19; // rdx
|
||||
uint8_t byte1F8; // al
|
||||
uint8_t byte1FD; // cl
|
||||
_BYTE* v22; // rdi
|
||||
uint64_t v23; // rax
|
||||
PakDecompState_t* p_m_pakDecompState; // rbp
|
||||
__int64 decomp_size_var; // rax
|
||||
uint64_t v26; // rdx
|
||||
uint64_t qword1D0; // rcx
|
||||
__int64 v28; // rax
|
||||
unsigned int m_bitsRemaining; // r8d
|
||||
char* m_patchData; // rdx
|
||||
unsigned __int64 v31; // rax
|
||||
uint64_t m_dataBuf; // r11
|
||||
int v33; // r8d
|
||||
uint64_t v34; // rax
|
||||
int v35; // ecx
|
||||
__int64 v36; // rdx
|
||||
uint64_t v37; // r11
|
||||
__int64(__fastcall * v38)(); // rax
|
||||
int v39; // r10d
|
||||
int v40; // r9d
|
||||
uint64_t v41; // r11
|
||||
unsigned int v42; // ecx
|
||||
unsigned int v43; // r8d
|
||||
unsigned int v44; // r12d
|
||||
char byteBC; // r15
|
||||
__int64 v46; // rbp
|
||||
__int64 v47; // r8
|
||||
unsigned __int64 v48; // rbp
|
||||
unsigned __int64 qword8; // rax
|
||||
__int64 v50; // rdi
|
||||
__int64 patchCount; // rcx
|
||||
__int64 v52; // r15
|
||||
char v53; // al
|
||||
char* v54; // rcx
|
||||
char* i; // rdx
|
||||
int v56; // edi
|
||||
__int64 v57; // r15
|
||||
unsigned __int64 v58; // rdx
|
||||
char pak_path_var[260]; // [rsp+40h] [rbp-148h] BYREF
|
||||
char v61[12]; // [rsp+144h] [rbp-44h] BYREF
|
||||
unsigned __int64 v62; // [rsp+190h] [rbp+8h]
|
||||
size_t pak_file_size_var; // [rsp+198h] [rbp+10h] BYREF
|
||||
|
||||
PakFileStream_t* fileStream = &pak->m_fileStream;
|
||||
PakMemoryData_t* memoryData = &pak->m_memoryData;
|
||||
|
||||
dwordB8 = (unsigned int)pak->m_fileStream.dwordB8;
|
||||
if ((_DWORD)dwordB8)
|
||||
v62 = dwordB8 << 19;
|
||||
else
|
||||
v62 = 128i64;
|
||||
v6 = fileStream->unsigned_intB4;
|
||||
if (v6 != (_DWORD)dwordB8)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
v7 = v6 & 0x1F;
|
||||
v8 = fileStream->gap94[v7];
|
||||
if (v8 != 1)
|
||||
break;
|
||||
LABEL_17:
|
||||
v6 = fileStream->unsigned_intB4 + 1;
|
||||
fileStream->unsigned_intB4 = v6;
|
||||
if (v6 == fileStream->dwordB8)
|
||||
goto LABEL_18;
|
||||
}
|
||||
index_Maybe = (unsigned __int64)LOBYTE(fileStream->gap14[v7]) << 6;
|
||||
v10 = *((_BYTE*)&g_pakStatusSlots[0].someState + index_Maybe);
|
||||
switch (v10)
|
||||
{
|
||||
case 0:
|
||||
goto LABEL_18;
|
||||
case 2:
|
||||
v11 = *(unsigned int*)((char*)&g_pakStatusSlots[0].unk7 + index_Maybe);
|
||||
if ((_DWORD)v11 == 0x8716253)
|
||||
v12 = "Error: Short read.";
|
||||
else
|
||||
v12 = StrPrintf("Error 0x%08x", v11);
|
||||
break;
|
||||
case 3:
|
||||
v12 = "Cancelled.";
|
||||
break;
|
||||
default:
|
||||
v12 = "OK";
|
||||
if (v10 == 1)
|
||||
{
|
||||
v13 = *(int*)((char*)&g_pakStatusSlots[0].unk6 + index_Maybe);
|
||||
goto LABEL_11;
|
||||
}
|
||||
break;
|
||||
}
|
||||
v13 = 0;
|
||||
LABEL_11:
|
||||
v14 = v13;
|
||||
v_Pak_CloseFile(*(int*)((char*)&g_pakStatusSlots[0].unk4 + index_Maybe));
|
||||
AcquireSRWLockExclusive(&stru_16721D260);
|
||||
RTech::FreeSlotInFiles((__int64)&dword_16721D240, index_Maybe >> 6);
|
||||
ReleaseSRWLockExclusive(&stru_16721D260);
|
||||
if (v10 == 2)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "Error reading pak file \"%s\" -- %s\n", pak->m_memoryData.m_fileName, v12);
|
||||
fileStream->qword1D0 += v14;
|
||||
if (v8)
|
||||
{
|
||||
byteBF = fileStream->byteBF;
|
||||
pakHeader = &pak->m_memoryData.m_pakHeader;
|
||||
v16 = (unsigned __int64)fileStream->unsigned_intB4 << 19;
|
||||
v17 = byteBF & 7;
|
||||
fileStream->byteBF = byteBF + 1;
|
||||
if (v8 == 2)
|
||||
{
|
||||
v18 = v16 & fileStream->qword1C8;
|
||||
fileStream->qword1D0 = v14 + v16;
|
||||
pakHeader = (PakFileHeader_t*)&fileStream->buffer[v18];
|
||||
}
|
||||
v19 = 32i64 * v17;
|
||||
*(_QWORD*)&fileStream->gapC0[32 * v17] = v16 + 128;
|
||||
*(_QWORD*)&fileStream->gapC0[v19 + 8] = v16 + pakHeader->m_compressedSize;
|
||||
*(_QWORD*)&fileStream->gapC0[v19 + 16] = pakHeader->m_decompressedSize;
|
||||
fileStream->gapC0[v19 + 24] = pakHeader->m_flags[1] & 1;
|
||||
}
|
||||
goto LABEL_17;
|
||||
}
|
||||
LABEL_18:
|
||||
byte1F8 = pak->byte1F8;
|
||||
if (byte1F8 != fileStream->byteBF)
|
||||
{
|
||||
byte1FD = pak->byte1FD;
|
||||
do
|
||||
{
|
||||
v22 = &fileStream->gapC0[32 * (byte1F8 & 7)];
|
||||
if (byte1FD)
|
||||
{
|
||||
pak->byte1FD = 0;
|
||||
pak->m_inputBytePos = *(_QWORD*)v22;
|
||||
if (v22[24])
|
||||
{
|
||||
pak->flags_1FE = 256;
|
||||
v23 = 128i64;
|
||||
}
|
||||
else
|
||||
{
|
||||
pak->flags_1FE = 1;
|
||||
v23 = *(_QWORD*)v22;
|
||||
}
|
||||
memoryData->m_processedPatchedDataSize = v23;
|
||||
if (!HIBYTE(pak->flags_1FE))
|
||||
{
|
||||
LABEL_35:
|
||||
v26 = *((_QWORD*)v22 + 1);
|
||||
qword1D0 = v26;
|
||||
if (fileStream->qword1D0 < v26)
|
||||
qword1D0 = fileStream->qword1D0;
|
||||
goto LABEL_41;
|
||||
}
|
||||
p_m_pakDecompState = &pak->m_pakDecompState;
|
||||
decomp_size_var = RTech::DecompressedSize(
|
||||
&pak->m_pakDecompState,
|
||||
(uint64_t)fileStream->buffer,
|
||||
(__int64)pakHeader,
|
||||
*((_QWORD*)v22 + 1) - (*(_QWORD*)v22 - sizeof(PakFileHeader_t)),
|
||||
*(_QWORD*)v22 - sizeof(PakFileHeader_t));
|
||||
|
||||
if (decomp_size_var != *((_QWORD*)v22 + 2))
|
||||
{
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE,
|
||||
"Error reading pak file \"%s\" -- decompressed size %u doesn't match expected value %u\n",
|
||||
pak->m_memoryData.m_fileName,
|
||||
decomp_size_var + sizeof(PakFileHeader_t),
|
||||
pak->m_memoryData.m_pakHeader.m_decompressedSize);
|
||||
}
|
||||
|
||||
pak->m_pakDecompState.m_outputBuf = (uint64_t)pak->m_decompBuffer;
|
||||
pak->m_pakDecompState.m_outputMask = 0x3FFFFFi64;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_m_pakDecompState = &pak->m_pakDecompState;
|
||||
}
|
||||
if (!HIBYTE(pak->flags_1FE))
|
||||
goto LABEL_35;
|
||||
qword1D0 = pak->m_pakDecompState.m_decompBytePosition;
|
||||
if (qword1D0 != pak->m_pakDecompState.m_decompSize)
|
||||
{
|
||||
Rtech::Decompress(p_m_pakDecompState, fileStream->qword1D0, memoryData->m_processedPatchedDataSize + 0x400000);
|
||||
qword1D0 = pak->m_pakDecompState.m_decompBytePosition;
|
||||
pak->m_inputBytePos = pak->m_pakDecompState.m_fileBytePosition;
|
||||
}
|
||||
v26 = *((_QWORD*)v22 + 1);
|
||||
LABEL_41:
|
||||
if (pak->m_inputBytePos != v26 || memoryData->m_processedPatchedDataSize != qword1D0)
|
||||
goto LABEL_45;
|
||||
byte1FD = 1;
|
||||
byte1F8 = pak->byte1F8 + 1;
|
||||
pak->byte1FD = 1;
|
||||
pak->byte1F8 = byte1F8;
|
||||
} while (byte1F8 != fileStream->byteBF);
|
||||
}
|
||||
qword1D0 = memoryData->m_processedPatchedDataSize;
|
||||
LABEL_45:
|
||||
v28 = memoryData->field_2A8;
|
||||
pak_file_size_var = qword1D0 - memoryData->m_processedPatchedDataSize;
|
||||
if (memoryData->m_patchSrcSize + v28)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!memoryData->m_numBytesToProcess_maybe)
|
||||
{
|
||||
m_bitsRemaining = memoryData->m_bitBuf.m_bitsRemaining;
|
||||
m_patchData = memoryData->m_patchData;
|
||||
memoryData->m_bitBuf.m_dataBuf |= *m_patchData << (64 - (unsigned __int8)m_bitsRemaining);
|
||||
v31 = m_bitsRemaining;
|
||||
m_dataBuf = memoryData->m_bitBuf.m_dataBuf;
|
||||
v33 = m_bitsRemaining & 7;
|
||||
memoryData->m_bitBuf.m_bitsRemaining = v33;
|
||||
memoryData->m_patchData = m_patchData + (v31 >> 3);
|
||||
v34 = m_dataBuf & 0x3F;
|
||||
v35 = (unsigned __int8)memoryData->PATCH_field_68[v34];
|
||||
v36 = (unsigned __int8)memoryData->patchCommands[v34];
|
||||
v37 = m_dataBuf >> v35;
|
||||
memoryData->m_bitBuf.m_dataBuf = v37;
|
||||
v38 = s_pakPatchFuncs[v36];
|
||||
memoryData->m_bitBuf.m_bitsRemaining = v33 + v35;
|
||||
memoryData->patchFunc = (unsigned __int8(__fastcall*)(PakFile_t*, unsigned __int64*))v38;
|
||||
if ((unsigned __int8)v36 > 3u)
|
||||
{
|
||||
memoryData->m_numBytesToProcess_maybe = *((unsigned int*)&off_141367980 + v36);
|
||||
}
|
||||
else
|
||||
{
|
||||
v39 = (unsigned __int8)memoryData->PATCH_unk3[(unsigned __int8)v37];
|
||||
v40 = (unsigned __int8)memoryData->PATCH_unk2[(unsigned __int8)v37];
|
||||
v41 = v37 >> memoryData->PATCH_unk3[(unsigned __int8)v37];
|
||||
memoryData->m_bitBuf.m_dataBuf = v41 >> v40;
|
||||
memoryData->m_numBytesToProcess_maybe = (1i64 << v40) + (v41 & ((1i64 << v40) - 1));
|
||||
memoryData->m_bitBuf.m_bitsRemaining = v33 + v35 + v40 + v39;
|
||||
}
|
||||
}
|
||||
} while (pak->m_memoryData.patchFunc(pak, &pak_file_size_var) && memoryData->m_patchSrcSize + memoryData->field_2A8);
|
||||
}
|
||||
if (LOBYTE(pak->flags_1FE))
|
||||
pak->m_inputBytePos = memoryData->m_processedPatchedDataSize;
|
||||
if (!fileStream->byteBD)
|
||||
{
|
||||
v42 = fileStream->unsigned_intB4;
|
||||
v43 = fileStream->dwordB8;
|
||||
if ((unsigned int)(pak->m_inputBytePos >> 19) < v42)
|
||||
v42 = pak->m_inputBytePos >> 19;
|
||||
v44 = v42 + 32;
|
||||
if (v43 != v42 + 32)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
byteBC = fileStream->byteBC;
|
||||
v46 = v43;
|
||||
v47 = v43 & 0x1F;
|
||||
v48 = (v46 + 1) << 19;
|
||||
if (byteBC == 1)
|
||||
break;
|
||||
qword8 = fileStream->qword8;
|
||||
if (v62 < qword8)
|
||||
{
|
||||
v50 = (unsigned int)v47;
|
||||
if (v48 < qword8)
|
||||
qword8 = v48;
|
||||
fileStream->gap14[(unsigned int)v47] = Pak_SetFileStreamContext(
|
||||
fileStream->fileHandle,
|
||||
v62 - fileStream->qword0,
|
||||
qword8 - v62,
|
||||
&fileStream->buffer[v62 & fileStream->qword1C8],
|
||||
0i64,
|
||||
0i64,
|
||||
4);
|
||||
fileStream->gap94[v50] = byteBC;
|
||||
fileStream->byteBC = 0;
|
||||
goto LABEL_65;
|
||||
}
|
||||
if (pak->m_patchCount >= LOWORD(pak->m_memoryData.m_pakHeader.m_patchIndex))
|
||||
{
|
||||
v_Pak_CloseFile(fileStream->fileHandle);
|
||||
fileStream->fileHandle = -1;
|
||||
fileStream->qword0 = 0i64;
|
||||
fileStream->byteBD = 1;
|
||||
return memoryData->m_patchSrcSize == 0;
|
||||
}
|
||||
if (!pak->dword14)
|
||||
return memoryData->m_patchSrcSize == 0;
|
||||
sprintf(pak_path_var, "paks\\Win64\\%s", pak->m_memoryData.m_fileName);
|
||||
patchCount = pak->m_patchCount;
|
||||
v52 = (unsigned int)patchCount;
|
||||
pak->m_patchCount = patchCount + 1;
|
||||
if (pak->m_memoryData.UnkPatchIndexes[patchCount])
|
||||
{
|
||||
v53 = pak_path_var[0];
|
||||
v54 = pak_path_var;
|
||||
for (i = 0i64; v53; ++v54)
|
||||
{
|
||||
if (v53 == '.')
|
||||
{
|
||||
i = v54;
|
||||
}
|
||||
else if (v53 == '\\' || v53 == '/')
|
||||
{
|
||||
i = 0i64;
|
||||
}
|
||||
v53 = v54[1];
|
||||
}
|
||||
if (i)
|
||||
v54 = i;
|
||||
snprintf(v54, v61 - v54, "(%02u).rpak");
|
||||
}
|
||||
|
||||
v56 = v_Pak_OpenFile(pak_path_var, 5i64, (__int64*)&pak_file_size_var);
|
||||
|
||||
if (v56 == -1)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "Couldn't open file \"%s\".\n", pak_path_var);
|
||||
|
||||
v57 = v52;
|
||||
|
||||
if (pak_file_size_var < pak->m_memoryData.m_patchHeaders[v57].m_sizeDisk)
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "File \"%s\" appears truncated.\n", pak_path_var);
|
||||
|
||||
v_Pak_CloseFile(fileStream->fileHandle);
|
||||
v43 = fileStream->dwordB8;
|
||||
fileStream->fileHandle = v56;
|
||||
v58 = (unsigned __int64)((v43 + 7) & 0xFFFFFFF8) << 19;
|
||||
fileStream->qword0 = v58;
|
||||
fileStream->byteBC = (v43 == ((v43 + 7) & 0xFFFFFFF8)) + 1;
|
||||
fileStream->qword8 = v58 + pak->m_memoryData.m_patchHeaders[v57].m_sizeDisk;
|
||||
LABEL_84:
|
||||
if (v43 == v44)
|
||||
return memoryData->m_patchSrcSize == 0;
|
||||
}
|
||||
fileStream->gap14[v47] = -2;
|
||||
fileStream->gap94[v47] = 1;
|
||||
if ((((_BYTE)v47 + 1) & 7) == 0)
|
||||
fileStream->byteBC = 2;
|
||||
LABEL_65:
|
||||
v43 = ++fileStream->dwordB8;
|
||||
v62 = v48;
|
||||
goto LABEL_84;
|
||||
}
|
||||
}
|
||||
return memoryData->m_patchSrcSize == 0;
|
||||
}*/
|
||||
|
||||
void V_RTechGame::Detour(const bool bAttach) const
|
||||
{
|
||||
DetourSetup(&v_Pak_OpenFile, &Pak_OpenFile, bAttach);
|
||||
|
||||
DetourSetup(&v_Pak_LoadAsync, &Pak_LoadAsync, bAttach);
|
||||
DetourSetup(&v_Pak_UnloadPak, &Pak_UnloadPak, bAttach);
|
||||
|
||||
//DetourSetup(&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset, bAttach);
|
||||
}
|
||||
|
||||
// Symbols taken from R2 dll's.
|
||||
PakLoadFuncs_t* g_pakLoadApi = nullptr;
|
@ -1,96 +0,0 @@
|
||||
#pragma once
|
||||
#include "tier0/tslist.h"
|
||||
#include "launcher/launcher.h"
|
||||
#include "public/rtech/ipakfile.h"
|
||||
|
||||
/* ==== RTECH_GAME ====================================================================================================================================================== */
|
||||
inline PakHandle_t(*v_Pak_LoadAsync)(const char* fileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk);
|
||||
inline EPakStatus(*v_Pak_WaitAsync)(PakHandle_t handle, void* finishCallback);
|
||||
inline unsigned int (*v_Pak_LoadPak)(void* thisptr, void* a2, uint64_t a3);
|
||||
inline void(*v_Pak_UnloadPak)(PakHandle_t handle);
|
||||
inline int(*v_Pak_OpenFile)(const CHAR* fileName, int64_t unused, LONGLONG* outFileSize);
|
||||
inline void(*v_Pak_CloseFile)(short fileHandle);
|
||||
|
||||
inline CMemory p_Pak_OpenFileOffset; // Offset to inlined 'Pak_OpenFile'.
|
||||
|
||||
inline void(*v_Pak_ProcessGuidRelationsForAsset)(PakFile_t* pak, PakAsset_t* asset);
|
||||
|
||||
typedef struct PakLoadFuncs_s
|
||||
{
|
||||
void* LoadPatches;
|
||||
void* RegisterAsset;
|
||||
char unknown0[8];
|
||||
PakHandle_t (*LoadAsync)(const char* pakFileName, CAlignedMemAlloc* allocator, int nIdx, bool bUnk);
|
||||
void* Func4;
|
||||
void (*UnloadPak)(PakHandle_t handle);
|
||||
void* Func6;
|
||||
char unknown2[16];
|
||||
void* Func7;
|
||||
void* Func8;
|
||||
EPakStatus(*WaitAsync)(PakHandle_t handle, void* finishCallback);
|
||||
void* Func10;
|
||||
void* Func11;
|
||||
void* FindByGUID;
|
||||
void* FindByName;
|
||||
char unknown3[8];
|
||||
void* Func14;
|
||||
void* Func15;
|
||||
void* Func16;
|
||||
void* Func17;
|
||||
void* Func18;
|
||||
void* IncrementStreamingAssetCount;
|
||||
void* DecrementStreamingAssetCount;
|
||||
void* IsFullStreamingInstall;
|
||||
char unknown4[48];
|
||||
void* OpenFile;
|
||||
void* CloseFile;
|
||||
void* Func24;
|
||||
void* Func25;
|
||||
void* Func26;
|
||||
void* QueueAsyncFileRead;
|
||||
void* Func28;
|
||||
void* Func29;
|
||||
void* WaitForAsyncFileRead;
|
||||
void* Func31;
|
||||
void* Func32;
|
||||
void* Func33;
|
||||
} PakLoadFuncs_t;
|
||||
|
||||
extern PakLoadFuncs_t* g_pakLoadApi;
|
||||
extern CUtlVector<PakHandle_t> g_vLoadedPakHandle;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_RTechGame : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("Pak_LoadAsync", v_Pak_LoadAsync);
|
||||
LogFunAdr("Pak_WaitAsync", v_Pak_WaitAsync);
|
||||
LogFunAdr("Pak_LoadPak", v_Pak_LoadPak);
|
||||
LogFunAdr("Pak_UnloadPak", v_Pak_UnloadPak);
|
||||
LogFunAdr("Pak_OpenFile", v_Pak_OpenFile);
|
||||
LogFunAdr("Pak_CloseFile", v_Pak_CloseFile);
|
||||
LogFunAdr("Pak_ProcessGuidRelationsForAsset", v_Pak_ProcessGuidRelationsForAsset);
|
||||
LogVarAdr("g_pakLoadApi", g_pakLoadApi);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 03 8B 0B").FollowNearCallSelf().GetPtr(v_Pak_LoadAsync);
|
||||
g_GameDll.FindPatternSIMD("40 53 55 48 83 EC 38 48 89 74 24 ??").GetPtr(v_Pak_WaitAsync);
|
||||
g_GameDll.FindPatternSIMD("48 89 4C 24 ?? 56 41 55 48 81 EC ?? ?? ?? ?? 4C").GetPtr(v_Pak_LoadPak);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 85 FF 74 0C").FollowNearCallSelf().GetPtr(v_Pak_UnloadPak);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 89 85 08 01 ?? ??").FollowNearCallSelf().GetPtr(v_Pak_OpenFile);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B D9 48 8D 35 ?? ?? ?? ??").GetPtr(v_Pak_CloseFile);
|
||||
g_GameDll.FindPatternSIMD("E8 ?? ?? ?? ?? 48 8B 86 ?? ?? ?? ?? 42 8B 0C B0").FollowNearCallSelf().GetPtr(v_Pak_ProcessGuidRelationsForAsset);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
g_pakLoadApi = CMemory(v_LauncherMain).Offset(0x820).FindPatternSelf("48 89").ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakLoadFuncs_t*>();
|
||||
}
|
||||
virtual void GetCon(void) const
|
||||
{
|
||||
p_Pak_OpenFileOffset = g_GameDll.FindPatternSIMD("48 89 7C 24 30 C7 44 24 28 ?? ?? ?? 40");
|
||||
}
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -1,690 +0,0 @@
|
||||
#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(PakDecompState_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_inputBuf = file_buf;
|
||||
state->m_outputBuf = 0i64;
|
||||
state->m_outputMask = 0i64;
|
||||
state->dword44 = 0;
|
||||
state->m_fileSize = fileSize + offNoHeader;
|
||||
state->m_inputMask = mask;
|
||||
input_byte_pos_init = offNoHeader + headerSize + 8;
|
||||
byte_init = *(uint64_t*)((mask & (offNoHeader + headerSize)) + file_buf);
|
||||
state->m_decompBytePosition = headerSize;
|
||||
decompressed_size_bits = byte_init & 0x3F;
|
||||
byte_init >>= 6;
|
||||
state->m_fileBytePosition = input_byte_pos_init;
|
||||
state->m_decompSize = (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_fileBytePosition = 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_inputInvMask = inv_mask_in;
|
||||
state->m_outputInvMask = 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_fileBytePosition = input_byte_pos_final;
|
||||
if (inv_mask_in == -1i64)
|
||||
{
|
||||
state->m_headerOffset = 0;
|
||||
stream_len_needed = fileSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
brih_bytes = brih_bits >> 3;
|
||||
state->m_headerOffset = brih_bytes + 1;
|
||||
byte_tmp = *(uint64_t*)((mask & input_byte_pos_final) + file_buf);
|
||||
state->m_fileBytePosition = input_byte_pos_final + brih_bytes + 1;
|
||||
stream_len_needed = byte_tmp & ((1i64 << (8 * ((uint8_t)brih_bytes + 1))) - 1);
|
||||
}
|
||||
result = state->m_decompSize;
|
||||
inv_mask_out = state->m_outputInvMask;
|
||||
qw70 = offNoHeader + state->m_inputInvMask - 6i64;
|
||||
state->m_bufferSizeNeeded = stream_len_needed + offNoHeader;
|
||||
state->qword70 = qw70;
|
||||
state->m_currentByte = byte_final;
|
||||
state->m_currentByteBit = byte_bit_offset_final;
|
||||
state->dword6C = 0;
|
||||
state->m_compressedStreamSize = stream_len_needed + offNoHeader;
|
||||
state->m_decompStreamSize = result;
|
||||
if (result - 1 > inv_mask_out)
|
||||
{
|
||||
stream_compressed_size_new = stream_len_needed + offNoHeader - state->m_headerOffset;
|
||||
state->m_decompStreamSize = inv_mask_out + 1;
|
||||
state->m_compressedStreamSize = stream_compressed_size_new;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const unsigned char /*unk_141313180*/ s_PakFileCompressionLUT[0x720] =
|
||||
{
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0B,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0xF7,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF3,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0E,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0x09,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF1,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0D,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0xF7,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF2,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF9, 0x04, 0xFD, 0xFC, 0x07, 0x04, 0x05, 0xFF, 0xF4,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF6, 0x04, 0xFD, 0xFC, 0xFB, 0x04, 0x06, 0xFF, 0x0F,
|
||||
0x04, 0xFE, 0xFC, 0x08, 0x04, 0xEF, 0x11, 0xF8, 0x04, 0xFD, 0xFC, 0x0C, 0x04, 0x05, 0xFF, 0x0A,
|
||||
0x04, 0xFE, 0xFC, 0x10, 0x04, 0xEF, 0x11, 0xF5, 0x04, 0xFD, 0xFC, 0xFA, 0x04, 0x06, 0xFF, 0xF0,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0C,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x09,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0E,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0B,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0A,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x10,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0C,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x09,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0F,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x11,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0D,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x07, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x0A,
|
||||
0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0x08, 0x04, 0x05, 0x04, 0x06, 0x04, 0x05, 0x04, 0xFF,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x07,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x07,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x06,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x02, 0x04, 0x03, 0x05, 0x02, 0x04, 0x04, 0x06, 0x02, 0x04, 0x03, 0x06, 0x02, 0x05, 0x04, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x07,
|
||||
0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x03, 0x01, 0x02, 0x01, 0x08,
|
||||
0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x06, 0x00, 0x08, 0x00, 0x01, 0x00, 0x08, 0x00, 0x0B,
|
||||
0x00, 0x08, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x09, 0x00, 0x08, 0x00, 0x03, 0x00, 0x08, 0x00, 0x0E,
|
||||
0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x07, 0x00, 0x08, 0x00, 0x02, 0x00, 0x08, 0x00, 0x0D,
|
||||
0x00, 0x08, 0x00, 0x0C, 0x00, 0x08, 0x00, 0x0A, 0x00, 0x08, 0x00, 0x05, 0x00, 0x08, 0x00, 0x0F,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x01, 0x02, 0x01, 0x05, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06, 0x01, 0x02, 0x01, 0x06,
|
||||
0x4A, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00,
|
||||
0xCA, 0x00, 0x00, 0x00, 0xEA, 0x00, 0x00, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x2A, 0x01, 0x00, 0x00,
|
||||
0x4A, 0x01, 0x00, 0x00, 0x6A, 0x01, 0x00, 0x00, 0x8A, 0x01, 0x00, 0x00, 0xAA, 0x01, 0x00, 0x00,
|
||||
0xAA, 0x03, 0x00, 0x00, 0xAA, 0x05, 0x00, 0x00, 0xAA, 0x25, 0x00, 0x00, 0xAA, 0x25, 0x02, 0x00,
|
||||
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x09, 0x09, 0x0D, 0x11, 0x15,
|
||||
0x00, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x2A, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x05,
|
||||
0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF,
|
||||
0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE,
|
||||
0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C,
|
||||
0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F,
|
||||
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37,
|
||||
0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
|
||||
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xF1, 0x1D, 0xC1, 0xF6, 0x7F, 0x00, 0x00,
|
||||
0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA,
|
||||
0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x3F,
|
||||
0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9, 0x02, 0x61, 0x4D, 0xB9,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||
0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37, 0xC2, 0x14, 0xCF, 0x37,
|
||||
0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0, 0x9E, 0x4B, 0x6F, 0xB0,
|
||||
0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA, 0x22, 0x0B, 0xB6, 0xBA,
|
||||
0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6, 0x00, 0x70, 0x95, 0xB6,
|
||||
0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D, 0xA9, 0xAA, 0x2A, 0x3D,
|
||||
0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x80, 0x3F,
|
||||
0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0xBF,
|
||||
0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE, 0xA8, 0xAA, 0x2A, 0xBE,
|
||||
0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C, 0xD2, 0x85, 0x08, 0x3C,
|
||||
0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F, 0x83, 0xF9, 0x22, 0x3F,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F, 0x00, 0x10, 0xC9, 0x3F,
|
||||
0x4C, 0x39, 0x56, 0x75, 0x42, 0x52, 0x65, 0x75, 0x70, 0x35, 0x31, 0x77, 0x4C, 0x51, 0x64, 0x61,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: decompress input data
|
||||
//-----------------------------------------------------------------------------
|
||||
uint8_t __fastcall RTech::DecompressPakFile(PakDecompState_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_bufferSizeNeeded)
|
||||
return 0;
|
||||
v5 = state->m_decompBytePosition;
|
||||
if (outLen < state->m_outputInvMask + (v5 & ~state->m_outputInvMask) + 1 && outLen < state->m_decompSize)
|
||||
return 0;
|
||||
v6 = state->m_outputBuf;
|
||||
v7 = state->m_currentByteBit;
|
||||
v8 = state->m_currentByte;
|
||||
v9 = state->m_fileBytePosition;
|
||||
v10 = state->qword70;
|
||||
v11 = state->m_inputBuf;
|
||||
if (state->m_compressedStreamSize < v10)
|
||||
v10 = state->m_compressedStreamSize;
|
||||
v12 = state->dword6C;
|
||||
v74 = v11;
|
||||
v70 = v6;
|
||||
v71 = v12;
|
||||
if (!v7)
|
||||
goto LABEL_11;
|
||||
v13 = (*(_QWORD*)((v9 & state->m_inputMask) + 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_inputMask));
|
||||
v71 = 1;
|
||||
v58 = (__int64*)(v6 + (v5 & state->m_outputMask));
|
||||
if (v56 == *((unsigned __int8*)&s_PakFileCompressionLUT + v16 + 1248))
|
||||
{
|
||||
if ((~v9 & state->m_inputInvMask) < 0xF || (state->m_outputInvMask & ~v5) < 15 || state->m_decompSize - 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_outputMask;
|
||||
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_inputMask;
|
||||
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_inputMask) + v11) << (64 - (unsigned __int8)v7)) | v19;
|
||||
}
|
||||
if (v5 != state->m_decompStreamSize)
|
||||
goto LABEL_25;
|
||||
v30 = state->m_decompSize;
|
||||
if (v5 == v30)
|
||||
{
|
||||
result = 1;
|
||||
goto LABEL_69;
|
||||
}
|
||||
v31 = state->m_inputInvMask;
|
||||
v32 = state->m_headerOffset;
|
||||
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_inputMask;
|
||||
v9 += v32;
|
||||
v36 = v5 + state->m_outputInvMask + 1;
|
||||
v37 = *(_QWORD*)(v35 + v11) & ((1i64 << (8 * (unsigned __int8)v32)) - 1);
|
||||
v38 = v37 + state->m_bufferSizeNeeded;
|
||||
v39 = v37 + state->m_compressedStreamSize;
|
||||
state->m_bufferSizeNeeded = v38;
|
||||
state->m_compressedStreamSize = v39;
|
||||
if (v36 >= v30)
|
||||
{
|
||||
v36 = v30;
|
||||
state->m_compressedStreamSize = v32 + v39;
|
||||
}
|
||||
state->m_decompStreamSize = v36;
|
||||
if (inLen >= v38 && outLen >= v36)
|
||||
{
|
||||
LABEL_25:
|
||||
v10 = state->qword70;
|
||||
if (v9 >= v10)
|
||||
{
|
||||
v9 = ~state->m_inputInvMask & (v9 + 7);
|
||||
v10 += state->m_inputInvMask + 1;
|
||||
state->qword70 = v10;
|
||||
}
|
||||
if (state->m_compressedStreamSize < v10)
|
||||
v10 = state->m_compressedStreamSize;
|
||||
goto LABEL_29;
|
||||
}
|
||||
v69 = state->qword70;
|
||||
if (v9 >= v69)
|
||||
{
|
||||
v9 = ~v31 & (v9 + 7);
|
||||
state->qword70 = v69 + v31 + 1;
|
||||
}
|
||||
state->dword6C = v71;
|
||||
result = 0;
|
||||
state->m_currentByte = v19;
|
||||
state->m_currentByteBit = v7;
|
||||
LABEL_69:
|
||||
state->m_decompBytePosition = v5;
|
||||
state->m_fileBytePosition = v9;
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Purpose: start loading shader sets, assign vftable pointer
|
||||
//----------------------------------------------------------------------------------
|
||||
void** RTech::LoadShaderSet(void** VTablePtr)
|
||||
{
|
||||
*VTablePtr = &g_pShaderGlueVFTable;
|
||||
return &g_pShaderGlueVFTable;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: gets information about loaded pak file via pak ID
|
||||
//-----------------------------------------------------------------------------
|
||||
PakLoadedInfo_t* RTech::GetPakLoadedInfo(PakHandle_t nHandle)
|
||||
{
|
||||
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
|
||||
{
|
||||
PakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (info->m_handle != 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
|
||||
//-----------------------------------------------------------------------------
|
||||
PakLoadedInfo_t* RTech::GetPakLoadedInfo(const char* szPakName)
|
||||
{
|
||||
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
|
||||
{
|
||||
PakLoadedInfo_t* info = &g_pLoadedPakInfo[i];
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
if (!info->m_fileName || !*info->m_fileName)
|
||||
continue;
|
||||
|
||||
if (strcmp(szPakName, info->m_fileName) != 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(EPakStatus status)
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case EPakStatus::PAK_STATUS_FREED: return "PAK_STATUS_FREED";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PENDING: return "PAK_STATUS_LOAD_PENDING";
|
||||
case EPakStatus::PAK_STATUS_REPAK_RUNNING: return "PAK_STATUS_REPAK_RUNNING";
|
||||
case EPakStatus::PAK_STATUS_REPAK_DONE: return "PAK_STATUS_REPAK_DONE";
|
||||
case EPakStatus::PAK_STATUS_LOAD_STARTING: return "PAK_STATUS_LOAD_STARTING";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PAKHDR: return "PAK_STATUS_LOAD_PAKHDR";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PATCH_INIT: return "PAK_STATUS_LOAD_PATCH_INIT";
|
||||
case EPakStatus::PAK_STATUS_LOAD_PATCH_EDIT_STREAM: return "PAK_STATUS_LOAD_PATCH_EDIT_STREAM";
|
||||
case EPakStatus::PAK_STATUS_LOAD_ASSETS: return "PAK_STATUS_LOAD_ASSETS";
|
||||
case EPakStatus::PAK_STATUS_LOADED: return "PAK_STATUS_LOADED";
|
||||
case EPakStatus::PAK_STATUS_UNLOAD_PENDING: return "PAK_STATUS_UNLOAD_PENDING";
|
||||
case EPakStatus::PAK_STATUS_FREE_PENDING: return "PAK_STATUS_FREE_PENDING";
|
||||
case EPakStatus::PAK_STATUS_CANCELING: return "PAK_STATUS_CANCELING";
|
||||
case EPakStatus::PAK_STATUS_ERROR: return "PAK_STATUS_ERROR";
|
||||
case EPakStatus::PAK_STATUS_INVALID_PAKHANDLE: return "PAK_STATUS_INVALID_PAKHANDLE";
|
||||
case EPakStatus::PAK_STATUS_BUSY: return "PAK_STATUS_BUSY";
|
||||
default: return "PAK_STATUS_UNKNOWN";
|
||||
}
|
||||
}
|
||||
void V_RTechUtils::Detour(const bool bAttach) const
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
RTech* g_pRTech = new RTech();
|
@ -1,93 +0,0 @@
|
||||
#pragma once
|
||||
#include "tier0/jobthread.h"
|
||||
#include "vpklib/packedstore.h"
|
||||
#include "rtech/rtech_game.h"
|
||||
#include "public/rendersystem/schema/texture.g.h"
|
||||
#include "public/rtech/ipakfile.h"
|
||||
|
||||
/* ==== RTECH =========================================================================================================================================================== */
|
||||
// [ PIXIE ]: I'm very unsure about this, but it really seems like it
|
||||
inline int32_t(*RTech_FindFreeSlotInFiles)(int32_t*);
|
||||
inline void(*RTech_RegisterAsset)(int, int, const char*, void*, void*, void*, void*, int, int, uint32_t, int, int);
|
||||
inline void(*v_StreamDB_Init)(const char* pszLevelName);
|
||||
|
||||
inline PakLoadedInfo_t* g_pLoadedPakInfo;
|
||||
inline int16_t* g_pRequestedPakCount;
|
||||
inline int16_t* g_pLoadedPakCount;
|
||||
inline JobID_t* g_pPakLoadJobID;
|
||||
inline PakGlobals_t* g_pPakGlobals;
|
||||
|
||||
inline int32_t* s_pFileArray;
|
||||
inline PSRWLOCK* s_pFileArrayMutex;
|
||||
inline pFileHandleTracker_t* s_pFileHandles;
|
||||
|
||||
inline JobFifoLock_s* g_pPakFifoLock;
|
||||
inline void* g_pPakFifoLockWrapper; // Pointer to functor that takes the global pak fifolock as argument.
|
||||
inline bool* g_bPakFifoLockAcquired;
|
||||
|
||||
class RTech
|
||||
{
|
||||
public:
|
||||
uint64_t __fastcall StringToGuid(const char* pData);
|
||||
uint8_t __fastcall DecompressPakFile(PakDecompState_t* state, uint64_t inLen, uint64_t outLen);
|
||||
uint64_t __fastcall DecompressPakFileInit(PakDecompState_t* state, uint8_t* fileBuffer, uint64_t fileSize, uint64_t offNoHeader, uint64_t headerSize);
|
||||
PakLoadedInfo_t* GetPakLoadedInfo(PakHandle_t nPakId);
|
||||
PakLoadedInfo_t* GetPakLoadedInfo(const char* szPakName);
|
||||
const char* PakStatusToString(EPakStatus status);
|
||||
|
||||
void** LoadShaderSet(void** VTablePtr);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
extern RTech* g_pRTech;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
class V_RTechUtils : public IDetour
|
||||
{
|
||||
virtual void GetAdr(void) const
|
||||
{
|
||||
LogFunAdr("RTech::FindFreeSlotInFiles", RTech_FindFreeSlotInFiles);
|
||||
|
||||
LogFunAdr("StreamDB_Init", v_StreamDB_Init);
|
||||
LogVarAdr("s_FileArray", s_pFileArray);
|
||||
LogVarAdr("s_FileArrayMutex", s_pFileArrayMutex);
|
||||
LogVarAdr("s_FileHandles", s_pFileHandles);
|
||||
|
||||
LogVarAdr("g_loadedPakInfo", g_pLoadedPakInfo);
|
||||
LogVarAdr("g_loadedPakCount", g_pLoadedPakCount);
|
||||
LogVarAdr("g_requestedPakCount", g_pRequestedPakCount);
|
||||
|
||||
LogVarAdr("g_pakGlobals", g_pPakGlobals);
|
||||
LogVarAdr("g_pakLoadJobID", g_pPakLoadJobID);
|
||||
|
||||
LogVarAdr("g_pakFifoLock", g_pPakFifoLock);
|
||||
LogVarAdr("g_pakFifoLockWrapper", g_pPakFifoLockWrapper);
|
||||
LogVarAdr("g_pakFifoLockAcquired", g_bPakFifoLockAcquired);
|
||||
}
|
||||
virtual void GetFun(void) const
|
||||
{
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 54 41 56 41 57 48 83 EC 40 48 8B E9").GetPtr(v_StreamDB_Init);
|
||||
g_GameDll.FindPatternSIMD("44 8B 51 0C 4C 8B C1").GetPtr(RTech_FindFreeSlotInFiles);
|
||||
g_GameDll.FindPatternSIMD("4D 89 42 08").FindPatternSelf("48 89 6C", CMemory::Direction::UP).GetPtr(RTech_RegisterAsset);
|
||||
}
|
||||
virtual void GetVar(void) const
|
||||
{
|
||||
s_pFileArray = CMemory(v_StreamDB_Init).Offset(0x70).FindPatternSelf("48 8D 0D", CMemory::Direction::DOWN, 512, 2).ResolveRelativeAddress(0x3, 0x7).RCast<int32_t*>();
|
||||
s_pFileHandles = CMemory(v_StreamDB_Init).Offset(0x70).FindPatternSelf("4C 8D", CMemory::Direction::DOWN, 512, 1).ResolveRelativeAddress(0x3, 0x7).RCast<pFileHandleTracker_t*>();
|
||||
s_pFileArrayMutex = CMemory(v_StreamDB_Init).Offset(0x70).FindPatternSelf("48 8D 0D", CMemory::Direction::DOWN, 512, 1).ResolveRelativeAddress(0x3, 0x7).RCast<PSRWLOCK*>();
|
||||
|
||||
g_pLoadedPakInfo = CMemory(v_Pak_UnloadPak).FindPattern("48 8D 05", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakLoadedInfo_t*>();
|
||||
g_pRequestedPakCount = CMemory(v_Pak_UnloadPak).FindPattern("66 89", CMemory::Direction::DOWN, 450).ResolveRelativeAddressSelf(0x3, 0x7).RCast<int16_t*>();
|
||||
g_pLoadedPakCount = &*g_pRequestedPakCount - 1; // '-1' shifts it back with sizeof(int16_t).
|
||||
|
||||
g_pPakGlobals = g_GameDll.FindPatternSIMD("48 8D 1D ?? ?? ?? ?? 45 8D 5A 0E").ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakGlobals_t*>(); /*48 8D 1D ? ? ? ? 45 8D 5A 0E*/
|
||||
g_pPakLoadJobID = reinterpret_cast<JobID_t*>(&*g_pLoadedPakCount - 2);
|
||||
|
||||
g_pPakFifoLock = CMemory(JT_HelpWithAnything).Offset(0x155).FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<JobFifoLock_s*>();
|
||||
g_pPakFifoLockWrapper = CMemory(JT_HelpWithAnything).Offset(0x1BC).FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<void*>();
|
||||
g_bPakFifoLockAcquired = CMemory(JT_HelpWithAnything).Offset(0x50).FindPatternSelf("C6 05").ResolveRelativeAddressSelf(0x2, 0x7).RCast<bool*>();
|
||||
}
|
||||
virtual void GetCon(void) const { }
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef RTECH_RUI_H
|
||||
#define RTECH_RUI_H
|
||||
|
||||
/* ==== RUI ====================================================================================================================================================== */
|
||||
inline bool(*v_Rui_Draw)(__int64* a1, __m128* a2, const __m128i* a3, __int64 a4, __m128* a5);
|
||||
@ -25,3 +26,5 @@ class V_Rui : public IDetour
|
||||
virtual void Detour(const bool bAttach) const;
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // RTECH_RUI_H
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifndef RTECH_STRYDER_H
|
||||
#define RTECH_STRYDER_H
|
||||
|
||||
/* ==== STRYDER ================================================================================================================================================ */
|
||||
inline void*(*v_Stryder_StitchRequest)(void* a1);
|
||||
@ -22,3 +23,5 @@ class VStryder : public IDetour
|
||||
virtual void Detour(const bool bAttach) const { }
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // RTECH_STRYDER_H
|
||||
|
@ -2,6 +2,19 @@
|
||||
#include "engine/host_cmd.h"
|
||||
#include "tier0/jobthread.h"
|
||||
|
||||
|
||||
bool JT_IsJobDone(const JobID_t jobId)
|
||||
{
|
||||
return (job_JT_Context[jobId & 0xFFF].field_24 ^ jobId) & 0xFFFFC000;
|
||||
}
|
||||
|
||||
// TODO: confirm this actually returns a JobID_t and not some other int
|
||||
JobID_t JTGuts_AddJob(JobTypeID_t jobTypeId, JobID_t jobId, void* callbackFunc, void* callbackArg)
|
||||
{
|
||||
const unsigned int jobIndex = JT_AllocateJob();
|
||||
return JTGuts_AddJob_Internal(jobTypeId, jobId, callbackFunc, callbackArg, jobIndex, &job_JT_Context[jobIndex]);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1,5 +1,24 @@
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Convert upper case characters to lower
|
||||
//-----------------------------------------------------------------------------
|
||||
static int FastToLower(char c)
|
||||
{
|
||||
int i = (unsigned char)c;
|
||||
if (i < 0x80)
|
||||
{
|
||||
// Brutally fast branchless ASCII tolower():
|
||||
i += (((('A' - 1) - i) & (i - ('Z' + 1))) >> 26) & 0x20;
|
||||
}
|
||||
else
|
||||
{
|
||||
i += isupper(i) ? 0x20 : 0;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// A special high-performance case-insensitive compare function
|
||||
// returns 0 if strings match exactly
|
||||
@ -910,6 +929,87 @@ V_MakeAbsolutePath(char* pOut, size_t outLen, const char* pPath, const char* pSt
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes a relative path
|
||||
//-----------------------------------------------------------------------------
|
||||
bool V_MakeRelativePath(const char* pFullPath, const char* pDirectory, char* pRelativePath, const size_t nBufLen)
|
||||
{
|
||||
Assert(nBufLen);
|
||||
pRelativePath[0] = 0;
|
||||
|
||||
const char* pPath = pFullPath;
|
||||
const char* pDir = pDirectory;
|
||||
|
||||
// Strip out common parts of the path
|
||||
const char* pLastCommonPath = NULL;
|
||||
const char* pLastCommonDir = NULL;
|
||||
while (*pPath && (FastToLower(*pPath) == FastToLower(*pDir) ||
|
||||
(PATHSEPARATOR(*pPath) && (PATHSEPARATOR(*pDir) || (*pDir == 0)))))
|
||||
{
|
||||
if (PATHSEPARATOR(*pPath))
|
||||
{
|
||||
pLastCommonPath = pPath + 1;
|
||||
pLastCommonDir = pDir + 1;
|
||||
}
|
||||
if (*pDir == 0)
|
||||
{
|
||||
--pLastCommonDir;
|
||||
break;
|
||||
}
|
||||
++pDir; ++pPath;
|
||||
}
|
||||
|
||||
// Nothing in common
|
||||
if (!pLastCommonPath)
|
||||
return false;
|
||||
|
||||
// For each path separator remaining in the dir, need a ../
|
||||
size_t nOutLen = 0;
|
||||
bool bLastCharWasSeparator = true;
|
||||
for (; *pLastCommonDir; ++pLastCommonDir)
|
||||
{
|
||||
if (PATHSEPARATOR(*pLastCommonDir))
|
||||
{
|
||||
pRelativePath[nOutLen++] = '.';
|
||||
pRelativePath[nOutLen++] = '.';
|
||||
pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
|
||||
bLastCharWasSeparator = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bLastCharWasSeparator = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Deal with relative paths not specified with a trailing slash
|
||||
if (!bLastCharWasSeparator)
|
||||
{
|
||||
pRelativePath[nOutLen++] = '.';
|
||||
pRelativePath[nOutLen++] = '.';
|
||||
pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
// Copy the remaining part of the relative path over, fixing the path separators
|
||||
for (; *pLastCommonPath; ++pLastCommonPath)
|
||||
{
|
||||
if (PATHSEPARATOR(*pLastCommonPath))
|
||||
{
|
||||
pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
pRelativePath[nOutLen++] = *pLastCommonPath;
|
||||
}
|
||||
|
||||
// Check for overflow
|
||||
if (nOutLen == nBufLen - 1)
|
||||
break;
|
||||
}
|
||||
|
||||
pRelativePath[nOutLen] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Strip off the last directory from dirName
|
||||
// Input : *dirName -
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <tier1/keyvalues.h>
|
||||
#include <windows/id3dx.h>
|
||||
#include <mathlib/color.h>
|
||||
#include <rtech/rtech_utils.h>
|
||||
#include <rtech/rui/rui.h>
|
||||
#include <vgui/vgui_debugpanel.h>
|
||||
#include <vguimatsurface/MatSystemSurface.h>
|
||||
|
@ -8,8 +8,6 @@ add_sources( SOURCE_GROUP "Private"
|
||||
"IAppSystem.h"
|
||||
"interfaces.cpp"
|
||||
"interfaces.h"
|
||||
"rson.cpp"
|
||||
"rson.h"
|
||||
)
|
||||
|
||||
add_sources( SOURCE_GROUP "Public"
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "vscript/languages/squirrel_re/include/sqstate.h"
|
||||
#include "vscript/languages/squirrel_re/include/sqvm.h"
|
||||
#include "vscript/ivscript.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "rtech/rson.h"
|
||||
|
||||
#define MAX_PRECOMPILED_SCRIPTS 1024
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "vscript/languages/squirrel_re/include/sqstate.h"
|
||||
#include "vscript/languages/squirrel_re/include/sqvm.h"
|
||||
#include "vscript/ivscript.h"
|
||||
#include "vpc/rson.h"
|
||||
#include "rtech/rson.h"
|
||||
|
||||
#define MOD_SCRIPT_PATH_IDENTIFIER "::MOD::"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user