Files
GTASource/game/system/FileMgr.cpp

1604 lines
44 KiB
C++
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
// Title : FileMgr.cpp
// Author : Adam Fowler
// Started : 22/02/05
#include "system/FileMgr.h"
// C headers
#if __WIN32PC
#include "direct.h"
#pragma warning(disable: 4668)
#include <shlobj.h>
#pragma warning(error: 4668)
#endif
// Rage headers
#include "bank/bank.h"
#include "bank/bkmgr.h"
#include "bank/bank.h"
#include "diag/channel.h"
#include "file/asset.h"
#include "file/file_channel.h"
#include "file/default_paths.h"
#include "file/device_crc.h"
#include "file/device_installer.h"
#include "file/device_relative.h"
#include "file/packfile.h"
#include "file/savegame.h"
#include "grcore/debugdraw.h"
#include "grcore/light.h"
#include "grcore/setup.h"
#include "grcore/stateblock.h"
#include "grmodel/setup.h"
#include "parser/manager.h"
#include "profile/timebars.h"
#include "streaming/CacheLoader.h"
#include "streaming/packfilemanager.h"
#include "streaming/streamingengine.h"
#include "streaming/streaminginstall_psn.h"
#include "streaming/streamingvisualize.h"
#include "string/string.h"
#include "system/bootmgr.h"
#include "system/memory.h"
#include "system/system.h"
#include "system/xtl.h"
#include "system/param.h"
#include "audiohardware/waveslot.h"
// Game headers
#ifndef NAVGEN_TOOL
#include "audio/frontendaudioentity.h"
#include "control/gamelogic.h"
#include "control/videorecording/videorecording.h"
#include "frontend/GameStreamMgr.h"
#include "frontend/loadingscreens.h"
#include "frontend/WarningScreen.h"
#include "modelinfo/ModelInfo.h"
#include "renderer/color.h"
#include "renderer/renderthread.h"
#include "scene/datafilemgr.h"
#include "scene/extracontent.h"
#include "scene/scene.h"
#include "system/controlmgr.h"
#include "system/StreamingInstall.winrt.h"
#include "system/system.h"
#include "text/Text.h"
#include "text/TextConversion.h"
#include "debug/Debug.h"
#else
#include <direct.h>
#include "GTATypes.h"
#endif
#define ASSETS_DIRECTORY "x:/gta5/assets_ng/"
#define ART_DIRECTORY RS_PROJROOT "/art/"
#if __BANK
#define TOOL_DIRECTORY RS_TOOLSROOT "/"
#endif
// Max number of RPFs the platform packfile can be split up into
#if RSG_ORBIS || RSG_DURANGO || (RSG_PC && RSG_CPU_X64)
#define MAX_PLATFORM_PACK_COUNT 26
#define MAX_PLATFORMCRC_PACK_COUNT 2 // only one needed right now, but we might add more later, eg, if split across chunks
#else
#define MAX_PLATFORM_PACK_COUNT 2
#endif // RSG_ORBIS || RSG_DURANGO
#define USE_NUMBERED_PLATPACKS 0 // use numbered platform packs instead of lettered, eg, xboxone02.rpf instead of xboxonec.rpf (if needing more than 26 packs)
// The PLATFORM_DIRECTORY needs to be consistent with the tests in ragebuilder/pack.cpp.
#if RSG_ORBIS
#define DISKROOT_DIRECTORY "/app0/"
#define HDD_GAME_DIRECTORY_BASE "/data/app/"
#if __FINAL
#define ROOT_DIRECTORY "/app0/"
#else
#define ROOT_DIRECTORY RS_BUILDBRANCH "/"
#endif // __FINAL
#define PLATFORM_PACK_COUNT 23
#define PLATFORMCRC_PACK_COUNT 1
#define PLATFORM_DIRECTORY "ps4/"
#define PLATFORM_PACK "ps4.rpf"
#define PLATFORM_DEBUG_PACK "ps4_debug.rpf" // contains all unshippable data for packaged non-final builds
#elif RSG_DURANGO
#define DISKROOT_DIRECTORY "G:/"
#define HDD_GAME_DIRECTORY_BASE "G:/"
#if __FINAL
#define ROOT_DIRECTORY "G:/"
#else
#define ROOT_DIRECTORY RS_BUILDBRANCH "/"
#endif // __FINAL
#define PLATFORM_PACK_COUNT 23
#define PLATFORMCRC_PACK_COUNT 1
#define PLATFORM_DIRECTORY "xboxone/"
#define PLATFORM_PACK "xboxone.rpf"
#define PLATFORM_DEBUG_PACK "xboxone_debug.rpf" // contains all unshippable data for packaged non-final builds
#else // pc, anything else
#define DISKROOT_DIRECTORY ""
#if __FINAL
#define ROOT_DIRECTORY ""
#else
#define ROOT_DIRECTORY RS_BUILDBRANCH "/"
#endif
#define PLATFORM_PACK_COUNT 23
#define PLATFORMCRC_PACK_COUNT 1
#if __64BIT
#define PLATFORM_DIRECTORY "x64/"
#define PLATFORM_PACK "x64.rpf"
#define PLATFORM_DEBUG_PACK "x64_debug.rpf" // contains all unshippable data for packaged non-final builds
#else
#define PLATFORM_DIRECTORY "pc/"
#define PLATFORM_PACK "pc.rpf"
#endif
#endif //__XENON
#if !__FINAL
#define COMMON_DEBUG_PACK "common_debug.rpf" // contains all unshippable data for packaged non-final builds
#endif // !__FINAL
#define COMMON_DIRECTORY "common/"
#if RSG_ORBIS
#define AUDIO_DIRECTORY "ps4/audio/"
#elif RSG_DURANGO
#define AUDIO_DIRECTORY "xboxone/audio/"
#elif RSG_PC
#define AUDIO_DIRECTORY "x64/audio/"
#else
#define AUDIO_DIRECTORY PLATFORM_DIRECTORY "audio/"
#endif
#if RSG_BANK
#define AUDIO_RPF "audio.rpf"
#define AUDIO_PACKLIST "packlist.txt"
#else
#define AUDIO_RPF "audio_rel.rpf"
#define AUDIO_PACKLIST "packlist_rel.txt"
#endif
char CFileMgr::ms_rootDirName[MAX_DIRNAME_CHARS] = ROOT_DIRECTORY;
char CFileMgr::ms_dirName[MAX_DIRNAME_CHARS];
char CFileMgr::ms_hddBootPath[MAX_DIRNAME_CHARS] = "";
#if __WIN32PC
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_appPath;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_userPath;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_rgscPath;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_appDataRootDirName;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_originalAppDataRootDirName;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_userDataRootDirName;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_originalUserDataRootDirName;
atFixedString<MAX_DIRNAME_CHARS> CFileMgr::ms_rockStarRootDirName;
static sysCriticalSectionToken s_FileMgrToken;
#endif // __WIN32PC
bool CFileMgr::ms_allChunksOnHdd = true;
#if !__FINAL
struct DummyAlloc
{
void * m_Buffer;
u32 m_Size;
u32 m_Allocator;
};
DummyAlloc s_dummyAllocs[] =
{
// orbis, durango, pc
// keep in sync VIRTUAL_STREAMING_MEMORY_LIMIT and PHYSICAL_STREAMING_MEMORY_LIMIT (GameScriptMgr.h)
{ NULL, 1 << 23, MEMTYPE_RESOURCE_VIRTUAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_VIRTUAL },
{ NULL, 1 << 22, MEMTYPE_RESOURCE_VIRTUAL }, //4
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL },
{ NULL, 1 << 23, MEMTYPE_RESOURCE_PHYSICAL }, //8
{ NULL, 1 << 22, MEMTYPE_RESOURCE_PHYSICAL }, //4
{ NULL, 1 << 21, MEMTYPE_RESOURCE_PHYSICAL }, //2
{ NULL, 1 << 20, MEMTYPE_RESOURCE_PHYSICAL } //1
};
#endif //!__FINAL
fiDeviceRelative gPlatformDevice;
fiDeviceRelative gCommonDevice;
fiDeviceRelative gGameCacheDevice;
fiDeviceRelative gAudioDevice;
fiDeviceCrc gCrcPlatformDevice;
fiDeviceCrc gCrcCommonDevice;
#if !__FINAL
fiDeviceRelative gAssetsDevice;
fiDeviceRelative gArtDevice;
fiDeviceRelative gDebugDevice; // mounted as debug: typically from the hosted build directory (eg, /<project>/build/<branch>)
// For packaged non-final builds, the devices below mount extra 'xxx_debug.rpf' packfiles that have -all- unshippable data in them
// To disable these (eg, for simulating a final configuration), use -nodebugpack as well as any applicable redirects (only final shaders, scripts, and text will be available)
// Note that these are mounted after the main devices, but before the update: device, so if there's any overlap, the search hierarchy is update: -> debug common:/platform: -> main common:/platform:
fiPackfile gDebugPlatformPackfileDevice; // only for packaged non-final builds (mounted as platform: from {platform}_debug.rpf)
fiPackfile gDebugCommonPackfileDevice; // only for packaged non-final builds (mounted as common: from common_debug.rpf)
#if __BANK
fiDeviceRelative gToolDevice;
#endif // __BANK
#if RSG_ORBIS || RSG_DURANGO
fiDeviceRelative gPlatformDeviceRfs;
fiDeviceRelative gCommonDeviceRfs;
fiDeviceCrc gCrcPlatformDeviceRfs;
fiDeviceCrc gCrcCommonDeviceRfs;
#endif // RSG_ORBIS || RSG_DURANGO
#endif // !__FINAL
#if __WIN32PC
fiDeviceRelative gUserDevice;
fiDeviceRelative gAppDataDevice;
#endif // __WIN32PC
fiPackfile gCommonPackfileDevice;
fiPackfile gPlatformPackfileDevice[MAX_PLATFORM_PACK_COUNT];
fiDeviceCrc gPlatformCrcPackfileDevice[MAX_PLATFORMCRC_PACK_COUNT];
fiPackfile gAudioPackfileDevice;
atArray<fiPackfile*> gAudioPacks;
int gPlatformPackfileCount = PLATFORM_PACK_COUNT;
int gPlatformCRCPackfileCount = PLATFORMCRC_PACK_COUNT;
#define PLAYGO_PACK_COUNT (2)
bool gCommonRpfInMemory = false;
bool gCommonRpfFromOdd = true;
namespace rage
{
NOSTRIP_XPARAM(audiofolder);
}
PARAM(marketing, "Marketing memory size");
PARAM(maponly, "Only load the map - turn off all cars & peds");
PARAM(maponlyextra, "Only load the map - turn off all cars & peds");
PARAM(stealextramemory, "Steal some extra memory");
PARAM(cheapmode, "Only load the map - turn off all cars & peds - no water reflections - reflection slods=300 - far clip=1500");
PARAM(common, "Indicate where common folder is");
PARAM(platform, "Indicate where platform folder is");
PARAM(nodebugpack, "Disable use of xxx_debug.rpf packfiles in packaged non-final builds");
NOSTRIP_PARAM(commonpack, "Indicate where common packfile is");
NOSTRIP_PARAM(platformpack, "Indicate where platform packfile is");
NOSTRIP_PARAM(audiopack, "Indicate where audio packfile is");
PARAM(audiopacklist, "Override audio packlist location");
PARAM(artdir, "Indicate where the art dir for the game is");
PARAM(assetsdir, "Indicate where the assets dir for the game is");
#if __BANK
PARAM(tooldir, "Indicate where the tools dir for the game is");
#endif
PARAM(rootdir, "Indicate where the root dir for the game is");
PARAM(usepackfiles, "Use RPF pack files");
PARAM(forceadpcm, "Use mp3 files for PS4");
#if defined(VIDEO_RECORDING_ENABLED) && VIDEO_RECORDING_ENABLED && (RSG_PC || RSG_DURANGO)
PARAM(videoOutputDir, "Indicate where to place recorded videos");
#endif
NOSTRIP_PARAM(userdir, "Indictate where the user folder is");
PARAM(cleaninstall, "Do not use hdd data even when it's newer.");
PARAM(playgoemu, "Emulation of PlayGo through private http server");
PARAM(playgotest, "Triggers the PlayGo script for debug and testing");
#if RSG_DURANGO || RSG_ORBIS
namespace rage
{
XPARAM(forceboothdd);
XPARAM(forceboothddloose);
};
#endif
static fiPackfile::CacheMode GetDefaultPackfileCacheMode()
{
return fiDeviceInstaller::GetIsBootedFromHdd() ? fiPackfile::CACHE_INSTALLER_FILE : fiPackfile::CACHE_NONE;
}
const char* GetRootFolder()
{
const char* pRootFolder = ROOT_DIRECTORY;
#if __CONSOLE
if (fiDeviceInstaller::GetIsBootedFromHdd())
{
return CFileMgr::GetHddBootPath();
}
if(sysBootManager::IsBootedFromDisc())
{
return DISKROOT_DIRECTORY;
}
#endif
if(PARAM_rootdir.Get(pRootFolder))
{
fileAssertf((pRootFolder[strlen(pRootFolder)-1] == '/'), "-rootdir parameter requires terminating //!");
}
#if RSG_DURANGO && __FINAL
return "G:/";
#else
#if RSG_DURANGO
if(PARAM_forceboothdd.Get() || PARAM_forceboothddloose.Get())
{
return "G:/";
}
else
#endif
{
#if !__FINAL
fileDisplayf("Root folder %s\n", pRootFolder);
#endif
return pRootFolder;
}
#endif
}
const char *GetAudioFolder()
{
if (fiDeviceInstaller::GetIsBootedFromHdd())
{
#if RSG_DURANGO || RSG_ORBIS
return HDD_GAME_DIRECTORY_BASE AUDIO_DIRECTORY;
#else
return GetRootFolder();
#endif
}
if(sysBootManager::IsBootedFromDisc())
{
#if RSG_DURANGO || RSG_ORBIS
return DISKROOT_DIRECTORY AUDIO_DIRECTORY;
#else
return GetRootFolder();
#endif
}
#if RSG_ORBIS
if(PARAM_forceadpcm.Get())
{
return "x64/audio/";
}
else
{
return "ps4/audio/";
}
#elif RSG_DURANGO
return "xboxone/audio/";
#elif RSG_PC
return "x64/audio/";
#else
return "platform:/audio/";
#endif
}
namespace rage {
NOSTRIP_XPARAM(nocachetimestamps);
};
#if !__FINAL
namespace rage {
XPARAM(noquits);
XPARAM(update);
};
#endif
const char* CFileMgr::GetAssetsFolder()
{
const char* pAssetsFolder = ASSETS_DIRECTORY;
if(PARAM_assetsdir.Get(pAssetsFolder))
{
fileAssertf((pAssetsFolder[strlen(pAssetsFolder)-1] == '/'), "-assetsdir parameter requires terminating //!");
}
#if !__FINAL
fileDisplayf("Assets folder %s\n", pAssetsFolder);
#endif
return pAssetsFolder;
}
const char* GetArtFolder()
{
const char* pArtFolder = ART_DIRECTORY;
if(PARAM_artdir.Get(pArtFolder))
{
fileAssertf((pArtFolder[strlen(pArtFolder)-1] == '/'), "-artdir parameter requires terminating //!");
}
#if !__FINAL
fileDisplayf("Art folder %s\n", pArtFolder);
#endif
return pArtFolder;
}
#if __BANK
const char* CFileMgr::GetToolFolder()
{
const char* pToolFolder = TOOL_DIRECTORY;
if(PARAM_tooldir.Get(pToolFolder))
{
fileAssertf((pToolFolder[strlen(pToolFolder)-1] == '/'), "-tooldir parameter requires terminating //!");
}
#if !__FINAL
fileDisplayf("Tool folder %s\n", pToolFolder);
#endif
return pToolFolder;
}
#endif
//
// name: ReadErrorHandler
// description: Read error handler
void ReadErrorHandler()
{
#if RSG_ORBIS
#if __FINAL
CWarningScreen::SetFatalReadMessageWithHeader(WARNING_MESSAGE_STANDARD, "", "READ_ERROR", FE_WARNING_NONE, false, -1);
#else
CWarningScreen::SetFatalReadMessageWithHeader(WARNING_MESSAGE_STANDARD, "", "READ_ERROR", FE_WARNING_OK, false, -1);
#endif
#endif
}
void CheckPack(bool success, const char *OUTPUT_ONLY(filename))
{
//@@: location CFILEMGR_CHECKPACK_ENTRY
if(!success)
{
if(sysBootManager::IsBootedFromDisc())
{
Errorf("Unable to find critical archive '%s', your disc image might be broken.",filename);
ReadErrorHandler();
PS3_ONLY(Quitf("Missing packfile" OUTPUT_ONLY("%s", filename)));
}
else
{
fileErrorf("Unable to find critical archive '%s', check that RFS connected properly.",filename);
__debugbreak();
ReadErrorHandler();
}
}
}
#if !__FINAL && !defined(NAVGEN_TOOL)
// allocate the dummy chunks of memory to prevent art mode using up all resource memory
void CFileMgr::AllocateDummyResourceMem()
{
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
MEM_USE_USERDATA(MEMUSERDATA_TEXLITE);
for(u32 i=0; i<NELEM(s_dummyAllocs); i++)
{
Assert(s_dummyAllocs[i].m_Buffer == NULL);
s_dummyAllocs[i].m_Buffer = strStreamingEngine::GetAllocator().Allocate(s_dummyAllocs[i].m_Size, 128, s_dummyAllocs[i].m_Allocator);
Assert(s_dummyAllocs[i].m_Buffer);
}
}
void CFileMgr::FreeDummyResourceMem()
{
MEM_USE_USERDATA(MEMUSERDATA_TEXLITE);
for(u32 i=0; i<NELEM(s_dummyAllocs); i++){
strStreamingEngine::GetAllocator().Free(s_dummyAllocs[i].m_Buffer);
s_dummyAllocs[i].m_Buffer = NULL;
}
}
atArray<void*> s_extraallocs;
// allocate the dummy chunks of memory to prevent art mode using up all resource memory
void CFileMgr::AllocateExtraResourceMem(size_t memory)
{
USE_MEMBUCKET(MEMBUCKET_SYSTEM);
MEM_USE_USERDATA(MEMUSERDATA_TEXLITE);
strStreamingAllocator& allocator = strStreamingEngine::GetAllocator();
size_t taken = 0;
size_t chunk = g_rscVirtualLeafSize << 8;
while (memory > g_rscVirtualLeafSize)
{
while (chunk > memory)
{
chunk >>= 1;
}
if (chunk < g_rscVirtualLeafSize)
break;
void* alloc = allocator.TryAllocate(chunk, 128, MEMTYPE_RESOURCE_VIRTUAL);
if (alloc)
{
s_extraallocs.Grow() = alloc;
memory -= chunk;
taken += chunk;
}
else
{
chunk >>= 1;
}
}
Warningf("Taken %" SIZETFMT "dKb of extra resource memory",taken >> 10);
}
void CFileMgr::FreeExtraResourceMem()
{
MEM_USE_USERDATA(MEMUSERDATA_TEXLITE);
strStreamingAllocator& allocator = strStreamingEngine::GetAllocator();
for (int i = 0; i < s_extraallocs.GetCount();++i)
{
allocator.Free(s_extraallocs[i]);
}
s_extraallocs.Reset();
}
#endif //!__FINAL
static void MakePlatformPackName(char *outBuffer, size_t outBufferSize, const char *rawName, int packIndex)
{
if (gPlatformPackfileCount == 1)
{
Assert(packIndex == 0);
safecpy(outBuffer, rawName, outBufferSize);
}
else
{
Assert(packIndex < gPlatformPackfileCount);
const char *extension = strrchr(rawName, '.');
size_t baseSize = Min(outBufferSize-2, (size_t) (extension - rawName));
memcpy(outBuffer, rawName, baseSize);
#if USE_NUMBERED_PLATPACKS
formatf(&outBuffer[baseSize],outBufferSize-baseSize,"%02d",packIndex);
safecat(outBuffer,extension,outBufferSize);
#else
outBuffer[baseSize] = 'a' + (char) packIndex;
safecpy(&outBuffer[baseSize+1], extension, outBufferSize - baseSize - 1);
#endif // USE_NUMBERED_PLATPACKS
}
}
// callback for when blocking on loading to avoid network timeouts
static const unsigned int KEEP_ALIVE_CALLBACK_INTERVAL = 50;
static void KeepAliveCallback()
{
//CLoadingScreens::KeepAliveUpdate();
#if __BANK
// Also keep the bank up to date here, to make sure we're flushing any queues (in particular the invoke queue)
BANKMGR.Update();
#endif
}
void CFileMgr::PreSetupDevices()
{
// when running debug hdd builds on ng, mount all data on PC too.
// this allows us to load rpfs from the pc if data there is newer than what's installed on console
#if !__FINAL && (RSG_ORBIS || RSG_DURANGO)
if ((!PARAM_forceboothdd.Get() && !PARAM_forceboothddloose.Get()) || PARAM_cleaninstall.Get())
return;
const char* pRootFolder = ROOT_DIRECTORY;
if (PARAM_rootdir.Get(pRootFolder))
fileAssertf((pRootFolder[strlen(pRootFolder)-1] == '/'), "-rootdir parameter requires terminating //!");
fiDevice::SetFindNewest(true);
char commonFolder[MAX_DIRNAME_CHARS];
char platformFolder[MAX_DIRNAME_CHARS];
strcpy(commonFolder, COMMON_DIRECTORY);
strcpy(platformFolder, PLATFORM_DIRECTORY);
char pCommonFolderPath[RAGE_MAX_PATH] = {0};
char pPlatformFolderPath[RAGE_MAX_PATH] = {0};
formatf(pCommonFolderPath, "%s%s", pRootFolder, commonFolder);
formatf(pPlatformFolderPath, "%s%s", pRootFolder, platformFolder);
const char* pCommonFolder = pCommonFolderPath;
const char* pPlatformFolder = pPlatformFolderPath;
PARAM_common.Get(pCommonFolder);
PARAM_platform.Get(pPlatformFolder);
// setup "common:/" device
gCommonDeviceRfs.Init(pCommonFolder, true);
gCommonDeviceRfs.MountAs("common:/");
// mount crc device
gCrcCommonDeviceRfs.Init("common:/", true, &gCommonDeviceRfs);
gCrcCommonDeviceRfs.MountAs("commoncrc:/");
// setup "platform:/" device
gPlatformDeviceRfs.Init(pPlatformFolder, true);
gPlatformDeviceRfs.MountAs("platform:/");
// mount platformcrc device
gCrcPlatformDeviceRfs.Init("platform:/", true, &gPlatformDeviceRfs);
gCrcPlatformDeviceRfs.MountAs("platformcrc:/");
#endif // !__FINAL && (RSG_ORBIS || RSG_DURANGO)
}
char g_AudioPack[RAGE_MAX_PATH];
//
// name: SetupDevices
// description:
void CFileMgr::SetupDevices()
{
PreSetupDevices();
char commonFolder[MAX_DIRNAME_CHARS];
char platformFolder[MAX_DIRNAME_CHARS];
char audioFolder[MAX_DIRNAME_CHARS];
strcpy(commonFolder, COMMON_DIRECTORY);
strcpy(platformFolder, PLATFORM_DIRECTORY);
if(PARAM_forceadpcm.Get())
{
strcpy(audioFolder, "x64/audio/");
}
else
{
strcpy(audioFolder, AUDIO_DIRECTORY);
}
fileDisplayf("Booting %s", sysParam::GetProgramName());
fiDeviceInstaller::SetKeepaliveCallback(datCallback(CFA(KeepAliveCallback)), KEEP_ALIVE_CALLBACK_INTERVAL);
#if __CONSOLE
#if RSG_ORBIS || RSG_DURANGO
if ((fiDeviceInstaller::GetIsBootedFromHdd() || PARAM_playgoemu.Get()) && !PARAM_forceboothddloose.Get())
{
if (PARAM_playgoemu.Get())
{
PARAM_commonpack.Set(DISKROOT_DIRECTORY "common.rpf");
PARAM_platformpack.Set(DISKROOT_DIRECTORY PLATFORM_PACK);
PARAM_audiopack.Set(DISKROOT_DIRECTORY AUDIO_DIRECTORY AUDIO_RPF);
}
else
{
PARAM_commonpack.Set(HDD_GAME_DIRECTORY_BASE "common.rpf");
PARAM_platformpack.Set(HDD_GAME_DIRECTORY_BASE PLATFORM_PACK);
PARAM_audiopack.Set(HDD_GAME_DIRECTORY_BASE AUDIO_DIRECTORY AUDIO_RPF);
}
strCacheLoader::SetReadOnly(true);
}
else
#endif
if(sysBootManager::IsBootedFromDisc())
{
const char* rootDir = GetRootFolder();
static char commonPath[RAGE_MAX_PATH];
static char platformPath[RAGE_MAX_PATH];
static char audioPath[RAGE_MAX_PATH];
if (gCommonRpfFromOdd)
{
formatf(commonPath, "%s%s", rootDir, "common.rpf");
}
PARAM_commonpack.Set(commonPath);
formatf(platformPath, "%s%s", rootDir, PLATFORM_PACK);
PARAM_platformpack.Set(platformPath);
formatf(audioPath, "%s" AUDIO_RPF, GetAudioFolder());
Displayf("Audio rpf = %s", audioPath);
PARAM_audiopack.Set(audioPath);
// #if !__FINAL
// PARAM_noquits.Set("1");
// #endif
strCacheLoader::SetReadOnly(true);
}
#if !__FINAL
else if(PARAM_usepackfiles.Get())
{
gPlatformPackfileCount = 1; // We never use split platform packfiles when running with -usepackfiles.
PARAM_commonpack.Set("common.rpf");
PARAM_platformpack.Set(PLATFORM_PACK);
strCacheLoader::SetReadOnly(true);
}
#endif
#else
// pc final builds assume packaged config - may switch this to __MASTER only
#if __FINAL
PARAM_commonpack.Set(DISKROOT_DIRECTORY "common.rpf");
PARAM_platformpack.Set(DISKROOT_DIRECTORY PLATFORM_PACK);
PARAM_audiopack.Set(DISKROOT_DIRECTORY AUDIO_DIRECTORY AUDIO_RPF);
#endif // !__FINAL
#endif
const char* pCommonFolder = commonFolder;
const char* pPlatformFolder = platformFolder;
const char* pCommonPack = NULL;
const char* pPlatformPack = NULL;
const char* pAudioFolder = audioFolder;
#if RSG_ORBIS
if(PARAM_forceadpcm.Get())
{
formatf(g_AudioPack, "%sx64/audio/" AUDIO_RPF, GetRootFolder());
}
else
{
formatf(g_AudioPack, "%sps4/audio/" AUDIO_RPF, GetRootFolder());
}
#elif RSG_DURANGO
formatf(g_AudioPack, "%sxboxone/audio/" AUDIO_RPF, GetRootFolder());
#elif RSG_PC
formatf(g_AudioPack, "%sx64/audio/" AUDIO_RPF, GetRootFolder());
#else
formatf(g_AudioPack, "%s" AUDIO_RPF, GetAudioFolder());
#endif
Displayf("Audio rpf = %s", g_AudioPack);
PARAM_common.Get(pCommonFolder);
PARAM_platform.Get(pPlatformFolder);
PARAM_audiofolder.Get(pAudioFolder);
// Indicate whether or not this is a packaged build.
#if !__FINAL
sysBootManager::SetIsPackagedBuild(PARAM_platformpack.Get() && PARAM_commonpack.Get());
if (PARAM_commonpack.Get())
{
// If we're grabbing common from a pack file, it's read only - that means we can't update the cache.
// As such, the cache is expected to be there and up-to-date.
PARAM_nocachetimestamps.Set("");
}
#else
// final can (and probably will) have packaged common data
if (PARAM_commonpack.Get())
PARAM_nocachetimestamps.Set("");
#endif // !__FINAL
// setup "common:/" device
if(PARAM_commonpack.Get(pCommonPack))
{
#if 0
CheckPack(gCommonPackfileDevice.Init(pCommonPack,true,fiPackfile::CACHE_MEMORY),pCommonPack);
gCommonRpfInMemory = true;
#else
CheckPack(gCommonPackfileDevice.Init(pCommonPack,true,GetDefaultPackfileCacheMode()),pCommonPack);
#endif
gCommonPackfileDevice.MountAs("common:/");
gCommonDevice.Init(pCommonFolder, true);
gCommonDevice.MountAs("common:/");
// mount crc device
gCrcCommonDevice.Init("common:/", true, &gCommonPackfileDevice);
gCrcCommonDevice.MountAs("commoncrc:/");
}
else
{
gCommonDevice.Init(pCommonFolder, true NOTFINAL_ONLY(&& sysBootManager::IsPackagedBuild())); // A packaged build might overlap common:/ with a read-only device, and we can't have mismatching readonly flags
gCommonDevice.MountAs("common:/");
// mount crc device
gCrcCommonDevice.Init("common:/", true, &gCommonDevice);
gCrcCommonDevice.MountAs("commoncrc:/");
}
// Let's also set up the cache folder. This can be different in some build types where common:/ is read-only.
// We WILL have to point it to the read-only RPF in some cases - like in disc builds.
// Since common:/ can be read-only, we have to use a separate mapping here.
bool packedCommon = pCommonPack!=NULL;
if (fiDeviceInstaller::GetIsBootedFromHdd() || PARAM_playgoemu.Get())
{
packedCommon = true;
#if RSG_ORBIS || RSG_DURANGO
if (PARAM_forceboothddloose.Get())
{
packedCommon = false;
}
#endif
}
// setup "platform:/" device
if(PARAM_platformpack.Get(pPlatformPack))
{
gPlatformDevice.Init(pPlatformFolder, true);
gPlatformDevice.MountAs("platform:/");
// mount platformcrc device
gCrcPlatformDevice.Init("platform:/", true, &gPlatformDevice);
gCrcPlatformDevice.MountAs("platformcrc:/");
if (CFileMgr::IsGameInstalled())
{
for (int x=0; x<gPlatformPackfileCount; x++)
{
char platformPackName[RAGE_MAX_PATH];
MakePlatformPackName(platformPackName, sizeof(platformPackName), pPlatformPack, x);
CheckPack(gPlatformPackfileDevice[x].Init(platformPackName,true,GetDefaultPackfileCacheMode()),platformPackName);
gPlatformPackfileDevice[x].MountAs("platform:/");
if(x<gPlatformCRCPackfileCount)
{
gPlatformCrcPackfileDevice[x].Init("platform:/", true, &gPlatformPackfileDevice[x]);
gPlatformCrcPackfileDevice[x].MountAs("platformcrc:/");
}
}
}
else
{
// the first two platform packs contain the initial payload for the prologue
for (int x=0; x<PLAYGO_PACK_COUNT; x++)
{
char platformPackName[RAGE_MAX_PATH];
MakePlatformPackName(platformPackName, sizeof(platformPackName), pPlatformPack, x);
CheckPack(gPlatformPackfileDevice[x].Init(platformPackName,true,GetDefaultPackfileCacheMode()),platformPackName);
gPlatformPackfileDevice[x].MountAs("platform:/");
if(x<gPlatformCRCPackfileCount)
{
gPlatformCrcPackfileDevice[x].Init("platform:/", true, &gPlatformPackfileDevice[x]);
gPlatformCrcPackfileDevice[x].MountAs("platformcrc:/");
}
}
}
}
else
{
gPlatformDevice.Init(pPlatformFolder, false);
gPlatformDevice.MountAs("platform:/");
// mount platformcrc device
gCrcPlatformDevice.Init("platform:/", true, &gPlatformDevice);
gCrcPlatformDevice.MountAs("platformcrc:/");
}
#if !__FINAL
if(!PARAM_nodebugpack.Get() && (PARAM_commonpack.Get() || PARAM_platformpack.Get()))
{
if(PARAM_commonpack.Get())
{
CheckPack(gDebugCommonPackfileDevice.Init(COMMON_DEBUG_PACK,true,GetDefaultPackfileCacheMode()),COMMON_DEBUG_PACK);
gDebugCommonPackfileDevice.MountAs("common:/");
}
if(PARAM_platformpack.Get())
{
CheckPack(gDebugPlatformPackfileDevice.Init(PLATFORM_DEBUG_PACK,true,GetDefaultPackfileCacheMode()),PLATFORM_DEBUG_PACK);
gDebugPlatformPackfileDevice.MountAs("platform:/");
}
}
#endif // !__FINAL
#if RSG_PC
const char *pParamValue;
char userDirPath[RAGE_MAX_PATH] = {0};
// Get the user directory from command line (passed via Social Club), default to regular UserDataRootDirectory
if(PARAM_userdir.GetParameter(pParamValue))
{
// Safety check the Path, default to regular UserDataRootDirectory
safecpy(userDirPath, pParamValue);
if (ASSET.CreateLeadingPath(userDirPath))
{
gUserDevice.Init(userDirPath, false);
}
else
{
ASSET.CreateLeadingPath(GetUserDataRootDirectory());
gUserDevice.Init(GetUserDataRootDirectory(), false);
}
}
else
{
ASSET.CreateLeadingPath(GetUserDataRootDirectory());
gUserDevice.Init(GetUserDataRootDirectory(), false);
}
gUserDevice.MountAs("user:/");
// Create app data folder
ASSET.CreateLeadingPath(GetAppDataRootDirectory());
gAppDataDevice.Init(GetAppDataRootDirectory(), false);
gAppDataDevice.MountAs("appdata:/");
#endif // RSG_PC
#if (RSG_PC || RSG_DURANGO)
#if defined(VIDEO_RECORDING_ENABLED) && VIDEO_RECORDING_ENABLED
// Set the output directory for videos on PC
char const * videoDirectory = NULL;
PARAM_videoOutputDir.Get( videoDirectory );
VideoRecording::InitializeExtraRecordingData( videoDirectory );
#endif
#endif // (RSG_PC || RSG_DURANGO)
// setup "audio:/" device
if(!PARAM_audiofolder.Get())
{
// Default to loading assets from audio.rpf - only use loose assets if -audiofolder=x is specified on cmd line
MountAudioPacks(g_AudioPack);
}
else
{
PARAM_audiofolder.Get(pAudioFolder);
Warningf("Using loose audio assets from %s", pAudioFolder);
gAudioDevice.Init(pAudioFolder, true);
gAudioDevice.MountAs("audio:/");
}
#if !__FINAL
gAssetsDevice.Init(GetAssetsFolder(), false);
gAssetsDevice.MountAs("assets:/");
gArtDevice.Init(GetArtFolder(), false);
gArtDevice.MountAs("art:/");
gDebugDevice.Init("x:\\gta5\\build\\dev_ng", false);
gDebugDevice.MountAs("debug:/");
#if __BANK
gToolDevice.Init(GetToolFolder(), false);
gToolDevice.MountAs("tool:/");
#endif // __BANK
#endif // !FINAL
CExtraContentManager::MountUpdate();
if (__FINAL || sysBootManager::IsBootedFromDisc() || packedCommon)
{
Displayf("Game cache is using read-only device - if you didn't prebuild your cache, you'll have a problem.");
extern fiDeviceRelative gTitleUpdateCommon2;
gGameCacheDevice.Init("common:/", true, &gTitleUpdateCommon2 );
}
else
{
#if !__FINAL && RSG_PC // definitely helps with pc, but may want to enable for other platforms, too
const char* pUpdateFolder;
if (PARAM_update.Get(pUpdateFolder))
{
gGameCacheDevice.Init("update:/common/", false);
}
else
#endif
{
extern fiDeviceRelative gTitleUpdateCommon2;
gGameCacheDevice.Init("common:/", false, &gTitleUpdateCommon2);
}
}
gGameCacheDevice.MountAs("gamecache:/");
}
bool CFileMgr::ShouldForceReleaseAudioPacklist()
{
return false;
}
bool CFileMgr::IsDownloadableVersion()
{
return false;
}
bool CFileMgr::IsAudioPackInInitialPackage(const char *packName)
{
const u32 initialPackList[] = { 0x41B63FE9, 0x231498DE };
const u32 hashToSearch = atStringHash(packName);
for(u32 i = 0; i < NELEM(initialPackList); i++)
{
if(hashToSearch == initialPackList[i])
{
return true;
}
}
return false;
}
bool CFileMgr::ShouldAudioPackBeSkipped(const char *CONSOLE_ONLY(packName))
{
#if !RSG_PC
const u32 skipList[] = { 0x3B9F8E17 }; // DLC_GTAO
const u32 hashToSearch = atStringHash(packName);
for(u32 i = 0; i < NELEM(skipList); i++)
{
if(hashToSearch == skipList[i])
{
return true;
}
}
#endif
return false;
}
void CFileMgr::MountAudioPacks(const char *packName)
{
bool secondaryInit = false;
if(!gAudioPackfileDevice.IsInitialized())
{
audWaveSlot::LoadStaticBankInfo();
PARAM_audiopack.Get(packName);
CheckPack(gAudioPackfileDevice.Init(packName,true,GetDefaultPackfileCacheMode()), packName);
gAudioPackfileDevice.MountAs("audio:/");
}
else
{
secondaryInit = true;
}
const char *packList = ShouldForceReleaseAudioPacklist() ? "audio:/config/packlist_rel.txt" : "audio:/config/" AUDIO_PACKLIST;
if (!sysBootManager::IsBootedFromDisc() || RSG_ORBIS || RSG_DURANGO)
{
PARAM_audiopacklist.Get(packList);
FileHandle handle = OpenFile(packList);
if(handle != INVALID_FILE_HANDLE)
{
bool eof = false;
while(!eof)
{
const char *line = ReadLine(handle, true);
if(!line || strlen(line) == 0)
{
eof = true;
continue;
}
if(ShouldAudioPackBeSkipped(line))
{
audDisplayf("Skipping pack: %s", line);
continue;
}
const bool isInitialPack = IsAudioPackInInitialPackage(line);
if(isInitialPack)
{
audDisplayf("Initial pack: %s", line);
}
if(isInitialPack && secondaryInit)
{
continue;
}
else if(!isInitialPack && !IsGameInstalled())
{
continue;
}
fiPackfile *pack = rage_new fiPackfile();
gAudioPacks.Grow() = pack;
char packPath[RAGE_MAX_PATH];
formatf(packPath, "%ssfx/%s.rpf", GetAudioFolder(), line);
Displayf("Mounting audio pack %s", packPath);
CheckPack(pack->Init(packPath,true,GetDefaultPackfileCacheMode()), packPath);
formatf(packPath, "audio:/sfx/%s/", line);
pack->MountAs(packPath);
}
CloseFile(handle);
}
else
{
audErrorf("Failed to open audio packlist: %s", packList);
}
}
else
{
// MEGA RPF SUPPORT
static const char* const audioPackfiles[] = {
"audio_cs",
"audio_misc",
"audio_music",
"audio_radio"
};
for(int i = 0; i < NELEM(audioPackfiles); i++)
{
char packPath[RAGE_MAX_PATH];
formatf(packPath, "%ssfx/%s.rpf", GetAudioFolder(), audioPackfiles[i]);
fiPackfile *pack = rage_new fiPackfile();
gAudioPacks.Grow() = pack;
CheckPack(pack->Init(packPath, true, GetDefaultPackfileCacheMode()), packPath);
pack->MountAs("audio:/sfx/");
}
if(!secondaryInit)
{
fiDeviceRelative *occlusionDevice = rage_new fiDeviceRelative();
occlusionDevice->Init("audio:/");
#if RSG_ORBIS
occlusionDevice->MountAs("ps4/audio/");
#elif RSG_DURANGO
occlusionDevice->MountAs("xboxone/audio/");
#elif RSG_PC
occlusionDevice->MountAs("x64/audio/");
#else
occlusionDevice->MountAs("platform:/audio/");
#endif
}
}
}
//
// name: CFileMgr::SetupDevicesAfterInit
// description: shutdown memory version of packfile
void CFileMgr::SetupDevicesAfterInit()
{
const char* pCommonPack = NULL;
if(PARAM_commonpack.Get(pCommonPack) && gCommonRpfInMemory)
{
fiDevice::Unmount("common:/");
// shutdown memory device and init file device
gCommonPackfileDevice.Shutdown();
gCommonPackfileDevice.Init(pCommonPack,true,GetDefaultPackfileCacheMode());
gCommonPackfileDevice.MountAs("common:/");
}
}
void CFileMgr::Initialise()
{
ms_allChunksOnHdd = StreamingInstall::Init();
#if !__FINAL
// pretend we need to run the streaming install code for debugging and such
if (PARAM_playgotest.Get())
{
ms_allChunksOnHdd = false;
}
#endif
#if RSG_DURANGO || (RSG_ORBIS && !__FINAL)
#if !__FINAL
if (PARAM_forceboothdd.Get() || PARAM_forceboothddloose.Get())
#endif
#if RSG_DURANGO || !__FINAL
{
SetGameHddBootPath(HDD_GAME_DIRECTORY_BASE);
}
#endif
#endif // RSG_DURANGO || RSG_ORBIS
#if RSG_ORBIS && !__FINAL
if (PARAM_playgoemu.Get())
{
SetGameHddBootPath(DISKROOT_DIRECTORY);
}
#endif
strcpy(ms_rootDirName, GetRootFolder());
#if RSG_DURANGO && !__FINAL
if (PARAM_forceboothdd.Get() || PARAM_forceboothddloose.Get())
{
// Add the build branch as a secondary directory so we can open files from there
strncat_s(ms_rootDirName, ";", _TRUNCATE);
strncat_s(ms_rootDirName, ROOT_DIRECTORY, _TRUNCATE);
}
#endif // RSG_DURANGO && !__FINAL
ASSET.SetPath(ms_rootDirName);
fiDevice::InitClass();
fiDevice::sm_FatalReadError = &ReadErrorHandler;
PF_START_STARTUPBAR("Init image list");
strPackfileManager::InitImageList();
#if __WIN32PC
// These need to be passed in once we know where they'll come from
ms_appPath = "\\Rockstar Games\\GTA V\\";
ms_userPath = "\\Rockstar Games\\GTA V\\";
ms_rgscPath = "\\Rockstar Games\\RGSC\\";
// get the current working dir on systems that support it.
//_getcwd(ms_rootDirName, MAX_DIRNAME_CHARS);
char dir[MAX_DIRNAME_CHARS];
char path[MAX_DIRNAME_CHARS];
//grab the directory and the path from the exe
if (!_splitpath_s(sysParam::sm_ProgName, dir, MAX_DIRNAME_CHARS, path, MAX_DIRNAME_CHARS, NULL, 0, NULL, 0))
{
safecat(dir, path, MAX_DIRNAME_CHARS);
safecpy(ms_rootDirName, dir, MAX_DIRNAME_CHARS);
//fix up any `/` in the path
size_t length = strlen(ms_rootDirName);
for (size_t i=0;i<length,i<MAX_DIRNAME_CHARS;i++)
if (ms_rootDirName[i] == '/')
ms_rootDirName[i] = '\\';
if(ms_rootDirName[length-1] != '\\')
safecat(ms_rootDirName, "\\", MAX_DIRNAME_CHARS);
}
else
{
_getcwd(ms_rootDirName, MAX_DIRNAME_CHARS);
}
fileDisplayf("Starting in %s", ms_rootDirName);
wchar_t AppDataRoot[MAX_DIRNAME_CHARS] = {0};
char TempPathBuffer[MAX_DIRNAME_CHARS] = {0};
int UnusedOut = 0;
if ( SUCCEEDED( SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, AppDataRoot) ) )
{ // CSIDL_LOCAL_APPDATA = <username>/Local Settings/Application Data/
ms_originalAppDataRootDirName = WideToUtf8(TempPathBuffer, reinterpret_cast<const char16*>(AppDataRoot), MAX_DIRNAME_CHARS, MAX_DIRNAME_CHARS, &UnusedOut);
ms_originalAppDataRootDirName += ms_appPath;
ms_appDataRootDirName = ms_originalAppDataRootDirName;
ms_rockStarRootDirName = TempPathBuffer;
ms_rockStarRootDirName += ms_rgscPath;
}
else
{ Assert(0); }
wchar_t UserDataRoot[MAX_DIRNAME_CHARS] = {0};
if ( SUCCEEDED( SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, UserDataRoot) ) )
{ // CSIDL_PERSONAL = My Documents
ms_originalUserDataRootDirName = WideToUtf8(TempPathBuffer, reinterpret_cast<const char16*>(UserDataRoot), MAX_DIRNAME_CHARS, MAX_DIRNAME_CHARS, &UnusedOut);;
ms_originalUserDataRootDirName += ms_userPath;
ms_userDataRootDirName = ms_originalUserDataRootDirName;
}
else
{ Assert(0); }
#endif
PF_START_STARTUPBAR("Setup devices");
//@@: location CFILEMGR_INITIALISE
SetupDevices();
fileAssertf(!strstr(ms_rootDirName,"VS_Project"),"Your working directory is highly likely to be wrong. Currently is %s", ms_rootDirName); // DW - fed up of the working directory being wrong and it crashing later in the code.
} // end - CFileMgr::Initialise
//
// name: NeedsPath
// description: Returns if a filename needs the root directory prepended to it
bool CFileMgr::NeedsPath(const char *base) {
if ( !base )
return true;
// If the name starts with either slash, or contains a colon anywhere, it does not need a path.
if (base[0] == '/' || base[0] == '\\' || strchr(base,':'))
return false;
else
return true;
}
#if RSG_DURANGO || RSG_ORBIS
void CFileMgr::SetGameHddBootPath(const char* hddBootPath)
{
strncpy(ms_hddBootPath, hddBootPath, MAX_DIRNAME_CHARS);
fiDeviceInstaller::SetIsBootedFromHdd(true, ms_hddBootPath);
}
#endif // RSG_DURANGO || RSG_ORBIS
void CFileMgr::SetDir(const char* pDirName)
{
#if __WIN32PC
sysCriticalSection oLock(s_FileMgrToken);
#endif
ms_dirName[0] ='\0';
if(NeedsPath(pDirName))
strcpy(ms_dirName, ms_rootDirName);
if(pDirName[0] != '\0')
{
strcat(ms_dirName, pDirName);
if(pDirName[strlen(pDirName)-1] != '\\')
strcat(ms_dirName, "\\");
}
ASSET.SetPath(ms_dirName);
} // end - CFileMgr::SetDir
#if __WIN32PC
void CFileMgr::SetAppDataDir(const char* pDirName, bool bUseOriginal)
{
sysCriticalSection oLock(s_FileMgrToken);
ms_dirName[0] = '\0';
atFixedString<MAX_DIRNAME_CHARS> dirToSet;
if(NeedsPath(pDirName))
{
if( bUseOriginal )
dirToSet = ms_originalAppDataRootDirName;
else
dirToSet = ms_appDataRootDirName;
}
SetPCDir(dirToSet, pDirName);
} // end - CFileMgr::SetAppDataDir
void CFileMgr::SetUserDataDir(const char* pDirName, bool bUseOriginal)
{
sysCriticalSection oLock(s_FileMgrToken);
ms_dirName[0] = '\0';
atFixedString<MAX_DIRNAME_CHARS> dirToSet;
if(NeedsPath(pDirName))
{
if( bUseOriginal )
dirToSet = ms_originalUserDataRootDirName;
else
dirToSet = ms_userDataRootDirName;
}
SetPCDir(dirToSet, pDirName);
} // end - CFileMgr::SetUserDataDir
void CFileMgr::SetRockStarDir(const char* pDirName)
{
sysCriticalSection oLock(s_FileMgrToken);
ms_dirName[0] = '\0';
atFixedString<MAX_DIRNAME_CHARS> dirToSet = ms_rockStarRootDirName;
SetPCDir(dirToSet, pDirName);
} // end - CFileMgr::SetRockStartDataDir
void CFileMgr::SetPCDir(atFixedString<MAX_DIRNAME_CHARS>& baseDir, const char* subDir)
{
if(subDir[0] != '\0')
{
baseDir += subDir;
if(!baseDir.EndsWith("\\") && !baseDir.EndsWith("/"))
baseDir += "/";
safecpy(ms_dirName, baseDir.c_str(), sizeof(ms_dirName));
USES_CONVERSION;
int result = SHCreateDirectoryExW(NULL, reinterpret_cast<const wchar_t*>(UTF8_TO_WIDE(ms_dirName)), NULL);
if(result != ERROR_SUCCESS && result != ERROR_ALREADY_EXISTS)
{ Assertf(0, "Can't create directory: %s \n", ms_dirName);}
}
ASSET.SetPath(ms_dirName);
}
#endif // __WIN32PC
// Name : LoadFile
// Purpose : Loads a file into the specified buffer
// Parameters : pFilename - file to load
// pBuffer - ptr to buffer to load file into
// bufferSize - maximum size of file to copy to buffer
// if 0, no action is taken
// Returns : File size or -1 if there is an error
s32 CFileMgr::LoadFile(const char* pFilename, u8* pBuffer, s32 DEV_ONLY(bufferSize), const char* UNUSED_PARAM(pReadString))
{
fiStream* pStream;
s32 size;
#if __DEV
fileDebugf1("LoadFile: %s Size:%d", pFilename, bufferSize);
#endif
// open file
pStream = ASSET.Open(pFilename, "");
if(pStream == NULL)
return -1;
size = pStream->Size();
pStream->Read(pBuffer, size);
// place end of file character at end of buffer
pBuffer[size] = '\0';
// close file
pStream->Close();
#if __DEV
fileDebugf1("Done LoadFile: %s Size:%d", pFilename, size);
#endif
return size;
} // end - CFileMgr::LoadFile
// Name : OpenFile
// Purpose : opens a file and returns a file id
// Parameters : pFilename - file to load
FileHandle CFileMgr::OpenFile(const char* pFilename, const char* pReadString)
{
fiStream* pStream;
bool bReadonly = true;
bool bCreate = false;
// check if 'w' is in readstring
if(pReadString)
{
while(*pReadString)
{
if(*pReadString == 'a')
bReadonly = false;
if(*pReadString == 'w')
bCreate = true;
pReadString++;
}
}
fileDebugf1("Opening %s", pFilename);
if(bCreate)
{
pStream = ASSET.Create(pFilename, "", false);
}
else
{
pStream = ASSET.Open(pFilename, "", false, bReadonly);
}
return (FileHandle)pStream;
}
// Name : OpenFileFroWriting
// Purpose : opens a file and returns a file id
// Parameters : pFilename - file to load
FileHandle CFileMgr::OpenFileForWriting(const char* pFilename)
{
return OpenFile(pFilename, "w");
}
FileHandle CFileMgr::OpenFileForAppending(const char* pFilename)
{
FileHandle NewFileHandle = OpenFile(pFilename, "a");
if(NewFileHandle!=INVALID_FILE_HANDLE)
{
fiStream* pStream = (fiStream*) NewFileHandle;
pStream->Seek(pStream->Size());
}
return NewFileHandle;
}
s32 CFileMgr::Read(FileHandle id, char* pData, s32 size)
{
fiStream* pStream = (fiStream*)id;
return pStream->Read(pData, size);
}
s32 CFileMgr::Write(FileHandle id, const char* pData, s32 size)
{
fiStream* pStream = (fiStream*)id;
return pStream->Write(pData, size);
}
s32 CFileMgr::Seek(FileHandle id, s32 offset)
{
fiStream* pStream = (fiStream*)id;
return pStream->Seek(offset);
}
s32 CFileMgr::Flush(FileHandle id)
{
fiStream* pStream = (fiStream*)id;
return pStream->Flush();
}
//
// name: ReadLine
// description: Read a single line from the file
bool CFileMgr::ReadLine(FileHandle id, char* pLine, s32 maxLen)
{
fiStream* pStream = (fiStream*)id;
s32 read = fgets(pLine,maxLen-1,pStream);
if (read == 0 && pStream->Tell() >= pStream->Size())
return false;
s32 i;
for(i=0; i<read; i++)
{
switch(pLine[i])
{
case '\r':
pLine[i] = '\0';
break;
case '\n':
pLine[i] = '\0';
case '\0' :
return true;
}
}
pLine[i] = '\0';
return true;
}
//
// name: ReadLine
// description: Read a single line from the file and possibly remove crap (tabs and commas)
// params: fileId & whether you want to removed crap (defaults to true)
char* CFileMgr::ReadLine(FileHandle id, bool bRemoveUnwantedChars)
{
#define READ_SIZE_FOR_A_LINE 1024 //increased from 512 because time cycle was failing
static char line[READ_SIZE_FOR_A_LINE];
char* pLineStart = &line[0];
if(ReadLine(id, &line[0], READ_SIZE_FOR_A_LINE))
{
if (bRemoveUnwantedChars)
{
char* pC = &line[0];
while(*pC != '\0')
{
if(((*pC < ' ' && *pC >= 0) || *pC == ','))
*pC = ' ';
pC++;
}
}
// get beginning of line first non-space/non-control character
while(*pLineStart == ' ' && *pLineStart != '\0')
pLineStart++;
return pLineStart;
}
return NULL;
}
//
// name: CloseFile
// description: Close a file handle
s32 CFileMgr::CloseFile(FileHandle id)
{
fiStream* pStream = (fiStream*)id;
return pStream->Close();
}
//
// name: GetTotalSize
// description: Get size of file
s32 CFileMgr::GetTotalSize(FileHandle id)
{
fiStream* pStream = (fiStream*)id;
return pStream->Size();
}
s32 CFileMgr::Tell(FileHandle id)
{
fiStream* pStream = (fiStream*)id;
return pStream->Tell();
}
bool CFileMgr::HasAsyncInstallFinished()
{
if (IsGameInstalled())
return true;
return StreamingInstall::HasInstallFinished();
}
void CFileMgr::CleanupAsyncInstall()
{
if (!HasAsyncInstallFinished())
return;
StreamingInstall::Shutdown();
if (!IsGameInstalled())
{
ms_allChunksOnHdd = true;
const char* pPlatformPack = NULL;
if (PARAM_platformpack.Get(pPlatformPack))
{
for (int x=PLAYGO_PACK_COUNT; x<gPlatformPackfileCount; x++)
{
char platformPackName[RAGE_MAX_PATH];
MakePlatformPackName(platformPackName, sizeof(platformPackName), pPlatformPack, x);
CheckPack(gPlatformPackfileDevice[x].Init(platformPackName,true,GetDefaultPackfileCacheMode()),platformPackName);
gPlatformPackfileDevice[x].MountAs("platform:/");
if(x<gPlatformCRCPackfileCount)
{
gPlatformCrcPackfileDevice[x].Init("platform:/", true, &gPlatformPackfileDevice[x]);
gPlatformCrcPackfileDevice[x].MountAs("platformcrc:/");
}
}
}
// Mount audio packs that were not included in the initial package
MountAudioPacks(g_AudioPack);
//CGameSessionStateMachine::SetForceInitLevel();
//CGame::StartNewGame(CGameLogic::GetRequestedLevelIndex());
}
}