mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
* 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
153 lines
6.1 KiB
C++
153 lines
6.1 KiB
C++
//=============================================================================//
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
}
|