You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/CryEngine/CrySystem/ResourceManager.cpp

876 lines
29 KiB
C++

/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Interface to the Resource Manager
#include "CrySystem_precompiled.h"
#include "ResourceManager.h"
#include "System.h"
#include "MaterialUtils.h"
#include <CryPath.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/IO/FileOperations.h>
#include <AzFramework/Archive/Archive.h>
#include <AzFramework/Archive/INestedArchive.h>
#include <Pak/CryPakUtils.h>
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define RESOURCEMANAGER_CPP_SECTION_1 1
#define RESOURCEMANAGER_CPP_SECTION_2 2
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(ResourceManager_cpp)
#endif
#define LEVEL_PAK_FILENAME "level.pak"
#define LEVEL_PAK_INMEMORY_MAXSIZE 10 * 1024 * 1024
#define ENGINE_PAK_FILENAME "engine.pak"
#define LEVEL_CACHE_PAK_FILENAME "xml.pak"
#define GAME_DATA_PAK_FILENAME "gamedata.pak"
#define FAST_LOADING_PAKS_SRC_FOLDER "_fastload/"
#define FRONTEND_COMMON_PAK_FILENAME_SP "modes/menucommon_sp.pak"
#define FRONTEND_COMMON_PAK_FILENAME_MP "modes/menucommon_mp.pak"
#define FRONTEND_COMMON_LIST_FILENAME "menucommon"
#define LEVEL_CACHE_SRC_FOLDER "_levelcache/"
#define LEVEL_CACHE_BIND_ROOT "LevelCache"
#define LEVEL_RESOURCE_LIST "resourcelist.txt"
#define AUTO_LEVEL_RESOURCE_LIST "auto_resourcelist.txt"
#define AUTO_LEVEL_SEQUENCE_RESOURCE_LIST "auto_resources_sequence.txt"
#define AUTO_LEVEL_TOTAL_RESOURCE_LIST "auto_resourcelist_total.txt"
#define AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST "auto_resources_total_sequence.txt"
//////////////////////////////////////////////////////////////////////////
// IResourceList implementation class.
//////////////////////////////////////////////////////////////////////////
class CLevelResourceList
: public AZ::IO::IResourceList
{
public:
CLevelResourceList()
{
m_pFileBuffer = 0;
m_nBufferSize = 0;
m_nCurrentLine = 0;
};
~CLevelResourceList()
{
Clear();
};
uint32 GetFilenameHash(const char* sResourceFile)
{
char filename[512];
azstrcpy(filename, AZ_ARRAY_SIZE(filename), sResourceFile);
MaterialUtils::UnifyMaterialName(filename);
uint32 code = CCrc32::ComputeLowercase(filename);
return code;
}
virtual void Add([[maybe_unused]] AZStd::string_view sResourceFile)
{
assert(0); // Not implemented.
}
virtual void Clear()
{
delete [] m_pFileBuffer;
m_pFileBuffer = 0;
m_nBufferSize = 0;
stl::free_container(m_lines);
stl::free_container(m_resources_crc32);
m_nCurrentLine = 0;
}
struct ComparePredicate
{
bool operator()(const char* s1, const char* s2)
{
return strcmp(s1, s2) < 0;
}
};
virtual bool IsExist(AZStd::string_view sResourceFile)
{
uint32 nHash = GetFilenameHash(sResourceFile.data());
if (stl::binary_find(m_resources_crc32.begin(), m_resources_crc32.end(), nHash) != m_resources_crc32.end())
{
return true;
}
return false;
}
virtual bool Load(AZStd::string_view sResourceListFilename)
{
Clear();
CCryFile file;
if (file.Open(sResourceListFilename.data(), "rb", AZ::IO::IArchive::FOPEN_ONDISK)) // File access can happen from disk as well.
{
m_nBufferSize = file.GetLength();
if (m_nBufferSize > 0)
{
m_pFileBuffer = new char[m_nBufferSize];
size_t numBytesRead = file.ReadRaw(m_pFileBuffer, file.GetLength());
if (numBytesRead <= 0 || numBytesRead != file.GetLength())
{
AZ_Error("ResourceManager", false, "Unable to read data for: %.*s", aznumeric_cast<int>(sResourceListFilename.size()), sResourceListFilename.data());
return false;
}
m_pFileBuffer[m_nBufferSize - 1] = 0;
char seps[] = "\r\n";
m_lines.reserve(5000);
// Parse file, every line in a file represents a resource filename.
char* nextToken = nullptr;
char* token = azstrtok(m_pFileBuffer, 0, seps, &nextToken);
while (token != NULL)
{
m_lines.push_back(token);
token = azstrtok(NULL, 0, seps, &nextToken);
}
m_resources_crc32.resize(m_lines.size());
for (int i = 0, numlines = m_lines.size(); i < numlines; i++)
{
MaterialUtils::UnifyMaterialName(const_cast<char*>(m_lines[i]));
m_resources_crc32[i] = CCrc32::ComputeLowercase(m_lines[i]);
}
std::sort(m_resources_crc32.begin(), m_resources_crc32.end());
}
return true;
}
return false;
}
virtual const char* GetFirst()
{
m_nCurrentLine = 0;
if (!m_lines.empty())
{
return m_lines[0];
}
return NULL;
}
virtual const char* GetNext()
{
m_nCurrentLine++;
if (m_nCurrentLine < (int)m_lines.size())
{
return m_lines[m_nCurrentLine];
}
return NULL;
}
void GetMemoryStatistics(ICrySizer* pSizer)
{
pSizer->Add(this, sizeof(*this));
pSizer->Add(m_pFileBuffer, m_nBufferSize);
pSizer->AddContainer(m_lines);
pSizer->AddContainer(m_resources_crc32);
}
public:
char* m_pFileBuffer;
int m_nBufferSize;
typedef std::vector<const char*> Lines;
Lines m_lines;
int m_nCurrentLine;
std::vector<uint32> m_resources_crc32;
};
//////////////////////////////////////////////////////////////////////////
CResourceManager::CResourceManager()
{
m_bRegisteredFileOpenSink = false;
m_bOwnResourceList = false;
m_bLevelTransitioning = false;
m_fastLoadPakPaths.reserve(8);
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::PrepareLevel(const char* sLevelFolder, const char* sLevelName)
{
LOADING_TIME_PROFILE_SECTION;
m_sLevelFolder = sLevelFolder;
m_sLevelName = sLevelName;
m_bLevelTransitioning = false;
m_currentLevelCacheFolder = CryPathString(LEVEL_CACHE_SRC_FOLDER) + sLevelName;
if (g_cvars.archiveVars.nLoadCache)
{
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
// The prefab system doesn't use level.pak
if (!usePrefabSystemForLevels)
{
CryPathString levelpak = PathUtil::Make(sLevelFolder, LEVEL_PAK_FILENAME);
size_t nPakFileSize = gEnv->pCryPak->FGetSize(levelpak.c_str());
if (nPakFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs.
{
// Force level.pak from this level in memory.
gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
}
}
gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
//
// Load _levelCache paks in the order they are stored on the disk - reduce seek time
//
if (gEnv->pConsole->GetCVar("e_StreamCgf") && gEnv->pConsole->GetCVar("e_StreamCgf")->GetIVal() != 0)
{
LoadLevelCachePak("cga.pak", "", true);
LoadLevelCachePak("cgf.pak", "", true);
if (g_cvars.archiveVars.nStreamCache)
{
LoadLevelCachePak("cgf_cache.pak", "", false);
}
}
LoadLevelCachePak("chr.pak", "", true);
if (g_cvars.archiveVars.nStreamCache)
{
LoadLevelCachePak("chr_cache.pak", "", false);
}
LoadLevelCachePak("dds0.pak", "", true);
if (g_cvars.archiveVars.nStreamCache)
{
LoadLevelCachePak("dds_cache.pak", "", false);
}
LoadLevelCachePak("skin.pak", "", true);
if (g_cvars.archiveVars.nStreamCache)
{
LoadLevelCachePak("skin_cache.pak", "", false);
}
LoadLevelCachePak(LEVEL_CACHE_PAK_FILENAME, "", true);
}
AZStd::intrusive_ptr<CLevelResourceList> pResList = new CLevelResourceList;
gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, pResList.get());
m_bOwnResourceList = true;
// Load resourcelist.txt, TODO: make sure there are no duplicates
if (g_cvars.archiveVars.nSaveLevelResourceList == 0)
{
string filename = PathUtil::Make(sLevelFolder, AUTO_LEVEL_RESOURCE_LIST);
if (!pResList->Load(filename.c_str())) // If we saving resource list do not use auto_resourcelist.txt
{
// Try resource list created by the editor.
filename = PathUtil::Make(sLevelFolder, LEVEL_RESOURCE_LIST);
pResList->Load(filename.c_str());
}
}
//LoadFastLoadPaks();
if (g_cvars.archiveVars.nStreamCache)
{
m_AsyncPakManager.ParseLayerPaks(GetCurrentLevelCacheFolder());
}
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::LoadFastLoadPaks(bool bToMemory)
{
if (g_cvars.archiveVars.nSaveFastloadResourceList != 0)
{
// Record a file list for _FastLoad/startup.pak
m_recordedFiles.clear();
gEnv->pCryPak->RegisterFileAccessSink(this);
m_bRegisteredFileOpenSink = true;
return false;
}
else
{
LOADING_TIME_PROFILE_SECTION;
// Load a special _fastload paks
int nPakPreloadFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::INestedArchive::FLAGS_OVERRIDE_PAK;
if (bToMemory && g_cvars.archiveVars.nLoadCache)
{
nPakPreloadFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY;
}
const char* const assetsDir = "@assets@";
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION RESOURCEMANAGER_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(ResourceManager_cpp)
#endif
gEnv->pCryPak->OpenPacks(assetsDir, AZ::IO::PathString(FAST_LOADING_PAKS_SRC_FOLDER) + "*.pak", nPakPreloadFlags, &m_fastLoadPakPaths);
gEnv->pCryPak->OpenPack(assetsDir, "Engine.pak", AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY);
return !m_fastLoadPakPaths.empty();
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadFastLoadPaks()
{
for (uint32 i = 0; i < m_fastLoadPakPaths.size(); i++)
{
// Unload a special _fastload paks
gEnv->pCryPak->ClosePack(m_fastLoadPakPaths[i].c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL);
}
m_fastLoadPakPaths.clear();
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadLevel()
{
gEnv->pCryPak->SetResourceList(AZ::IO::IArchive::RFOM_Level, NULL);
if (m_bRegisteredFileOpenSink)
{
if (g_cvars.archiveVars.nSaveTotalResourceList)
{
SaveRecordedResources(true);
m_recordedFiles.clear();
}
}
stl::free_container(m_sLevelFolder);
stl::free_container(m_sLevelName);
stl::free_container(m_currentLevelCacheFolder);
// should always be empty, since it is freed at the end of
// the level loading process, if it is not
// something went wrong and we have a levelheap leak
assert(m_openedPaks.capacity() == 0);
m_pSequenceResourceList = NULL;
}
//////////////////////////////////////////////////////////////////////////
AZ::IO::IResourceList* CResourceManager::GetLevelResourceList()
{
auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level);
return pResList;
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::LoadLevelCachePak(const char* sPakName, const char* sBindRoot, bool bOnlyDuringLevelLoading)
{
LOADING_TIME_PROFILE_SECTION;
CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName;
pakPath.MakeLower();
pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
// Check if pak is already loaded
for (int i = 0; i < (int)m_openedPaks.size(); i++)
{
if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str()))
{
return true;
}
}
// check pak file size.
size_t nFileSize = gEnv->pCryPak->FGetSize(pakPath.c_str(), true);
if (nFileSize <= 0)
{
// Cached file does not exist
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Level cache pak file %s does not exist", pakPath.c_str());
return false;
}
//set these flags as DLC LevelCache Paks are found via the mod paths,
//and the paks can never be inside other paks so we optimise the search
uint32 nOpenPakFlags = AZ::IO::IArchive::FLAGS_FILENAMES_AS_CRC32 | AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK;
if (nFileSize < LEVEL_PAK_INMEMORY_MAXSIZE) // 10 megs.
{
if (!(nOpenPakFlags & AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY_CPU))
{
nOpenPakFlags |= AZ::IO::IArchive::FLAGS_PAK_IN_MEMORY;
}
}
SOpenedPak op;
if (gEnv->pCryPak->OpenPack(sBindRoot, { pakPath.c_str(), pakPath.size() }, nOpenPakFlags | AZ::IO::IArchive::FOPEN_HINT_QUIET, NULL, &op.filename))
{
op.bOnlyDuringLevelLoading = bOnlyDuringLevelLoading;
m_openedPaks.push_back(op);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::LoadModeSwitchPak(const char* sPakName, const bool multiplayer)
{
if (g_cvars.archiveVars.nSaveLevelResourceList)
{
//Don't load the pak if we're trying to save a resourcelist in order to build it.
m_recordedFiles.clear();
gEnv->pCryPak->RegisterFileAccessSink(this);
m_bRegisteredFileOpenSink = true;
return true;
}
else
{
if (g_cvars.archiveVars.nLoadModePaks)
{
// Unload SP common pak if switching to multiplayer
if (multiplayer)
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
}
else
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP, FRONTEND_COMMON_LIST_FILENAME "_mp");
}
//Load the mode switching pak. If this is available and up to date it speeds up this process considerably
bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0);
bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
return (bOpened && bLoaded);
}
else
{
return true;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadModeSwitchPak(const char* sPakName, const char* sResourceListName, const bool multiplayer)
{
if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink)
{
m_sLevelFolder = sResourceListName;
SaveRecordedResources();
gEnv->pCryPak->UnregisterFileAccessSink(this);
m_bRegisteredFileOpenSink = false;
}
else
{
if (g_cvars.archiveVars.nLoadModePaks)
{
//Unload the mode switching pak.
gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
gEnv->pCryPak->ClosePack(sPakName, 0);
//Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc, currently SP only
if (!multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP);
}
else if (multiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP) == false)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_MP);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::LoadMenuCommonPak(const char* sPakName)
{
if (g_cvars.archiveVars.nSaveMenuCommonResourceList)
{
//Don't load the pak if we're trying to save a resourcelist in order to build it.
m_recordedFiles.clear();
gEnv->pCryPak->RegisterFileAccessSink(this);
m_bRegisteredFileOpenSink = true;
return true;
}
else
{
//Load the mode switching pak. If this is available and up to date it speeds up this process considerably
bool bOpened = gEnv->pCryPak->OpenPack("@assets@", sPakName, 0);
bool bLoaded = gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_GPU);
return (bOpened && bLoaded);
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadMenuCommonPak(const char* sPakName, const char* sResourceListName)
{
if (g_cvars.archiveVars.nSaveMenuCommonResourceList)
{
m_sLevelFolder = sResourceListName;
SaveRecordedResources();
gEnv->pCryPak->UnregisterFileAccessSink(this);
m_bRegisteredFileOpenSink = false;
}
else
{
//Unload the mode switching pak.
gEnv->pCryPak->LoadPakToMemory(sPakName, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
gEnv->pCryPak->ClosePack(sPakName, 0);
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadLevelCachePak(const char* sPakName)
{
LOADING_TIME_PROFILE_SECTION;
CryPathString pakPath = GetCurrentLevelCacheFolder() + "/" + sPakName;
pakPath.MakeLower();
pakPath.replace(AZ_WRONG_FILESYSTEM_SEPARATOR, AZ_CORRECT_FILESYSTEM_SEPARATOR);
for (int i = 0; i < (int)m_openedPaks.size(); i++)
{
if (strstr(m_openedPaks[i].filename.c_str(), pakPath.c_str()))
{
gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), AZ::IO::IArchive::FLAGS_PATH_REAL);
m_openedPaks.erase(m_openedPaks.begin() + i);
break;
}
}
if (m_openedPaks.empty())
{
stl::free_container(m_openedPaks);
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::UnloadAllLevelCachePaks(bool bLevelLoadEnd)
{
LOADING_TIME_PROFILE_SECTION;
if (!bLevelLoadEnd)
{
m_AsyncPakManager.Clear();
UnloadFastLoadPaks();
}
else
{
m_AsyncPakManager.UnloadLevelLoadPaks();
}
uint32 nClosePakFlags = AZ::IO::IArchive::FLAGS_PATH_REAL; //AZ::IO::IArchive::FLAGS_CHECK_MOD_PATHS | AZ::IO::IArchive::FLAGS_NEVER_IN_PAK | AZ::IO::IArchive::FLAGS_PATH_REAL;
for (int i = 0; i < (int)m_openedPaks.size(); i++)
{
if ((m_openedPaks[i].bOnlyDuringLevelLoading && bLevelLoadEnd) ||
!bLevelLoadEnd)
{
gEnv->pCryPak->ClosePack(m_openedPaks[i].filename.c_str(), nClosePakFlags);
}
}
if (g_cvars.archiveVars.nLoadCache)
{
gEnv->pCryPak->LoadPakToMemory(ENGINE_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
bool usePrefabSystemForLevels = false;
AzFramework::ApplicationRequests::Bus::BroadcastResult(
usePrefabSystemForLevels, &AzFramework::ApplicationRequests::IsPrefabSystemForLevelsEnabled);
if (!usePrefabSystemForLevels)
{
// Force level.pak out of memory.
gEnv->pCryPak->LoadPakToMemory(LEVEL_PAK_FILENAME, AZ::IO::IArchive::eInMemoryPakLocale_Unload);
}
}
if (!bLevelLoadEnd)
{
stl::free_container(m_openedPaks);
}
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::LoadPakToMemAsync(const char* pPath, bool bLevelLoadOnly)
{
return m_AsyncPakManager.LoadPakToMemAsync(pPath, bLevelLoadOnly);
}
bool CResourceManager::LoadLayerPak(const char* sLayerName)
{
return m_AsyncPakManager.LoadLayerPak(sLayerName);
}
void CResourceManager::UnloadLayerPak(const char* sLayerName)
{
m_AsyncPakManager.UnloadLayerPak(sLayerName);
}
void CResourceManager::GetLayerPakStats(SLayerPakStats& stats, bool bCollectAllStats) const
{
m_AsyncPakManager.GetLayerPakStats(stats, bCollectAllStats);
}
void CResourceManager::UnloadAllAsyncPaks()
{
m_AsyncPakManager.Clear();
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::Update()
{
m_AsyncPakManager.Update();
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::Init()
{
GetISystem()->GetISystemEventDispatcher()->RegisterListener(this);
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::Shutdown()
{
UnloadAllLevelCachePaks(false);
if (GetISystem() && GetISystem()->GetISystemEventDispatcher())
{
GetISystem()->GetISystemEventDispatcher()->RemoveListener(this);
}
}
//////////////////////////////////////////////////////////////////////////
bool CResourceManager::IsStreamingCachePak(const char* filename) const
{
const char* cachePaks[] = {
"dds_cache.pak",
"cgf_cache.pak",
"skin_cache.pak",
"chr_cache.pak"
};
for (int i = 0; i < sizeof(cachePaks) / sizeof(cachePaks[0]); ++i)
{
if (strstr(filename, cachePaks[i]))
{
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_PTR wparam, [[maybe_unused]] UINT_PTR lparam)
{
switch (event)
{
case ESYSTEM_EVENT_FRONTEND_INITIALISED:
{
GetISystem()->GetStreamEngine()->PauseStreaming(false, -1);
}
break;
case ESYSTEM_EVENT_GAME_POST_INIT_DONE:
{
if (g_cvars.archiveVars.nSaveFastloadResourceList != 0)
{
SaveRecordedResources();
if (g_cvars.archiveVars.nSaveLevelResourceList == 0 && g_cvars.archiveVars.nSaveTotalResourceList == 0)
{
m_recordedFiles.clear();
}
}
// Unload all paks from memory, after game init.
UnloadAllLevelCachePaks(false);
gEnv->pCryPak->LoadPaksToMemory(0, false);
if (g_cvars.archiveVars.nLoadCache)
{
//Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc
if (!gEnv->bMultiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP);
}
}
break;
}
case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE:
{
if (!gEnv->bMultiplayer)
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
}
else
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP, FRONTEND_COMMON_LIST_FILENAME "_mp");
}
m_bLevelTransitioning = !m_sLevelName.empty();
m_lastLevelLoadTime.SetValue(0);
m_beginLevelLoadTime = gEnv->pTimer->GetAsyncTime();
if (g_cvars.archiveVars.nSaveLevelResourceList || g_cvars.archiveVars.nSaveTotalResourceList)
{
if (!g_cvars.archiveVars.nSaveTotalResourceList)
{
m_recordedFiles.clear();
}
if (!m_bRegisteredFileOpenSink)
{
gEnv->pCryPak->RegisterFileAccessSink(this);
m_bRegisteredFileOpenSink = true;
}
}
// Cancel any async pak loading, it will fight with the impending sync IO
m_AsyncPakManager.CancelPendingJobs();
// Pause streaming engine for anything but sound, music, video and flash.
uint32 nMask = (1 << eStreamTaskTypeFlash) | (1 << eStreamTaskTypeVideo) | STREAM_TASK_TYPE_AUDIO_ALL; // Unblock specified streams
nMask = ~nMask; // Invert mask, bit set means blocking type.
GetISystem()->GetStreamEngine()->PauseStreaming(true, nMask);
}
break;
case ESYSTEM_EVENT_LEVEL_LOAD_END:
{
if (m_bOwnResourceList)
{
m_bOwnResourceList = false;
// Clear resource list, after level loading.
auto pResList = gEnv->pCryPak->GetResourceList(AZ::IO::IArchive::RFOM_Level);
if (pResList)
{
pResList->Clear();
}
}
}
break;
case ESYSTEM_EVENT_LEVEL_UNLOAD:
UnloadAllLevelCachePaks(false);
break;
case ESYSTEM_EVENT_LEVEL_PRECACHE_START:
{
// Unpause all streams in streaming engine.
GetISystem()->GetStreamEngine()->PauseStreaming(false, -1);
}
break;
case ESYSTEM_EVENT_LEVEL_PRECACHE_FIRST_FRAME:
{
UnloadAllLevelCachePaks(true);
}
break;
case ESYSTEM_EVENT_LEVEL_PRECACHE_END:
{
CTimeValue t = gEnv->pTimer->GetAsyncTime();
m_lastLevelLoadTime = t - m_beginLevelLoadTime;
if (g_cvars.archiveVars.nSaveLevelResourceList && m_bRegisteredFileOpenSink)
{
SaveRecordedResources();
if (!g_cvars.archiveVars.nSaveTotalResourceList)
{
gEnv->pCryPak->UnregisterFileAccessSink(this);
m_bRegisteredFileOpenSink = false;
}
}
UnloadAllLevelCachePaks(true);
}
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::GetMemoryStatistics(ICrySizer* pSizer)
{
pSizer->AddContainer(m_openedPaks);
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::ReportFileOpen([[maybe_unused]] AZ::IO::HandleType inFileHandle, AZStd::string_view szFullPath)
{
if (!g_cvars.archiveVars.nSaveLevelResourceList && !g_cvars.archiveVars.nSaveFastloadResourceList && !g_cvars.archiveVars.nSaveMenuCommonResourceList && !g_cvars.archiveVars.nSaveTotalResourceList)
{
return;
}
string file = PathUtil::MakeGamePath(string(szFullPath.data(), szFullPath.size()));
file.replace('\\', '/');
file.MakeLower();
{
CryAutoCriticalSection lock(recordedFilesLock);
m_recordedFiles.push_back(file);
}
}
//////////////////////////////////////////////////////////////////////////
void CResourceManager::SaveRecordedResources(bool bTotalList)
{
CryAutoCriticalSection lock(recordedFilesLock);
std::set<string> fileset;
// eliminate duplicate values
std::vector<string>::iterator endLocation = std::unique(m_recordedFiles.begin(), m_recordedFiles.end());
m_recordedFiles.erase(endLocation, m_recordedFiles.end());
fileset.insert(m_recordedFiles.begin(), m_recordedFiles.end());
string sSequenceFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_SEQUENCE_RESOURCE_LIST : AUTO_LEVEL_SEQUENCE_RESOURCE_LIST);
{
AZ::IO::HandleType fileHandle = fxopen(sSequenceFilename, "wb", true);
if (fileHandle != AZ::IO::InvalidHandle)
{
for (std::vector<string>::iterator it = m_recordedFiles.begin(); it != m_recordedFiles.end(); ++it)
{
const char* str = it->c_str();
AZ::IO::Print(fileHandle, "%s\n", str);
}
gEnv->pFileIO->Close(fileHandle);
}
}
string sResourceSetFilename = PathUtil::AddSlash(m_sLevelFolder) + (bTotalList ? AUTO_LEVEL_TOTAL_RESOURCE_LIST : AUTO_LEVEL_RESOURCE_LIST);
{
AZ::IO::HandleType fileHandle = fxopen(sResourceSetFilename, "wb", true);
if (fileHandle != AZ::IO::InvalidHandle)
{
for (std::set<string>::iterator it = fileset.begin(); it != fileset.end(); ++it)
{
const char* str = it->c_str();
AZ::IO::Print(fileHandle, "%s\n", str);
}
gEnv->pFileIO->Close(fileHandle);
}
}
}
//////////////////////////////////////////////////////////////////////////
CTimeValue CResourceManager::GetLastLevelLoadTime() const
{
return m_lastLevelLoadTime;
}