mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
RTech: major cleanup of pak globals and improvement
Add missing types to fully mapped out PakGlobals_s struct, which is a 13MiB+ structure! This covers the vast majority of the pakfile system which is why we had to change a bunch of stuff for this patch. This patch also comes with: - Reversed 'JobFifoLock_s' structure - Reversed 'PakTracker_s' structure - Reversed 'PakAssetTracker_s' structure Many globals have been dropped as they were covered by the large PakGlobals_s singleton. The pak decoder logic has been changed up as well, we now use a decode mode enumerant which will make it easier to add in more decoders for the pak files in the future.
This commit is contained in:
parent
869741b3b3
commit
6e7bfab4bd
@ -303,9 +303,9 @@ void Pak_ListPaks_f(const CCommand& args)
|
||||
|
||||
uint32_t nTotalLoaded = 0;
|
||||
|
||||
for (int16_t i = 0, n = *g_pLoadedPakCount; i < n; ++i)
|
||||
for (int16_t i = 0, n = g_pakGlobals->loadedPakCount; i < n; ++i)
|
||||
{
|
||||
const PakLoadedInfo_t& info = g_pLoadedPakInfo[i];
|
||||
const PakLoadedInfo_t& info = g_pakGlobals->loadedPaks[i];
|
||||
|
||||
if (info.status == EPakStatus::PAK_STATUS_FREED)
|
||||
continue;
|
||||
@ -335,7 +335,7 @@ void Pak_ListTypes_f(const CCommand& args)
|
||||
|
||||
for (int8_t i = 0; i < PAK_MAX_TYPES; ++i)
|
||||
{
|
||||
PakAssetBinding_t* type = &g_pPakGlobals->assetBindings[i];
|
||||
PakAssetBinding_t* type = &g_pakGlobals->assetBindings[i];
|
||||
|
||||
if (!type->description)
|
||||
continue;
|
||||
|
@ -22,6 +22,10 @@ typedef intptr_t intp;
|
||||
|
||||
typedef const unsigned char* rsig_t;
|
||||
|
||||
// 32bit and 64bit wide boolean type
|
||||
typedef int32_t b32;
|
||||
typedef int64_t b64;
|
||||
|
||||
// signed size types
|
||||
typedef std::make_signed_t<std::size_t> ssize_t;
|
||||
|
||||
|
@ -140,7 +140,7 @@ void Mod_GetAllInstalledMaps()
|
||||
|
||||
if (!regexMatches.empty())
|
||||
{
|
||||
const string match = regexMatches[1].str();
|
||||
const std::sub_match<const char*>& match = regexMatches[1];
|
||||
|
||||
if (match.compare("frontend") == 0)
|
||||
continue; // Frontend contains no BSP's.
|
||||
@ -152,8 +152,12 @@ void Mod_GetAllInstalledMaps()
|
||||
|
||||
continue; // Common contains mp_lobby.
|
||||
}
|
||||
else if (!g_InstalledMaps.HasElement(match.c_str()))
|
||||
g_InstalledMaps.AddToTail(match.c_str());
|
||||
else
|
||||
{
|
||||
const string mapName = match.str();
|
||||
if (!g_InstalledMaps.HasElement(mapName.c_str()))
|
||||
g_InstalledMaps.AddToTail(mapName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,15 +236,18 @@ void Mod_QueuedPakCacheFrame()
|
||||
{
|
||||
if (*data->pakName)
|
||||
{
|
||||
const int index = data->pakId & PAK_MAX_HANDLES_MASK;
|
||||
PakLoadedInfo_t* const pakInfo = Pak_GetPakInfo(data->pakId);
|
||||
EPakStatus status;
|
||||
|
||||
// TODO: revisit this, this appears incorrect but also the way
|
||||
// respawn does this. it this always supposed to be true on
|
||||
// retail builds?
|
||||
bool keepLoaded = true;
|
||||
data->keepLoaded = true;
|
||||
|
||||
if (g_pLoadedPakInfo[index].handle == data->pakId)
|
||||
if (pakInfo->handle == data->pakId)
|
||||
{
|
||||
status = g_pLoadedPakInfo[index].status;
|
||||
status = pakInfo->status;
|
||||
keepLoaded = data->keepLoaded;
|
||||
}
|
||||
else
|
||||
@ -359,12 +366,14 @@ void Mod_QueuedPakCacheFrame()
|
||||
{
|
||||
if (!*(_BYTE*)(pMTVFTaskItem + 4))
|
||||
{
|
||||
if (*g_pPakHasPendingUnloadJobs || *g_pLoadedPakCount != *g_pRequestedPakCount)
|
||||
JobFifoLock_s* const pakFifoLock = &g_pakGlobals->fifoLock;
|
||||
|
||||
if (g_pakGlobals->hasPendingUnloadJobs || g_pakGlobals->loadedPakCount != g_pakGlobals->requestedPakCount)
|
||||
{
|
||||
if (!JT_AcquireFifoLockOrHelp(g_pPakFifoLock)
|
||||
&& !JT_HelpWithJobTypes((__int64(__fastcall*)(__int64, _DWORD*, __int64, _QWORD*))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64))
|
||||
if (!JT_AcquireFifoLockOrHelp(pakFifoLock)
|
||||
&& !JT_HelpWithJobTypes(g_pPakFifoLockWrapper, pakFifoLock, -1i64, 0i64))
|
||||
{
|
||||
JT_HelpWithJobTypesOrSleep((unsigned __int8(__fastcall*)(_QWORD))g_pPakFifoLockWrapper, g_pPakFifoLock, -1i64, 0i64, 0i64, 1);
|
||||
JT_HelpWithJobTypesOrSleep(g_pPakFifoLockWrapper, pakFifoLock, -1i64, 0i64, 0i64, 1);
|
||||
}
|
||||
|
||||
Mod_UnloadPendingAndPrecacheRequestedPaks();
|
||||
@ -374,10 +383,11 @@ void Mod_QueuedPakCacheFrame()
|
||||
if (*g_bPakFifoLockAcquired)
|
||||
{
|
||||
*g_bPakFifoLockAcquired = 0;
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
JT_ReleaseFifoLock(pakFifoLock);
|
||||
}
|
||||
}
|
||||
JT_ReleaseFifoLock(g_pPakFifoLock);
|
||||
|
||||
JT_ReleaseFifoLock(pakFifoLock);
|
||||
|
||||
pMTVFTaskItem = *g_pMTVFTaskItem;
|
||||
}
|
||||
@ -413,9 +423,9 @@ CHECK_FOR_FAILURE:
|
||||
|
||||
if (commonData->pakId != INVALID_PAK_HANDLE)
|
||||
{
|
||||
const int infoIndex = (commonData->pakId & PAK_MAX_HANDLES_MASK);
|
||||
const PakLoadedInfo_t* const pli = Pak_GetPakInfo(commonData->pakId);
|
||||
|
||||
if (g_pLoadedPakInfo[infoIndex].handle != commonData->pakId || ((g_pLoadedPakInfo[infoIndex].status - 9) & 0xFFFFFFFB) != 0)
|
||||
if (pli->handle != commonData->pakId || ((pli->status - 9) & 0xFFFFFFFB) != 0)
|
||||
{
|
||||
*g_pPakPrecacheJobFinished = false;
|
||||
return;
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "rtech/iasync.h"
|
||||
#include "rtech/rstdlib.h"
|
||||
#include "thirdparty/zstd/zstd.h"
|
||||
|
||||
// pak header versions
|
||||
#define PAK_HEADER_MAGIC (('k'<<24)+('a'<<16)+('P'<<8)+'R')
|
||||
@ -13,19 +12,25 @@
|
||||
|
||||
// pak header flags
|
||||
#define PAK_HEADER_FLAGS_HAS_MODULE (1<<0)
|
||||
#define PAK_HEADER_FLAGS_HAS_MODULE_EXTENDED PAK_HEADER_FLAGS_HAS_MODULE | (1<<1)
|
||||
|
||||
#define PAK_HEADER_FLAGS_COMPRESSED (1<<8)
|
||||
|
||||
// use the ZStd decoder instead of the RTech one
|
||||
#define PAK_HEADER_FLAGS_ZSTREAM (1<<9)
|
||||
#define PAK_HEADER_FLAGS_ZSTREAM_ENCODED (1<<9)
|
||||
|
||||
// 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 0x40000 // TODO: rename to PAK_MAX_LOADED_ASSETS
|
||||
#define PAK_MAX_ASSETS_MASK (PAK_MAX_ASSETS-1)
|
||||
|
||||
// max amount of global pak assets tracked at runtime
|
||||
#define PAK_MAX_TRACKED_ASSETS (PAK_MAX_ASSETS/2)
|
||||
#define PAK_MAX_TRACKED_ASSETS_MASK (PAK_MAX_TRACKED_ASSETS-1)
|
||||
|
||||
// max amount of segments a pak file could have
|
||||
#define PAK_MAX_SEGMENTS 20
|
||||
|
||||
@ -37,7 +42,7 @@
|
||||
#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 512 // TODO: rename to PAK_MAX_LOADED_PAKS
|
||||
#define PAK_MAX_HANDLES_MASK (PAK_MAX_HANDLES-1)
|
||||
|
||||
// max amount of async streaming requests that could be made per pak file, if a
|
||||
@ -51,7 +56,8 @@
|
||||
// size is below PAK_DECODE_IN_RING_BUFFER_SIZE, the system allocates a
|
||||
// buffer with the size of the compressed pak + the value of this define
|
||||
// the system should still use the default ring buffer input size for decoding
|
||||
// as these pak files get decoded in one-go; there is buffer wrapping going on
|
||||
// as these pak files get decoded in one-go; there is no input buffer wrapping
|
||||
// going on
|
||||
#define PAK_DECODE_IN_RING_BUFFER_SMALL_SIZE 0x1000
|
||||
#define PAK_DECODE_IN_RING_BUFFER_SMALL_MASK (PAK_DECODE_IN_RING_BUFFER_SMALL_SIZE-1)
|
||||
|
||||
@ -64,6 +70,9 @@
|
||||
#define PAK_DECODE_OUT_RING_BUFFER_SIZE 0x400000
|
||||
#define PAK_DECODE_OUT_RING_BUFFER_MASK (PAK_DECODE_OUT_RING_BUFFER_SIZE-1)
|
||||
|
||||
// max amount to read per async fs read request
|
||||
#define PAK_READ_DATA_CHUNK_SIZE (1ull << 19)
|
||||
|
||||
// base pak directory containing paks sorted in platform specific subdirectories
|
||||
#define PAK_BASE_PATH "paks\\"
|
||||
#define PLATFORM_PAK_PATH PAK_BASE_PATH"Win64\\"
|
||||
@ -73,7 +82,10 @@
|
||||
#define PLATFORM_PAK_OVERRIDE_PATH PAK_BASE_PATH"Win64_override\\"
|
||||
|
||||
// the handle that should be returned when a pak failed to load or process
|
||||
#define INVALID_PAK_HANDLE -1
|
||||
#define INVALID_PAK_HANDLE -1 // TODO: rename to PAK_INVALID_HANDLE
|
||||
|
||||
#define PAK_MAX_DISPATCH_LOAD_JOBS 4
|
||||
#define PAK_DEFAULT_JOB_GROUP_ID 0x3000
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Forward declarations
|
||||
@ -116,6 +128,24 @@ union PakPage_t
|
||||
//-----------------------------------------------------------------------------
|
||||
// Enumerations
|
||||
//-----------------------------------------------------------------------------
|
||||
enum EPakDecodeMode : int32_t
|
||||
{
|
||||
MODE_DISABLED = -1,
|
||||
|
||||
// the default decoder
|
||||
MODE_RTECH,
|
||||
MODE_ZSTD
|
||||
};
|
||||
|
||||
enum EPakStreamSet
|
||||
{
|
||||
STREAMING_SET_MANDATORY = 0,
|
||||
STREAMING_SET_OPTIONAL,
|
||||
|
||||
// number of streaming sets
|
||||
STREAMING_SET_COUNT
|
||||
};
|
||||
|
||||
enum EPakStatus : int32_t
|
||||
{
|
||||
PAK_STATUS_FREED = 0,
|
||||
@ -136,15 +166,6 @@ enum 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
|
||||
{
|
||||
enum EType
|
||||
@ -221,17 +242,152 @@ struct PakAsset_t
|
||||
struct PakAssetShort_t
|
||||
{
|
||||
PakGuid_t guid;
|
||||
uint32_t unk_8;
|
||||
uint32_t trackerIndex;
|
||||
uint32_t unk_C;
|
||||
void* head;
|
||||
void* cpu;
|
||||
};
|
||||
|
||||
struct PakGlobals_t
|
||||
struct PakAssetTracker_s
|
||||
{
|
||||
PakAssetBinding_t assetBindings[PAK_MAX_TYPES]; // [ PIXIE ]: Max possible registered assets on Season 3, 0-2 I did not check yet.
|
||||
PakAssetShort_t assets[PAK_MAX_ASSETS];
|
||||
// end size unknown, but there appears to be stuff below too
|
||||
void* memPage;
|
||||
int trackerIndex;
|
||||
int loadedPakIndex;
|
||||
uint8_t assetTypeHashIdx;
|
||||
char unk_11[3];
|
||||
char unk_10[4];
|
||||
};
|
||||
|
||||
struct PakTracker_s
|
||||
{
|
||||
uint32_t numPaksTracked;
|
||||
int unk_4;
|
||||
int unk_8;
|
||||
char gap_C[644100];
|
||||
int loadedAssetIndices[PAK_MAX_HANDLES];
|
||||
char gap_9DC04[522240];
|
||||
};
|
||||
|
||||
class PakLoadedInfo_t
|
||||
{
|
||||
public:
|
||||
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;
|
||||
JobID_t loadJobId;
|
||||
uint32_t padding_maybe;
|
||||
|
||||
// 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;
|
||||
HMODULE hModule;
|
||||
|
||||
}; //Size: 0x00B8/0x00E8
|
||||
|
||||
struct PakGlobals_s
|
||||
{
|
||||
// [ PIXIE ]: Max possible registered assets on Season 3, 0-2 I did not check yet.
|
||||
PakAssetBinding_t assetBindings[PAK_MAX_TYPES];
|
||||
PakAssetShort_t loadedAssets[PAK_MAX_ASSETS];
|
||||
|
||||
// assets that are tracked across all asset types
|
||||
PakAssetTracker_s trackedAssets[PAK_MAX_TRACKED_ASSETS];
|
||||
|
||||
RHashMap trackedAssetMap; // links to 'trackedAssets'
|
||||
RHashMap loadedPakMap; // links to 'loadedPaks'
|
||||
|
||||
// all currently loaded pak handles
|
||||
PakLoadedInfo_t loadedPaks[PAK_MAX_HANDLES];
|
||||
|
||||
RMultiHashMap unkMap2; // links to 'unkIntArray' and 'unkIntArray2'
|
||||
int unkIntArray[PAK_MAX_TRACKED_ASSETS];
|
||||
int unkIntArray2[PAK_MAX_ASSETS];
|
||||
|
||||
// whether asset streaming (mandatory & optional) is enabled
|
||||
b64 useStreamingSystem;
|
||||
|
||||
// whether we should emulate (fake) our streaming install for debugging
|
||||
b64 emulateStreamingInstallInit;
|
||||
b64 emulateStreamingInstall;
|
||||
|
||||
// mounted # streamable assets (globally across all paks)
|
||||
int64_t numStreamableAssets;
|
||||
b64 hasPendingUnloadJobs;
|
||||
|
||||
// paks that contain tracked assets
|
||||
PakTracker_s* pakTracker;
|
||||
|
||||
// called when threads have to be synced (e.g. syncing the render thread
|
||||
// when we execute the unloading of paks and assets)
|
||||
void* threadSyncFunc;
|
||||
|
||||
// the index to the asset in the trackedAssets array of the last asset we
|
||||
// tracked
|
||||
int lastAssetTrackerIndex;
|
||||
bool updateSplitScreenAnims;
|
||||
|
||||
// the current # pending asset loading jobs
|
||||
int16_t numAssetLoadJobs;
|
||||
JobFifoLock_s fifoLock;
|
||||
JobID_t pakLoadJobId;
|
||||
|
||||
int16_t loadedPakCount;
|
||||
int16_t requestedPakCount;
|
||||
|
||||
PakHandle_t loadedPakHandles[PAK_MAX_HANDLES];
|
||||
|
||||
JobTypeID_t assetBindJobTypes[PAK_MAX_TYPES];
|
||||
JobTypeID_t jobTypeSlots_Unused[PAK_MAX_TYPES];
|
||||
|
||||
JobTypeID_t dispatchLoadJobTypes[PAK_MAX_DISPATCH_LOAD_JOBS];
|
||||
uint8_t dispathLoadJobPriorities[PAK_MAX_DISPATCH_LOAD_JOBS]; // promoted to JobPriority_e
|
||||
uint32_t dispatchLoadJobAffinities[PAK_MAX_DISPATCH_LOAD_JOBS];
|
||||
|
||||
RTL_SRWLOCK cpuDataLock;
|
||||
char unknown_or_unused[32];
|
||||
void* addToMapFunc;
|
||||
void* removeFromMapFunc;
|
||||
__int64 qword_167ED8540;
|
||||
int dword_167ED8548;
|
||||
int dword_167ED854C;
|
||||
__int64 qword_167ED8550;
|
||||
int dword_167ED8558;
|
||||
int unknown_dword_or_nothing;
|
||||
int dword_167ED8560;
|
||||
int numPatchedPaks;
|
||||
const char** patchedPakFiles;
|
||||
uint8_t* patchNumbers;
|
||||
};
|
||||
|
||||
struct PakPatchFileHeader_t
|
||||
@ -275,9 +431,19 @@ struct PakFileHeader_t
|
||||
return headerSize;
|
||||
}
|
||||
|
||||
inline bool IsCompressed() const
|
||||
inline EPakDecodeMode GetCompressionMode() const
|
||||
{
|
||||
return flags & PAK_HEADER_FLAGS_COMPRESSED;
|
||||
if (flags & PAK_HEADER_FLAGS_ZSTREAM_ENCODED)
|
||||
return EPakDecodeMode::MODE_ZSTD;
|
||||
|
||||
// NOTE: this should be the first check once we rebuilt function
|
||||
// 14043F300 and alloc ring buffer for the flags individually instead
|
||||
// instead of having to define the main compress flag (which really
|
||||
// just means that the pak is using the RTech decoder)
|
||||
else if (flags & PAK_HEADER_FLAGS_COMPRESSED)
|
||||
return EPakDecodeMode::MODE_RTECH;
|
||||
|
||||
return EPakDecodeMode::MODE_DISABLED;
|
||||
}
|
||||
|
||||
// file versions
|
||||
@ -369,29 +535,45 @@ struct PakDecoder_t
|
||||
uint64_t outputInvMask;
|
||||
|
||||
uint32_t headerOffset;
|
||||
uint32_t padding; // unused data, available for other stuff
|
||||
|
||||
// this field was unused, it now contains the decoder mode
|
||||
EPakDecodeMode decodeMode;
|
||||
|
||||
// NOTE: unless you are in the RTech decoder, use the getter if you need to
|
||||
// get the current pos!!!
|
||||
uint64_t inBufBytePos;
|
||||
// NOTE: unless you are in the RTech decoder, use the getter if you need to
|
||||
// get the current pos!!!
|
||||
uint64_t outBufBytePos;
|
||||
|
||||
size_t bufferSizeNeeded;
|
||||
|
||||
// current byte and current bit of byte
|
||||
uint64_t currentByte;
|
||||
uint32_t currentBit;
|
||||
union
|
||||
{
|
||||
// current byte and current bit of byte
|
||||
uint64_t currentByte;
|
||||
};
|
||||
|
||||
uint32_t currentBit;
|
||||
uint32_t dword6C;
|
||||
|
||||
uint64_t qword70;
|
||||
|
||||
union
|
||||
{
|
||||
size_t compressedStreamSize;
|
||||
|
||||
// compressedStreamSize isn't used on ZStd paks, instead, we need to
|
||||
// store the frame header size
|
||||
size_t frameHeaderSize;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
size_t decompressedStreamSize;
|
||||
|
||||
// decompressedStreamSize isn't used on ZStd paks; use this space for
|
||||
// the decoder
|
||||
ZSTD_DStream* zstreamContext;
|
||||
};
|
||||
};
|
||||
@ -402,54 +584,6 @@ struct PakRingBufferFrame_t
|
||||
size_t frameLen;
|
||||
};
|
||||
|
||||
struct PakFile_t;
|
||||
|
||||
class PakLoadedInfo_t
|
||||
{
|
||||
public:
|
||||
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 PakFileStream_t
|
||||
{
|
||||
struct Descriptor
|
||||
@ -460,20 +594,20 @@ struct PakFileStream_t
|
||||
|
||||
// NOTE: if this is set, the game sets 'PakMemoryData_t::processedPatchedDataSize'
|
||||
// to 'dataOffset'; else its getting set to 'sizeof(PakFileHeader_t)'.
|
||||
bool isCompressed;
|
||||
EPakDecodeMode compressionMode;
|
||||
};
|
||||
|
||||
_QWORD qword0;
|
||||
_QWORD qword8;
|
||||
_QWORD fileSize;
|
||||
int fileHandle;
|
||||
int gap14[32];
|
||||
int asyncRequestHandles[32];
|
||||
_BYTE gap94[32];
|
||||
unsigned int unsigned_intB4;
|
||||
_DWORD dwordB8;
|
||||
_BYTE byteBC;
|
||||
unsigned int numDataChunksProcessed;
|
||||
_DWORD numDataChunks;
|
||||
_BYTE fileReadStatus;
|
||||
bool finishedLoadingPatches;
|
||||
_BYTE gapBE;
|
||||
_BYTE byteBF;
|
||||
_BYTE numLoadedFiles;
|
||||
Descriptor descriptors[PAK_MAX_ASYNC_STREAMED_LOAD_REQUESTS];
|
||||
uint8_t* buffer;
|
||||
_QWORD bufferMask;
|
||||
@ -536,8 +670,8 @@ struct PakMemoryData_t
|
||||
|
||||
uint64_t qword2D0;
|
||||
PakHandle_t pakId;
|
||||
JobID_t unkJobID;
|
||||
int* qword2E0;
|
||||
JobID_t assetLoadJobId;
|
||||
int* loadedAssetIndices;
|
||||
uint8_t** memPageBuffers;
|
||||
|
||||
PakPatchFileHeader_t* patchHeaders;
|
||||
@ -684,22 +818,13 @@ struct PakFile_t
|
||||
}
|
||||
};
|
||||
|
||||
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(UnknownPakStruct_t) == 0x11D410);
|
||||
static_assert(sizeof(PakTracker_s) == 0x11D410);
|
||||
static_assert(sizeof(PakFile_t) == 2224); // S3+
|
||||
static_assert(sizeof(PakLoadedInfo_t) == 184);
|
||||
static_assert(sizeof(PakDecoder_t) == 136);
|
||||
static_assert(sizeof(PakPatchFileHeader_t) == 16);
|
||||
static_assert(sizeof(PakPatchDataHeader_t) == 8);
|
||||
static_assert(sizeof(PakGlobals_s) == 0xC98A48);
|
||||
|
||||
#endif // RTECH_IPACKFILE_H
|
||||
|
@ -55,25 +55,64 @@ private:
|
||||
SRWLOCK m_lock;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
class RBitRead
|
||||
struct RMultiHashMap
|
||||
{
|
||||
public:
|
||||
FORCEINLINE uint64_t ReadBits(const uint32_t numBits)
|
||||
int globalIndex;
|
||||
int firstBufSize;
|
||||
void* firstBuffer;
|
||||
void* secondBuffer;
|
||||
int firstSlotsUsed;
|
||||
int secondSlotsUsed;
|
||||
int firstIndex;
|
||||
int secondIndex;
|
||||
int secondBufMask;
|
||||
};
|
||||
|
||||
#pragma pack(push, 4)
|
||||
|
||||
struct RBitRead
|
||||
{
|
||||
unsigned __int64 m_dataBuf;
|
||||
unsigned int m_bitsAvailable;
|
||||
|
||||
RBitRead() : m_dataBuf(0), m_bitsAvailable(64) {};
|
||||
|
||||
FORCEINLINE void ConsumeData(unsigned __int64 input, unsigned int numBits = 64)
|
||||
{
|
||||
Assert(numBits <= 64, "RBitRead::ReadBits: numBits must be less than or equal to 64.");
|
||||
if (numBits > m_bitsAvailable)
|
||||
{
|
||||
assert(false && "RBitRead::ConsumeData: numBits must be less than or equal to m_bitsAvailable.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataBuf |= input << (64 - numBits);
|
||||
}
|
||||
|
||||
FORCEINLINE void ConsumeData(void* input, unsigned int numBits = 64)
|
||||
{
|
||||
if (numBits > m_bitsAvailable)
|
||||
{
|
||||
assert(false && "RBitRead::ConsumeData: numBits must be less than or equal to m_bitsAvailable.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataBuf |= *reinterpret_cast<unsigned __int64*>(input) << (64 - numBits);
|
||||
}
|
||||
|
||||
FORCEINLINE int BitsAvailable() const { return m_bitsAvailable; };
|
||||
|
||||
FORCEINLINE unsigned __int64 ReadBits(unsigned int 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)
|
||||
FORCEINLINE void DiscardBits(unsigned int numBits)
|
||||
{
|
||||
Assert(numBits <= 64, "RBitRead::DiscardBits: numBits must be less than or equal to 64.");
|
||||
assert(numBits <= 64 && "RBitRead::DiscardBits: numBits must be less than or equal to 64.");
|
||||
this->m_dataBuf >>= numBits;
|
||||
this->m_bitsRemaining += numBits;
|
||||
this->m_bitsAvailable += numBits;
|
||||
}
|
||||
|
||||
uint64_t m_dataBuf;
|
||||
int m_bitsRemaining;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -4,8 +4,13 @@
|
||||
typedef uint32_t JobID_t;
|
||||
typedef uint8_t JobTypeID_t;
|
||||
|
||||
typedef bool(*JobHelpCallback_t)(__int64, _DWORD*, __int64, _QWORD*);
|
||||
|
||||
struct JobFifoLock_s
|
||||
{
|
||||
int id;
|
||||
int depth;
|
||||
short tls[64];
|
||||
};
|
||||
|
||||
struct JobContext_s
|
||||
@ -35,13 +40,14 @@ extern JobID_t JTGuts_AddJob(JobTypeID_t jobTypeId, JobID_t jobId, void* callbac
|
||||
inline void(*JT_ParallelCall)(void);
|
||||
inline void*(*JT_HelpWithAnything)(bool bShouldLoadPak);
|
||||
|
||||
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_HelpWithJobTypes)(JobHelpCallback_t, JobFifoLock_s* pFifoLock, __int64 a3, __int64 a4);
|
||||
inline __int64(*JT_HelpWithJobTypesOrSleep)(JobHelpCallback_t, 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);
|
||||
|
||||
|
@ -53,7 +53,7 @@ extern void FS_CloseAsyncFile(const int fileHandle);
|
||||
inline int(*v_FS_OpenAsyncFile)(const char* const filePath, const int logLevel, size_t* const outFileSize);
|
||||
inline void(*v_FS_CloseAsyncFile)(const int fileHandle);
|
||||
|
||||
inline int(*v_FS_ReadAsyncFile)(int a1, __int64 a2, unsigned __int64 a3, void* a4, void* a5, void* a6, int a7);
|
||||
inline int(*v_FS_ReadAsyncFile)(const int fileHandle, __int64 readOffset, unsigned __int64 readSize, 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).
|
||||
|
@ -17,7 +17,7 @@ void Pak_AlignSegmentHeaders(PakFile_t* const pak, PakSegmentDescriptor_t* const
|
||||
|
||||
for (uint8_t i = 0; i < PAK_MAX_TYPES; ++i)
|
||||
{
|
||||
const PakAssetBinding_t& binding = g_pPakGlobals->assetBindings[i];
|
||||
const PakAssetBinding_t& binding = g_pakGlobals->assetBindings[i];
|
||||
|
||||
if (desc->assetTypeCount[i])
|
||||
{
|
||||
|
@ -6,9 +6,6 @@
|
||||
#include "tier0/binstream.h"
|
||||
#include "tier1/fmtstr.h"
|
||||
|
||||
#include "thirdparty/zstd/zstd.h"
|
||||
#include "thirdparty/zstd/decompress/zstd_decompress_internal.h"
|
||||
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
#include "paktools.h"
|
||||
@ -140,6 +137,8 @@ static const unsigned char /*141313180*/ s_defaultDecoderLUT[] =
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_HasEnoughDecodeBufferAvailable(PakDecoder_t* const decoder, const size_t outLen)
|
||||
{
|
||||
// make sure caller has copied all data out the ring buffer first before
|
||||
// overwriting it with new decoded data
|
||||
const uint64_t bytesWritten = (decoder->outBufBytePos & ~decoder->outputInvMask);
|
||||
return (outLen >= decoder->outputInvMask + (bytesWritten +1) || outLen >= decoder->decompSize);
|
||||
}
|
||||
@ -149,8 +148,11 @@ bool Pak_HasEnoughDecodeBufferAvailable(PakDecoder_t* const decoder, const size_
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_HasEnoughStreamedDataForDecode(PakDecoder_t* const decoder, const size_t inLen)
|
||||
{
|
||||
// the decoder needs at least this many bytes to decode the current block
|
||||
// buffer contiguously
|
||||
// the decoder needs at least this amount of input data streamed in order
|
||||
// to decode the rest of the pak file, as this is where reading has stopped
|
||||
// this value may equal the currently streamed input size, as its possible
|
||||
// this function is getting called to flush the remainder decoded data into
|
||||
// the out buffer which got truncated off on the call prior due to wrapping
|
||||
return (inLen >= decoder->bufferSizeNeeded);
|
||||
}
|
||||
|
||||
@ -176,7 +178,7 @@ PakRingBufferFrame_t Pak_DetermineRingBufferFrame(const uint64_t bufMask, const
|
||||
//-----------------------------------------------------------------------------
|
||||
// initializes the RTech decoder
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t Pak_RStreamDecoderInit(PakDecoder_t* const decoder, const uint8_t* const fileBuffer,
|
||||
size_t Pak_RTechDecoderInit(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 frameHeader = *(_QWORD*)((inputMask & (dataOffset + headerSize)) + fileBuffer);
|
||||
@ -241,7 +243,7 @@ size_t Pak_RStreamDecoderInit(PakDecoder_t* const decoder, const uint8_t* const
|
||||
//-----------------------------------------------------------------------------
|
||||
// decodes the RTech data stream up to available buffer or data
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_RStreamDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen)
|
||||
bool Pak_RTechStreamDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen)
|
||||
{
|
||||
bool result; // al
|
||||
uint64_t outBufBytePos; // r15
|
||||
@ -568,15 +570,9 @@ LABEL_69:
|
||||
//-----------------------------------------------------------------------------
|
||||
// initializes the ZStd decoder
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t Pak_ZStreamDecoderInit(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)
|
||||
size_t Pak_ZStdDecoderInit(PakDecoder_t* const decoder, const uint8_t* frameHeader,
|
||||
const size_t dataSize, const size_t headerSize)
|
||||
{
|
||||
// NOTE: on original paks, this data is parsed out of the frame header,
|
||||
// but for ZStd encoded paks we are always limiting this to the ring
|
||||
// buffer size
|
||||
decoder->inputInvMask = PAK_DECODE_OUT_RING_BUFFER_MASK;
|
||||
decoder->outputInvMask = PAK_DECODE_OUT_RING_BUFFER_MASK;
|
||||
|
||||
ZSTD_DStream* const dctx = ZSTD_createDStream();
|
||||
assert(dctx);
|
||||
|
||||
@ -586,16 +582,7 @@ size_t Pak_ZStreamDecoderInit(PakDecoder_t* const decoder, const uint8_t* const
|
||||
|
||||
decoder->zstreamContext = dctx;
|
||||
|
||||
// this points to the first byte of the frame header, takes dataOffset
|
||||
// into account which is the offset in the ring buffer to the patched
|
||||
// data as we parse it contiguously after the base pak data, which
|
||||
// might have ended somewhere in the middle of the ring buffer
|
||||
const uint8_t* const frameHeaderData = (inputMask & (dataOffset + headerSize)) + fileBuffer;
|
||||
|
||||
// this is the offset to the ZStd header in the input buffer
|
||||
decoder->headerOffset = static_cast<uint32_t>(frameHeaderData - fileBuffer);
|
||||
|
||||
if (ZSTD_getFrameHeader(&dctx->fParams, frameHeaderData, dataSize) != 0)
|
||||
if (ZSTD_getFrameHeader(&dctx->fParams, frameHeader, dataSize) != 0)
|
||||
{
|
||||
ZSTD_freeDStream(decoder->zstreamContext);
|
||||
decoder->zstreamContext = nullptr;
|
||||
@ -619,51 +606,46 @@ size_t Pak_ZStreamDecoderInit(PakDecoder_t* const decoder, const uint8_t* const
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// decodes the ZStd data stream up to available buffer or data, whichever ends
|
||||
// first (determined by Pak_DetermineRingBufferFrame())
|
||||
// first
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_ZStreamDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen)
|
||||
bool Pak_ZStdStreamDecode(PakDecoder_t* const decoder, const PakRingBufferFrame_t& outFrame, const PakRingBufferFrame_t& inFrame)
|
||||
{
|
||||
// must have a ZStd decoder at this point, and input seek pos may not exceed
|
||||
// inLen as we can't read past currently streamed data; this should've been
|
||||
// checked before calling this function
|
||||
assert(decoder->zstreamContext && decoder->inBufBytePos <= inLen);
|
||||
|
||||
const PakRingBufferFrame_t outFrame = Pak_DetermineRingBufferFrame(decoder->outputMask, decoder->outBufBytePos, outLen);
|
||||
|
||||
ZSTD_outBuffer outBuffer = {
|
||||
&decoder->outputBuf[outFrame.bufIndex],
|
||||
outFrame.frameLen,
|
||||
NULL
|
||||
outFrame.frameLen, NULL
|
||||
};
|
||||
|
||||
const PakRingBufferFrame_t inFrame = Pak_DetermineRingBufferFrame(decoder->inputMask, decoder->inBufBytePos, inLen);
|
||||
|
||||
ZSTD_inBuffer inBuffer = {
|
||||
&decoder->inputBuf[inFrame.bufIndex],
|
||||
inFrame.frameLen,
|
||||
NULL
|
||||
inFrame.frameLen, NULL
|
||||
};
|
||||
|
||||
const size_t ret = ZSTD_decompressStream(decoder->zstreamContext, &outBuffer, &inBuffer);
|
||||
|
||||
if (ZSTD_isError(ret))
|
||||
{
|
||||
DevWarning(eDLL_T::RTECH, "%s: decode error: %s\n", __FUNCTION__, ZSTD_getErrorName(ret));
|
||||
// NOTE: obtained here and not in the error formatter as we could check
|
||||
// the error string during the assertion
|
||||
const char* const decodeError = ZSTD_getErrorName(ret);
|
||||
assert(0);
|
||||
|
||||
Error(eDLL_T::RTECH, EXIT_FAILURE, "%s: decode error: %s\n", __FUNCTION__, decodeError);
|
||||
return false;
|
||||
}
|
||||
|
||||
// advance buffer io positions, required so the main parser could already
|
||||
// start parsing the headers while the rest is getting decoded still
|
||||
decoder->inBufBytePos += inBuffer.pos;
|
||||
decoder->outBufBytePos += outBuffer.pos;
|
||||
decoder->inBufBytePos += inBuffer.pos;
|
||||
|
||||
// on the next call, we need at least this amount of data streamed in order
|
||||
// to decode the rest of the pak file, as this is where reading has stopped
|
||||
// this value may equal the currently streamed input size, as its possible
|
||||
// this function is getting called to flush the remainder decoded data into
|
||||
// the out buffer which got truncated off on the call prior due to wrapping
|
||||
//
|
||||
// if the input stream has fully decoded, this should equal the size of the
|
||||
// encoded pak file
|
||||
decoder->bufferSizeNeeded = decoder->inBufBytePos;
|
||||
|
||||
const bool decoded = ret == NULL;
|
||||
@ -683,10 +665,10 @@ bool Pak_ZStreamDecode(PakDecoder_t* const decoder, const size_t inLen, const si
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t Pak_InitDecoder(PakDecoder_t* const decoder, const uint8_t* const inputBuf, uint8_t* const outputBuf,
|
||||
const uint64_t inputMask, const uint64_t outputMask, const size_t dataSize, const size_t dataOffset,
|
||||
const size_t headerSize, const bool useZStream)
|
||||
const size_t headerSize, const EPakDecodeMode decodeMode)
|
||||
{
|
||||
// buffer size must be power of two as we index into buffers using a bit
|
||||
// mask rather than modulo, the mask provided must be bufferSize-1
|
||||
// mask rather than a modulo, the mask provided must be bufferSize-1
|
||||
assert(IsPowerOfTwo(inputMask + 1));
|
||||
assert(IsPowerOfTwo(outputMask + 1));
|
||||
|
||||
@ -697,7 +679,7 @@ size_t Pak_InitDecoder(PakDecoder_t* const decoder, const uint8_t* const inputBu
|
||||
// the actual file size, which consists of dataOffset (anything up to the
|
||||
// frame header, like the file header) and the actual encoded data itself
|
||||
decoder->fileSize = dataOffset + dataSize;
|
||||
decoder->padding = NULL;
|
||||
decoder->decodeMode = decodeMode;
|
||||
|
||||
// buffer masks, which essentially gets used to index into the input and
|
||||
// output buffers, similar to 'idx % bufSize', where bufSize = bufMask+1
|
||||
@ -712,10 +694,26 @@ size_t Pak_InitDecoder(PakDecoder_t* const decoder, const uint8_t* const inputBu
|
||||
decoder->inBufBytePos = dataOffset + headerSize;
|
||||
decoder->outBufBytePos = headerSize;
|
||||
|
||||
if (useZStream)
|
||||
return Pak_ZStreamDecoderInit(decoder, inputBuf, inputMask, dataSize, dataOffset, headerSize);
|
||||
// if we use the default RTech decoder, return from here as the stuff below
|
||||
// is handled by the RTech decoder internally
|
||||
if (decodeMode == EPakDecodeMode::MODE_RTECH)
|
||||
return Pak_RTechDecoderInit(decoder, inputBuf, inputMask, dataSize, dataOffset, headerSize);
|
||||
|
||||
return Pak_RStreamDecoderInit(decoder, inputBuf, inputMask, dataSize, dataOffset, headerSize);
|
||||
// NOTE: on RTech encoded paks this data is parsed out of the frame header,
|
||||
// but for ZStd encoded paks we are always limiting this to the ring buffer
|
||||
// size
|
||||
decoder->outputInvMask = PAK_DECODE_OUT_RING_BUFFER_MASK;
|
||||
|
||||
// this points to the first byte of the frame header, takes dataOffset
|
||||
// into account which is the offset in the ring buffer to the patched
|
||||
// data as we parse it contiguously after the base pak data, which
|
||||
// might have ended somewhere in the middle of the ring buffer
|
||||
const uint8_t* const frameHeaderData = &inputBuf[inputMask & (dataOffset + headerSize)];
|
||||
|
||||
const size_t decodeSize = Pak_ZStdDecoderInit(decoder, frameHeaderData, dataSize, headerSize);
|
||||
assert(decodeSize);
|
||||
|
||||
return decodeSize;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -723,7 +721,7 @@ size_t Pak_InitDecoder(PakDecoder_t* const decoder, const uint8_t* const inputBu
|
||||
// from where the base pak had ended as patch pak files are considered part of
|
||||
// the pak file that's currently getting loaded
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_StreamToBufferDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen, const bool useZStream)
|
||||
bool Pak_StreamToBufferDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen, const EPakDecodeMode decodeMode)
|
||||
{
|
||||
if (!Pak_HasEnoughStreamedDataForDecode(decoder, inLen))
|
||||
return false;
|
||||
@ -731,22 +729,33 @@ bool Pak_StreamToBufferDecode(PakDecoder_t* const decoder, const size_t inLen, c
|
||||
if (!Pak_HasEnoughDecodeBufferAvailable(decoder, outLen))
|
||||
return false;
|
||||
|
||||
if (useZStream)
|
||||
return Pak_ZStreamDecode(decoder, inLen, outLen);
|
||||
if (decodeMode == EPakDecodeMode::MODE_RTECH)
|
||||
return Pak_RTechStreamDecode(decoder, inLen, outLen);
|
||||
|
||||
return Pak_RStreamDecode(decoder, inLen, outLen);
|
||||
// must have a decoder at this point
|
||||
//
|
||||
// also, input seek pos may not exceed inLen as we can't read past
|
||||
// currently streamed data; this should've been checked before reaching
|
||||
// this position in code
|
||||
assert(decoder->zstreamContext && decoder->inBufBytePos <= inLen);
|
||||
|
||||
const PakRingBufferFrame_t outFrame = Pak_DetermineRingBufferFrame(decoder->outputMask, decoder->outBufBytePos , outLen);
|
||||
const PakRingBufferFrame_t inFrame = Pak_DetermineRingBufferFrame(decoder->inputMask, decoder->inBufBytePos, inLen);
|
||||
|
||||
return Pak_ZStdStreamDecode(decoder, outFrame, inFrame);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// decodes buffered input pak data
|
||||
//-----------------------------------------------------------------------------
|
||||
bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const size_t pakSize)
|
||||
bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const size_t pakSize, const EPakDecodeMode decodeMode)
|
||||
{
|
||||
PakFileHeader_t* const inHeader = reinterpret_cast<PakFileHeader_t*>(inBuf);
|
||||
const bool usesZStream = inHeader->flags & PAK_HEADER_FLAGS_ZSTREAM;
|
||||
assert(decodeMode != EPakDecodeMode::MODE_DISABLED);
|
||||
|
||||
PakDecoder_t decoder{};
|
||||
const size_t decompressedSize = Pak_InitDecoder(&decoder, inBuf, outBuf, UINT64_MAX, UINT64_MAX, pakSize, NULL, sizeof(PakFileHeader_t), usesZStream);
|
||||
const size_t decompressedSize = Pak_InitDecoder(&decoder, inBuf, outBuf, UINT64_MAX, UINT64_MAX, pakSize, NULL, sizeof(PakFileHeader_t), decodeMode);
|
||||
|
||||
PakFileHeader_t* const inHeader = reinterpret_cast<PakFileHeader_t*>(inBuf);
|
||||
|
||||
if (decompressedSize != inHeader->decompressedSize)
|
||||
{
|
||||
@ -757,7 +766,7 @@ bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const
|
||||
}
|
||||
|
||||
// we should always have enough buffer room at this point
|
||||
if (!Pak_StreamToBufferDecode(&decoder, inHeader->compressedSize, inHeader->decompressedSize, usesZStream))
|
||||
if (!Pak_StreamToBufferDecode(&decoder, inHeader->compressedSize, inHeader->decompressedSize, decodeMode))
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: decompression failed!\n",
|
||||
__FUNCTION__);
|
||||
@ -772,7 +781,7 @@ bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const
|
||||
|
||||
// remove compress flags
|
||||
outHeader->flags &= ~PAK_HEADER_FLAGS_COMPRESSED;
|
||||
outHeader->flags &= ~PAK_HEADER_FLAGS_ZSTREAM;
|
||||
outHeader->flags &= ~PAK_HEADER_FLAGS_ZSTREAM_ENCODED;
|
||||
|
||||
// equal compressed size with decompressed
|
||||
outHeader->compressedSize = outHeader->decompressedSize;
|
||||
@ -841,7 +850,9 @@ bool Pak_DecodePakFile(const char* const inPakFile, const char* const outPakFile
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!inHeader->IsCompressed())
|
||||
const EPakDecodeMode decodeMode = inHeader->GetCompressionMode();
|
||||
|
||||
if (decodeMode == EPakDecodeMode::MODE_DISABLED)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: pak '%s' is already decompressed!\n",
|
||||
__FUNCTION__, inPakFile);
|
||||
@ -862,7 +873,7 @@ bool Pak_DecodePakFile(const char* const inPakFile, const char* const outPakFile
|
||||
std::unique_ptr<uint8_t[]> outPakBufContainer(new uint8_t[inHeader->decompressedSize]);
|
||||
uint8_t* const outPakBuf = outPakBufContainer.get();
|
||||
|
||||
if (!Pak_BufferToBufferDecode(inPakBuf, outPakBuf, fileSize))
|
||||
if (!Pak_BufferToBufferDecode(inPakBuf, outPakBuf, fileSize, decodeMode))
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: failed to decompress pak file '%s'!\n",
|
||||
__FUNCTION__, inPakFile);
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
extern size_t Pak_InitDecoder(PakDecoder_t* const decoder, const uint8_t* const inputBuf, uint8_t* const outputBuf,
|
||||
const uint64_t inputMask, const uint64_t outputMask, const size_t dataSize, const size_t dataOffset,
|
||||
const size_t headerSize, const bool useZStream);
|
||||
const size_t headerSize, const EPakDecodeMode decodeMode);
|
||||
|
||||
extern bool Pak_StreamToBufferDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen, const bool useCustom);
|
||||
extern bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const size_t pakSize);
|
||||
extern bool Pak_StreamToBufferDecode(PakDecoder_t* const decoder, const size_t inLen, const size_t outLen, const EPakDecodeMode decodeMode);
|
||||
extern bool Pak_BufferToBufferDecode(uint8_t* const inBuf, uint8_t* const outBuf, const size_t pakSize, const EPakDecodeMode decodeMode);
|
||||
|
||||
extern bool Pak_DecodePakFile(const char* const inPakFile, const char* const outPakFile);
|
||||
|
||||
|
@ -4,11 +4,26 @@
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "tier0/binstream.h"
|
||||
#include "thirdparty/zstd/zstd.h"
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "paktools.h"
|
||||
#include "pakencode.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// determines whether encoding had failed
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool Pak_HasEncodeFailed(const size_t result)
|
||||
{
|
||||
return static_cast<bool>(ZSTD_isError(result));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns the encode error as string
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char* Pak_GetEncodeError(const size_t result)
|
||||
{
|
||||
return ZSTD_getErrorName(result);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// encodes the pak file from buffer, we can't do streamed compression as we
|
||||
// need to know the actual decompress size ahead of time, else the runtime will
|
||||
@ -22,17 +37,20 @@ bool Pak_BufferToBufferEncode(const uint8_t* const inBuf, const uint64_t inLen,
|
||||
// compressed
|
||||
const size_t dataOffset = sizeof(PakFileHeader_t);
|
||||
|
||||
const size_t compressSize = ZSTD_compress(
|
||||
outBuf + dataOffset,
|
||||
outLen - dataOffset,
|
||||
inBuf + dataOffset,
|
||||
inLen - dataOffset,
|
||||
level);
|
||||
uint8_t* const dstBuf = outBuf + dataOffset;
|
||||
const size_t dstLen = outLen - dataOffset;
|
||||
|
||||
if (ZSTD_isError(compressSize))
|
||||
const uint8_t* const srcBuf = inBuf + dataOffset;
|
||||
const size_t srcLen = inLen - dataOffset;
|
||||
|
||||
size_t compressSize = NULL;
|
||||
|
||||
compressSize = ZSTD_compress(dstBuf, dstLen, srcBuf, srcLen, level);
|
||||
|
||||
if (Pak_HasEncodeFailed(compressSize))
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: compression failed! [%s]\n",
|
||||
__FUNCTION__, ZSTD_getErrorName(compressSize));
|
||||
__FUNCTION__, Pak_GetEncodeError(compressSize));
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -46,7 +64,7 @@ bool Pak_BufferToBufferEncode(const uint8_t* const inBuf, const uint64_t inLen,
|
||||
// these flags are required for the game's runtime to decide whether or not to
|
||||
// decompress the pak, and how; see Pak_ProcessPakFile() for more details
|
||||
outHeader->flags |= PAK_HEADER_FLAGS_COMPRESSED;
|
||||
outHeader->flags |= PAK_HEADER_FLAGS_ZSTREAM;
|
||||
outHeader->flags |= PAK_HEADER_FLAGS_ZSTREAM_ENCODED;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -111,7 +129,7 @@ bool Pak_EncodePakFile(const char* const inPakFile, const char* const outPakFile
|
||||
return false;
|
||||
}
|
||||
|
||||
if (inHeader->IsCompressed())
|
||||
if (inHeader->GetCompressionMode() != EPakDecodeMode::MODE_DISABLED)
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: pak '%s' is already compressed!\n",
|
||||
__FUNCTION__, inPakFile);
|
||||
@ -135,7 +153,9 @@ bool Pak_EncodePakFile(const char* const inPakFile, const char* const outPakFile
|
||||
__FUNCTION__, inPakFile);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> outPakBufContainer(new uint8_t[inHeader->decompressedSize]);
|
||||
const size_t outBufSize = inHeader->decompressedSize;
|
||||
|
||||
std::unique_ptr<uint8_t[]> outPakBufContainer(new uint8_t[outBufSize]);
|
||||
uint8_t* const outPakBuf = outPakBufContainer.get();
|
||||
|
||||
PakFileHeader_t* const outHeader = reinterpret_cast<PakFileHeader_t* const>(outPakBuf);
|
||||
@ -144,7 +164,7 @@ bool Pak_EncodePakFile(const char* const inPakFile, const char* const outPakFile
|
||||
*outHeader = *inHeader;
|
||||
|
||||
// encoding failed
|
||||
if (!Pak_BufferToBufferEncode(inPakBuf, inHeader->compressedSize, outPakBuf, inHeader->decompressedSize, level))
|
||||
if (!Pak_BufferToBufferEncode(inPakBuf, fileSize, outPakBuf, outBufSize, level))
|
||||
{
|
||||
Error(eDLL_T::RTECH, NO_ERROR, "%s: failed to compress pak file '%s'!\n",
|
||||
__FUNCTION__, inPakFile);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#ifndef RTECH_PAKENCODE_H
|
||||
#define RTECH_PAKENCODE_H
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
bool Pak_BufferToBufferEncode(const uint8_t* const inBuf, const uint64_t inLen,
|
||||
uint8_t* const outBuf, const uint64_t outLen, const int level);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,19 +20,14 @@ 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);
|
||||
|
||||
inline void (*v_Pak_RunAssetLoadingJobs)(PakFile_t* pak);
|
||||
inline void (*Pak_ProcessAssetRelationsAndResolveDependencies)(PakFile_t* pak_arg, PakAsset_t* asset_arg, unsigned int asset_idx_arg, unsigned int a4);
|
||||
|
||||
inline int (*Pak_TrackAsset)(PakFile_t* const a1, PakAsset_t* a2);
|
||||
|
||||
// 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.
|
||||
@ -66,8 +61,8 @@ typedef struct PakLoadFuncs_s
|
||||
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);
|
||||
uint8_t (*CheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg);
|
||||
uint8_t (*WaitAndCheckAsyncRequest)(int idx, size_t* const bytesProcessed, const char** const statusMsg);
|
||||
void* WaitForAsyncFileRead;
|
||||
void* Func31;
|
||||
void* Func32;
|
||||
@ -95,7 +90,6 @@ class V_PakParse : public IDetour
|
||||
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
|
||||
@ -111,22 +105,15 @@ class V_PakParse : public IDetour
|
||||
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("40 53 56 48 83 EC 58 44 8B 09").GetPtr(v_Pak_RunAssetLoadingJobs);
|
||||
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(Pak_TrackAsset);
|
||||
g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 48 83 EC 30 41 8B E9").GetPtr(Pak_ProcessAssetRelationsAndResolveDependencies);
|
||||
|
||||
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;
|
||||
|
@ -6,63 +6,34 @@
|
||||
|
||||
#include "rtech/ipakfile.h"
|
||||
|
||||
inline PakGlobals_t* g_pPakGlobals;
|
||||
inline PakLoadedInfo_t* g_pLoadedPakInfo;
|
||||
inline PakGlobals_s* g_pakGlobals;
|
||||
inline JobHelpCallback_t g_pPakFifoLockWrapper; // Pointer to functor that takes the global pak fifolock as argument.
|
||||
|
||||
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.
|
||||
// TODO: rename to 'g_bPakFifoLockAcquiredInMainThread'
|
||||
// if this is set, JT_ReleaseFifoLock has to be called
|
||||
// twice as the depth goes up to the thread that
|
||||
// acquired the lock + the main thread
|
||||
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_pakGlobals", g_pakGlobals);
|
||||
|
||||
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);
|
||||
g_pakGlobals = g_GameDll.FindPatternSIMD("48 8D 1D ?? ?? ?? ?? 45 8D 5A 0E").ResolveRelativeAddressSelf(0x3, 0x7).RCast<PakGlobals_s*>(); /*48 8D 1D ? ? ? ? 45 8D 5A 0E*/
|
||||
|
||||
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_pPakFifoLockWrapper = jtBase.Offset(0x1BC).FindPatternSelf("48 8D 0D").ResolveRelativeAddressSelf(0x3, 0x7).RCast<JobHelpCallback_t>();
|
||||
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 { };
|
||||
|
@ -6,8 +6,10 @@
|
||||
#include "tier0/commandline.h"
|
||||
#include "rtech/async/asyncio.h"
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstream.h"
|
||||
|
||||
#include "pakparse.h"
|
||||
#include "pakstate.h"
|
||||
#include "pakstream.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// determines whether or not to emulate the streaming install, this basically
|
||||
@ -16,23 +18,20 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
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;
|
||||
if (g_pakGlobals->emulateStreamingInstallInit)
|
||||
return g_pakGlobals->emulateStreamingInstall;
|
||||
|
||||
const char* value = nullptr;
|
||||
|
||||
if (CommandLine()->CheckParm("-emulate_streaming_install", &value))
|
||||
{
|
||||
if (value && atoi(value))
|
||||
shouldEmulate = true;
|
||||
g_pakGlobals->emulateStreamingInstall = true;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
return shouldEmulate;
|
||||
g_pakGlobals->emulateStreamingInstallInit = true;
|
||||
return g_pakGlobals->emulateStreamingInstall;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -95,7 +94,7 @@ void Pak_EnableEmbeddedStreamingData(PakLoadedInfo_t* const loadedInfo, PakLoade
|
||||
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)));
|
||||
char* const embeddedName = reinterpret_cast<char* const>(loadedInfo->allocator->Alloc(totalBufLen, 1));
|
||||
assert(embeddedName);
|
||||
|
||||
// copy the base path if none was found in the file name
|
||||
|
@ -1,6 +1,7 @@
|
||||
#ifndef RTECH_PAKSTREAM_H
|
||||
#define RTECH_PAKSTREAM_H
|
||||
#include "rtech/ipakfile.h"
|
||||
#include "pakstate.h"
|
||||
|
||||
extern void Pak_OpenAssociatedStreamingFiles(PakLoadedInfo_t* const loadedInfo, PakLoadedInfo_t::StreamingInfo_t& streamInfo,
|
||||
const uint16_t fileNamesBufSize, const EPakStreamSet set);
|
||||
@ -8,46 +9,31 @@ extern void Pak_OpenAssociatedStreamingFiles(PakLoadedInfo_t* const loadedInfo,
|
||||
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;
|
||||
// the current download progress of optional streaming assets
|
||||
inline float* g_pStreamingDownloadProgress = nullptr;
|
||||
|
||||
// inlines
|
||||
inline void(*v_Pak_IncrementStreamingAssetCount)(void);
|
||||
inline void(*v_Pak_DecrementStreamingAssetCount)(void);
|
||||
// NOTE: must use these when incrementing asset counts !!!
|
||||
inline void Pak_IncrementStreamingAssetCount() { ThreadInterlockedIncrement64(&g_pakGlobals->numStreamableAssets); }
|
||||
inline void Pak_DecrementStreamingAssetCount() { ThreadInterlockedDecrement64(&g_pakGlobals->numStreamableAssets); }
|
||||
|
||||
inline bool Pak_StreamingEnabled() { return *g_pUseAssetStreamingSystem != NULL; }
|
||||
inline int64_t Pak_GetNumStreamableAssets() { return *g_pNumStreamableAssets; }
|
||||
inline int64_t Pak_GetNumStreamableAssets() { return g_pakGlobals->numStreamableAssets; }
|
||||
|
||||
inline float Pak_GetStreamingDownloadProgress() { return *g_pStreamingDownloadProgress; }
|
||||
inline bool Pak_StreamingDownloadFinished() { return Pak_GetStreamingDownloadProgress() == 1.0f; }
|
||||
|
||||
inline bool Pak_StreamingEnabled() { return g_pakGlobals->useStreamingSystem != NULL; }
|
||||
|
||||
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 GetFun(void) const { }
|
||||
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 { };
|
||||
|
@ -101,6 +101,20 @@ const char* Pak_StatusToString(const EPakStatus status)
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns pak decoder as string
|
||||
//-----------------------------------------------------------------------------
|
||||
const char* Pak_DecoderToString(const EPakDecodeMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case EPakDecodeMode::MODE_RTECH: return "RTech";
|
||||
case EPakDecodeMode::MODE_ZSTD: return "ZStd";
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// compute a guid from input string data
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -146,22 +160,9 @@ PakGuid_t Pak_StringToGuid(const char* const string)
|
||||
//-----------------------------------------------------------------------------
|
||||
// gets information about loaded pak file via pak id
|
||||
//-----------------------------------------------------------------------------
|
||||
const PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId)
|
||||
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;
|
||||
return &g_pakGlobals->loadedPaks[pakId & PAK_MAX_HANDLES_MASK];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -169,9 +170,9 @@ const PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId)
|
||||
//-----------------------------------------------------------------------------
|
||||
const PakLoadedInfo_t* Pak_GetPakInfo(const char* const pakName)
|
||||
{
|
||||
for (int16_t i = 0; i < *g_pLoadedPakCount; ++i)
|
||||
for (int16_t i = 0; i < g_pakGlobals->loadedPakCount; ++i)
|
||||
{
|
||||
const PakLoadedInfo_t* const info = &g_pLoadedPakInfo[i];
|
||||
const PakLoadedInfo_t* const info = &g_pakGlobals->loadedPaks[i];
|
||||
if (!info)
|
||||
continue;
|
||||
|
||||
|
@ -13,9 +13,11 @@ extern bool Pak_FileOverrideExists(const char* const pakFilePath, char* const ou
|
||||
extern int Pak_FileExists(const char* const pakFilePath);
|
||||
|
||||
extern const char* Pak_StatusToString(const EPakStatus status);
|
||||
const char* Pak_DecoderToString(const EPakDecodeMode mode);
|
||||
|
||||
extern PakGuid_t Pak_StringToGuid(const char* const string);
|
||||
|
||||
extern const PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId);
|
||||
extern PakLoadedInfo_t* Pak_GetPakInfo(const PakHandle_t pakId);
|
||||
extern const PakLoadedInfo_t* Pak_GetPakInfo(const char* const pakName);
|
||||
|
||||
extern PakPatchDataHeader_t* Pak_GetPatchDataHeader(PakFileHeader_t* const pakHeader);
|
||||
|
Loading…
x
Reference in New Issue
Block a user