1604 lines
44 KiB
C++
1604 lines
44 KiB
C++
![]() |
// 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());
|
||
|
}
|
||
|
}
|