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:
Kawe Mazidjatari 2024-04-05 17:51:19 +02:00
parent 1783db92b5
commit fe2a95e4ec
54 changed files with 4186 additions and 2202 deletions

View File

@ -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");

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -59,7 +59,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
"SV_RCon_Pb"
"CL_RCon_Pb"
"rtech_tools"
"rson"
"rtech_game"
"playlists"
"stryder"

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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";

View File

@ -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"

View File

@ -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
{

View File

@ -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"

View File

@ -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"

View File

@ -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
{

View 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

View File

@ -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

View File

@ -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);

View 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 { };
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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()

View 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
View 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

View 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]);
}
}
}

View 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

View 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;
}

View 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

View 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
View 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

View 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,
};

View 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

View File

@ -0,0 +1,8 @@
//=============================================================================//
//
// Purpose: pak runtime memory and management
//
//=============================================================================//
#include "rtech/ipakfile.h"
#include "pakstate.h"

View 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

View 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);
}
}
}

View 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

View 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;
}

View 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

View File

@ -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

View File

@ -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;

View File

@ -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;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -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();

View File

@ -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;
};
///////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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:
//-----------------------------------------------------------------------------

View File

@ -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 -

View File

@ -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>

View File

@ -8,8 +8,6 @@ add_sources( SOURCE_GROUP "Private"
"IAppSystem.h"
"interfaces.cpp"
"interfaces.h"
"rson.cpp"
"rson.h"
)
add_sources( SOURCE_GROUP "Public"

View File

@ -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

View File

@ -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::"