mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-17 08:57:09 +00:00
Made a bunch of changes to make the resource store system more friendly to multiple stores instead of just a single active one, and set up a resource database for editor assets
This commit is contained in:
@@ -18,17 +18,13 @@
|
||||
#define EXPORT_COOKED 1
|
||||
|
||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||
: mStore(this)
|
||||
{
|
||||
mGameDir = FileUtil::MakeAbsolute(rkInputDir);
|
||||
mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
|
||||
|
||||
mpProject = new CGameProject(mExportDir);
|
||||
mDiscDir = mpProject->DiscDir(true);
|
||||
mContentDir = mpProject->ContentDir(false);
|
||||
mCookedDir = mpProject->CookedDir(false);
|
||||
mWorldsDirName = L"Worlds\\";
|
||||
mStore.SetActiveProject(mpProject);
|
||||
}
|
||||
|
||||
#if PUBLIC_RELEASE
|
||||
@@ -39,18 +35,27 @@ bool CGameExporter::Export()
|
||||
{
|
||||
SCOPED_TIMER(ExportGame);
|
||||
|
||||
CResourceStore *pOldStore = gpResourceStore;
|
||||
gpResourceStore = &mStore;
|
||||
FileUtil::CreateDirectory(mExportDir);
|
||||
FileUtil::ClearDirectory(mExportDir);
|
||||
|
||||
CopyDiscData();
|
||||
mpStore = new CResourceStore(this, L"Content\\", L"Cooked\\", mpProject->Game());
|
||||
mpStore->SetProject(mpProject);
|
||||
mContentDir = mpStore->RawDir(false);
|
||||
mCookedDir = mpStore->CookedDir(false);
|
||||
|
||||
CResourceStore *pOldStore = gpResourceStore;
|
||||
gpResourceStore = mpStore;
|
||||
|
||||
LoadAssetList();
|
||||
LoadPaks();
|
||||
ExportWorlds();
|
||||
ExportCookedResources();
|
||||
|
||||
gpResourceStore = pOldStore;
|
||||
delete mpStore;
|
||||
mpStore = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -464,7 +469,7 @@ void CGameExporter::ExportWorlds()
|
||||
if (rkRes.Type == "MLVL" && !rkRes.Name.EndsWith("NODEPEND"))
|
||||
{
|
||||
// Load world
|
||||
CWorld *pWorld = (CWorld*) mStore.LoadResource(rkRes.ID, rkRes.Type);
|
||||
CWorld *pWorld = (CWorld*) mpStore->LoadResource(rkRes.ID, rkRes.Type);
|
||||
|
||||
if (!pWorld)
|
||||
{
|
||||
@@ -510,7 +515,7 @@ void CGameExporter::ExportWorlds()
|
||||
}
|
||||
}
|
||||
|
||||
mStore.DestroyUnreferencedResources();
|
||||
mpStore->DestroyUnreferencedResources();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -530,7 +535,7 @@ void CGameExporter::ExportCookedResources()
|
||||
{
|
||||
SCOPED_TIMER(SaveResourceDatabase);
|
||||
#if EXPORT_COOKED
|
||||
mStore.SaveResourceDatabase();
|
||||
mpStore->SaveResourceDatabase();
|
||||
#endif
|
||||
mpProject->Save();
|
||||
}
|
||||
@@ -544,7 +549,7 @@ void CGameExporter::ExportCookedResources()
|
||||
// todo: we're wasting a ton of time loading the same resources over and over because most resources automatically
|
||||
// load all their dependencies and then we just clear it out from memory even though we'll need it again later. we
|
||||
// should really be doing this by dependency order instead of by ID order.
|
||||
for (CResourceIterator It(&mStore); It; ++It)
|
||||
for (CResourceIterator It(mpStore); It; ++It)
|
||||
{
|
||||
if (!It->IsTransient())
|
||||
{
|
||||
@@ -571,7 +576,7 @@ void CGameExporter::ExportCookedResources()
|
||||
{
|
||||
// All resources should have dependencies generated, so save the cache file
|
||||
SCOPED_TIMER(SaveResourceCacheData);
|
||||
mStore.SaveCacheFile();
|
||||
mpStore->SaveCacheFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,7 +601,7 @@ void CGameExporter::ExportResource(SResourceInstance& rRes)
|
||||
if (OutDir.IsEmpty()) OutDir = L"Uncategorized\\";
|
||||
|
||||
// Register resource and write to file
|
||||
CResourceEntry *pEntry = mStore.RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), OutDir, OutName);
|
||||
CResourceEntry *pEntry = mpStore->RegisterResource(rRes.ResourceID, CResource::ResTypeForExtension(rRes.ResourceType), OutDir, OutName);
|
||||
|
||||
#if EXPORT_COOKED
|
||||
// Save cooked asset
|
||||
|
||||
@@ -13,7 +13,7 @@ class CGameExporter
|
||||
{
|
||||
// Project
|
||||
CGameProject *mpProject;
|
||||
CResourceStore mStore;
|
||||
CResourceStore *mpStore;
|
||||
|
||||
// Directories
|
||||
TWideString mGameDir;
|
||||
|
||||
@@ -7,10 +7,7 @@ CGameProject *CGameProject::mspActiveProject = nullptr;
|
||||
CGameProject::~CGameProject()
|
||||
{
|
||||
if (IsActive())
|
||||
{
|
||||
mspActiveProject = nullptr;
|
||||
gpResourceStore->SetActiveProject(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool CGameProject::Load(const TWideString& rkPath)
|
||||
@@ -21,6 +18,8 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||
TString ProjPath = rkPath.ToUTF8();
|
||||
CXMLReader Reader(ProjPath);
|
||||
Serialize(Reader);
|
||||
|
||||
mpResourceStore->LoadResourceDatabase();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,7 +71,7 @@ void CGameProject::SetActive()
|
||||
if (mspActiveProject != this)
|
||||
{
|
||||
mspActiveProject = this;
|
||||
gpResourceStore->SetActiveProject(this);
|
||||
gpResourceStore = mpResourceStore;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ class CGameProject
|
||||
TWideString mProjectRoot;
|
||||
TWideString mResourceDBPath;
|
||||
std::vector<CPackage*> mPackages;
|
||||
CResourceStore *mpResourceStore;
|
||||
|
||||
enum EProjectVersion
|
||||
{
|
||||
@@ -31,7 +32,9 @@ public:
|
||||
CGameProject()
|
||||
: mGame(eUnknownGame)
|
||||
, mProjectName("Unnamed Project")
|
||||
{}
|
||||
{
|
||||
mpResourceStore = new CResourceStore(this);
|
||||
}
|
||||
|
||||
CGameProject(const TWideString& rkProjRootDir)
|
||||
: mGame(eUnknownGame)
|
||||
@@ -39,6 +42,7 @@ public:
|
||||
, mProjectRoot(rkProjRootDir)
|
||||
, mResourceDBPath(L"ResourceDB.rdb")
|
||||
{
|
||||
mpResourceStore = new CResourceStore(this);
|
||||
mProjectRoot.Replace(L"/", L"\\");
|
||||
}
|
||||
|
||||
@@ -55,8 +59,6 @@ public:
|
||||
inline TWideString ResourceDBPath(bool Relative) const { return Relative ? mResourceDBPath : mProjectRoot + mResourceDBPath; }
|
||||
inline TWideString DiscDir(bool Relative) const { return Relative ? L"Disc\\" : mProjectRoot + L"Disc\\"; }
|
||||
inline TWideString CacheDir(bool Relative) const { return Relative ? L"Cache\\" : mProjectRoot + L"Cache\\"; }
|
||||
inline TWideString ContentDir(bool Relative) const { return Relative ? L"Content\\" : mProjectRoot + L"Content\\"; }
|
||||
inline TWideString CookedDir(bool Relative) const { return Relative ? L"Cooked\\" : mProjectRoot + L"Cooked\\"; }
|
||||
inline TWideString PackagesDir(bool Relative) const { return Relative ? L"Packages\\" : mProjectRoot + L"Packages\\"; }
|
||||
inline TWideString ProjectPath() const { return mProjectRoot + FileUtil::SanitizeName(mProjectName.ToUTF16(), false) + L".prj"; }
|
||||
inline TWideString ResourceCachePath(bool Relative) const { return ResourceDBPath(Relative).GetFileDirectory() + L"ResourceCacheData.rcd"; }
|
||||
@@ -68,7 +70,7 @@ public:
|
||||
inline u32 NumPackages() const { return mPackages.size(); }
|
||||
inline CPackage* PackageByIndex(u32 Index) const { return mPackages[Index]; }
|
||||
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); }
|
||||
|
||||
inline CResourceStore* ResourceStore() const { return mpResourceStore; }
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline bool IsActive() const { return mspActiveProject == this; }
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
|
||||
|
||||
mpDirectory = mpStore->GetVirtualDirectory(rkDir, Transient, true);
|
||||
if (mpDirectory) mpDirectory->AddChild(L"", this);
|
||||
mGame = ((Transient || !mpStore->ActiveProject()) ? eUnknownGame : mpStore->ActiveProject()->Game());
|
||||
mGame = ((Transient || !mpStore) ? eUnknownGame : mpStore->Game());
|
||||
}
|
||||
|
||||
CResourceEntry::~CResourceEntry()
|
||||
@@ -80,11 +80,6 @@ void CResourceEntry::UpdateDependencies()
|
||||
mpStore->DestroyUnreferencedResources();
|
||||
}
|
||||
|
||||
TWideString CResourceEntry::CacheDataPath(bool Relative) const
|
||||
{
|
||||
return mpStore->ActiveProject()->CacheDir(Relative) + mID.ToString().ToUTF16() + L".rcd";
|
||||
}
|
||||
|
||||
bool CResourceEntry::HasRawVersion() const
|
||||
{
|
||||
return FileUtil::Exists(RawAssetPath());
|
||||
@@ -100,7 +95,12 @@ TString CResourceEntry::RawAssetPath(bool Relative) const
|
||||
TWideString Ext = GetResourceRawExtension(mType, mGame).ToUTF16();
|
||||
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
||||
TWideString Name = mName + L"." + Ext;
|
||||
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->ContentDir(false) + Path + Name);
|
||||
return ((IsTransient() || Relative) ? Path + Name : mpStore->RawDir(false) + Path + Name);
|
||||
}
|
||||
|
||||
TString CResourceEntry::RawExtension() const
|
||||
{
|
||||
return GetResourceRawExtension(mType, mGame);
|
||||
}
|
||||
|
||||
TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||
@@ -108,7 +108,7 @@ TString CResourceEntry::CookedAssetPath(bool Relative) const
|
||||
TWideString Ext = GetResourceCookedExtension(mType, mGame).ToUTF16();
|
||||
TWideString Path = mpDirectory ? mpDirectory->FullPath() : L"";
|
||||
TWideString Name = mName + L"." + Ext;
|
||||
return ((IsTransient() || Relative) ? Path + Name : mpStore->ActiveProject()->CookedDir(false) + Path + Name);
|
||||
return ((IsTransient() || Relative) ? Path + Name : mpStore->CookedDir(false) + Path + Name);
|
||||
}
|
||||
|
||||
CFourCC CResourceEntry::CookedExtension() const
|
||||
@@ -218,8 +218,14 @@ CResource* CResourceEntry::Load()
|
||||
|
||||
if (mpResource)
|
||||
{
|
||||
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions
|
||||
CResourceStore *pOldStore = gpResourceStore;
|
||||
gpResourceStore = mpStore;
|
||||
|
||||
CXMLReader Reader(RawAssetPath());
|
||||
mpResource->Serialize(Reader);
|
||||
|
||||
gpResourceStore = pOldStore;
|
||||
}
|
||||
|
||||
return mpResource;
|
||||
@@ -251,8 +257,14 @@ CResource* CResourceEntry::LoadCooked(IInputStream& rInput)
|
||||
if (mpResource) return mpResource;
|
||||
if (!rInput.IsValid()) return nullptr;
|
||||
|
||||
// Set gpResourceStore to ensure the correct resource store is accessed by loader functions
|
||||
CResourceStore *pOldStore = gpResourceStore;
|
||||
gpResourceStore = mpStore;
|
||||
|
||||
mpResource = CResourceFactory::LoadCookedResource(this, rInput);
|
||||
mpStore->TrackLoadedResource(this);
|
||||
|
||||
gpResourceStore = pOldStore;
|
||||
return mpResource;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,11 @@ public:
|
||||
|
||||
void SerializeCacheData(IArchive& rArc);
|
||||
void UpdateDependencies();
|
||||
TWideString CacheDataPath(bool Relative = false) const;
|
||||
|
||||
bool HasRawVersion() const;
|
||||
bool HasCookedVersion() const;
|
||||
TString RawAssetPath(bool Relative = false) const;
|
||||
TString RawExtension() const;
|
||||
TString CookedAssetPath(bool Relative = false) const;
|
||||
CFourCC CookedExtension() const;
|
||||
bool IsInDirectory(CVirtualDirectory *pDir) const;
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
|
||||
inline bool IsLoaded() const { return mpResource != nullptr; }
|
||||
inline CResource* Resource() const { return mpResource; }
|
||||
inline CResourceStore* ResourceStore() const { return mpStore; }
|
||||
inline CDependencyTree* Dependencies() const { return mpDependencies; }
|
||||
inline CAssetID ID() const { return mID; }
|
||||
inline EGame Game() const { return mGame; }
|
||||
|
||||
@@ -11,23 +11,40 @@
|
||||
#include <tinyxml2.h>
|
||||
|
||||
using namespace tinyxml2;
|
||||
CResourceStore *gpResourceStore = new CResourceStore;
|
||||
CResourceStore *gpResourceStore = nullptr;
|
||||
CResourceStore *gpEditorStore = nullptr;
|
||||
|
||||
CResourceStore::CResourceStore()
|
||||
CResourceStore::CResourceStore(const TWideString& rkDatabasePath)
|
||||
: mpProj(nullptr)
|
||||
, mpProjectRoot(nullptr)
|
||||
, mGame(eUnknownGame)
|
||||
, mpExporter(nullptr)
|
||||
{}
|
||||
{
|
||||
mpDatabaseRoot = new CVirtualDirectory();
|
||||
mDatabasePath = FileUtil::MakeAbsolute(rkDatabasePath.GetFileDirectory());
|
||||
mDatabaseName = rkDatabasePath.GetFileName();
|
||||
}
|
||||
|
||||
CResourceStore::CResourceStore(CGameExporter *pExporter)
|
||||
CResourceStore::CResourceStore(CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game)
|
||||
: mpProj(nullptr)
|
||||
, mpProjectRoot(nullptr)
|
||||
, mGame(Game)
|
||||
, mRawDir(rkRawDir)
|
||||
, mCookedDir(rkCookedDir)
|
||||
, mpExporter(pExporter)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
CResourceStore::CResourceStore(CGameProject *pProject)
|
||||
: mpProj(nullptr)
|
||||
, mGame(eUnknownGame)
|
||||
, mpDatabaseRoot(nullptr)
|
||||
, mpExporter(nullptr)
|
||||
{
|
||||
SetProject(pProject);
|
||||
}
|
||||
|
||||
CResourceStore::~CResourceStore()
|
||||
{
|
||||
CloseActiveProject();
|
||||
CloseProject();
|
||||
DestroyUnreferencedResources();
|
||||
|
||||
for (auto It = mResourceEntries.begin(); It != mResourceEntries.end(); It++)
|
||||
@@ -66,7 +83,9 @@ void CResourceStore::SerializeResourceDatabase(IArchive& rArc)
|
||||
}
|
||||
|
||||
// Serialize
|
||||
rArc << SERIAL_CONTAINER_AUTO(Resources, "Resource");
|
||||
rArc << SERIAL("RawDir", mRawDir)
|
||||
<< SERIAL("CookedDir", mCookedDir)
|
||||
<< SERIAL_CONTAINER_AUTO(Resources, "Resource");
|
||||
|
||||
// Register resources
|
||||
if (rArc.IsReader())
|
||||
@@ -81,27 +100,29 @@ void CResourceStore::SerializeResourceDatabase(IArchive& rArc)
|
||||
|
||||
void CResourceStore::LoadResourceDatabase()
|
||||
{
|
||||
ASSERT(mpProj);
|
||||
TString Path = mpProj->ResourceDBPath(false).ToUTF8();
|
||||
ASSERT(!mDatabasePath.IsEmpty());
|
||||
TString Path = DatabasePath().ToUTF8();
|
||||
|
||||
if (!mpDatabaseRoot)
|
||||
mpDatabaseRoot = new CVirtualDirectory();
|
||||
|
||||
CXMLReader Reader(Path);
|
||||
if (!mpProj) mGame = Reader.Game();
|
||||
SerializeResourceDatabase(Reader);
|
||||
LoadCacheFile();
|
||||
}
|
||||
|
||||
void CResourceStore::SaveResourceDatabase()
|
||||
{
|
||||
ASSERT(mpProj);
|
||||
TString Path = mpProj->ResourceDBPath(false).ToUTF8();
|
||||
|
||||
CXMLWriter Writer(Path, "ResourceDB", 0, mpProj ? mpProj->Game() : eUnknownGame);
|
||||
TString Path = DatabasePath().ToUTF8();
|
||||
CXMLWriter Writer(Path, "ResourceDB", 0, mGame);
|
||||
SerializeResourceDatabase(Writer);
|
||||
}
|
||||
|
||||
void CResourceStore::LoadCacheFile()
|
||||
{
|
||||
TString CacheDataPath = mpProj->ResourceCachePath(false).ToUTF8();
|
||||
CFileInStream CacheFile(CacheDataPath.ToStdString(), IOUtil::eBigEndian);
|
||||
TString CachePath = CacheDataPath().ToUTF8();
|
||||
CFileInStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian);
|
||||
ASSERT(CacheFile.IsValid());
|
||||
|
||||
// Cache header
|
||||
@@ -141,13 +162,13 @@ void CResourceStore::LoadCacheFile()
|
||||
|
||||
void CResourceStore::SaveCacheFile()
|
||||
{
|
||||
TString CacheDataPath = mpProj->ResourceCachePath(false).ToUTF8();
|
||||
CFileOutStream CacheFile(CacheDataPath.ToStdString(), IOUtil::eBigEndian);
|
||||
TString CachePath = CacheDataPath().ToUTF8();
|
||||
CFileOutStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian);
|
||||
ASSERT(CacheFile.IsValid());
|
||||
|
||||
// Cache header
|
||||
CFourCC("CACH").Write(CacheFile);
|
||||
CSerialVersion Version(0, 0, mpProj->Game());
|
||||
CSerialVersion Version(0, 0, mGame);
|
||||
Version.Write(CacheFile);
|
||||
|
||||
u32 ResCountOffset = CacheFile.Tell();
|
||||
@@ -184,23 +205,26 @@ void CResourceStore::SaveCacheFile()
|
||||
CacheFile.WriteLong(ResCount);
|
||||
}
|
||||
|
||||
void CResourceStore::SetActiveProject(CGameProject *pProj)
|
||||
void CResourceStore::SetProject(CGameProject *pProj)
|
||||
{
|
||||
if (mpProj == pProj) return;
|
||||
|
||||
CloseActiveProject();
|
||||
if (mpProj)
|
||||
CloseProject();
|
||||
|
||||
mpProj = pProj;
|
||||
|
||||
if (pProj)
|
||||
if (mpProj)
|
||||
{
|
||||
mpProjectRoot = new CVirtualDirectory();
|
||||
|
||||
if (!mpExporter)
|
||||
LoadResourceDatabase();
|
||||
TWideString DatabasePath = mpProj->ResourceDBPath(false);
|
||||
mDatabasePath = DatabasePath.GetFileDirectory();
|
||||
mDatabaseName = DatabasePath.GetFileName();
|
||||
mpDatabaseRoot = new CVirtualDirectory();
|
||||
mGame = mpProj->Game();
|
||||
}
|
||||
}
|
||||
|
||||
void CResourceStore::CloseActiveProject()
|
||||
void CResourceStore::CloseProject()
|
||||
{
|
||||
// Destroy unreferenced resources first. (This is necessary to avoid invalid memory accesses when
|
||||
// various TResPtrs are destroyed. There might be a cleaner solution than this.)
|
||||
@@ -233,14 +257,15 @@ void CResourceStore::CloseActiveProject()
|
||||
It++;
|
||||
}
|
||||
|
||||
delete mpProjectRoot;
|
||||
mpProjectRoot = nullptr;
|
||||
delete mpDatabaseRoot;
|
||||
mpDatabaseRoot = nullptr;
|
||||
mpProj = nullptr;
|
||||
mGame = eUnknownGame;
|
||||
}
|
||||
|
||||
CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TWideString& rkPath, bool Transient, bool AllowCreate)
|
||||
{
|
||||
if (rkPath.IsEmpty()) return nullptr;
|
||||
if (rkPath.IsEmpty()) return mpDatabaseRoot;
|
||||
|
||||
else if (Transient)
|
||||
{
|
||||
@@ -260,9 +285,9 @@ CVirtualDirectory* CResourceStore::GetVirtualDirectory(const TWideString& rkPath
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
else if (mpProjectRoot)
|
||||
else if (mpDatabaseRoot)
|
||||
{
|
||||
return mpProjectRoot->FindChildDirectory(rkPath, AllowCreate);
|
||||
return mpDatabaseRoot->FindChildDirectory(rkPath, AllowCreate);
|
||||
}
|
||||
|
||||
else return nullptr;
|
||||
@@ -276,6 +301,11 @@ CResourceEntry* CResourceStore::FindEntry(const CAssetID& rkID) const
|
||||
else return Found->second;
|
||||
}
|
||||
|
||||
CResourceEntry* CResourceStore::FindEntry(const TWideString& rkPath) const
|
||||
{
|
||||
return (mpDatabaseRoot ? mpDatabaseRoot->FindChildResource(rkPath) : nullptr);
|
||||
}
|
||||
|
||||
bool CResourceStore::IsResourceRegistered(const CAssetID& rkID) const
|
||||
{
|
||||
return FindEntry(rkID) == nullptr;
|
||||
@@ -382,10 +412,37 @@ CResource* CResourceStore::LoadResource(const CAssetID& rkID, const CFourCC& rkT
|
||||
}
|
||||
}
|
||||
|
||||
CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||
CResource* CResourceStore::LoadResource(const TWideString& rkPath)
|
||||
{
|
||||
// todo - support loading raw resources from arbitrary directory
|
||||
// Construct ID from string, check if resource is loaded already
|
||||
// If this is a relative path then load via the resource DB
|
||||
if (!FileUtil::IsAbsolute(rkPath))
|
||||
{
|
||||
CResourceEntry *pEntry = FindEntry(rkPath);
|
||||
|
||||
if (pEntry)
|
||||
{
|
||||
// Verify extension matches the entry + load resource
|
||||
TString Ext = rkPath.ToUTF8().GetFileExtension();
|
||||
|
||||
if (!Ext.IsEmpty())
|
||||
{
|
||||
if (Ext.Length() == 4)
|
||||
{
|
||||
ASSERT(Ext.CaseInsensitiveCompare(pEntry->CookedExtension().ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(Ext.CaseInsensitiveCompare(pEntry->RawExtension()));
|
||||
}
|
||||
}
|
||||
|
||||
return pEntry->Load();
|
||||
}
|
||||
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
// Otherwise create transient entry; construct ID from string, check if resource is loaded already
|
||||
TWideString Dir = FileUtil::MakeAbsolute(TWideString(rkPath.GetFileDirectory()));
|
||||
TString Name = rkPath.GetFileName(false);
|
||||
CAssetID ID = (Name.IsHexString() ? Name.ToInt64() : rkPath.Hash64());
|
||||
@@ -395,21 +452,22 @@ CResource* CResourceStore::LoadResource(const TString& rkPath)
|
||||
return Find->second->Resource();
|
||||
|
||||
// Determine type
|
||||
TString Extension = rkPath.GetFileExtension().ToUpper();
|
||||
TString PathUTF8 = rkPath.ToUTF8();
|
||||
TString Extension = TString(PathUTF8).GetFileExtension().ToUpper();
|
||||
EResType Type = CResource::ResTypeForExtension(Extension);
|
||||
|
||||
if (Type == eInvalidResType)
|
||||
{
|
||||
Log::Error("Unable to load resource " + rkPath + "; unrecognized extension: " + Extension);
|
||||
Log::Error("Unable to load resource " + PathUTF8 + "; unrecognized extension: " + Extension);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Open file
|
||||
CFileInStream File(rkPath.ToStdString(), IOUtil::eBigEndian);
|
||||
CFileInStream File(PathUTF8.ToStdString(), IOUtil::eBigEndian);
|
||||
|
||||
if (!File.IsValid())
|
||||
{
|
||||
Log::Error("Unable to load resource; couldn't open file: " + rkPath);
|
||||
Log::Error("Unable to load resource; couldn't open file: " + PathUTF8);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Core/Resource/EResType.h"
|
||||
#include <Common/CAssetID.h>
|
||||
#include <Common/CFourCC.h>
|
||||
#include <Common/FileUtil.h>
|
||||
#include <Common/TString.h>
|
||||
#include <Common/types.h>
|
||||
#include <map>
|
||||
@@ -19,12 +20,17 @@ class CResourceStore
|
||||
friend class CResourceIterator;
|
||||
|
||||
CGameProject *mpProj;
|
||||
CVirtualDirectory *mpProjectRoot;
|
||||
EGame mGame;
|
||||
CVirtualDirectory *mpDatabaseRoot;
|
||||
std::vector<CVirtualDirectory*> mTransientRoots;
|
||||
std::map<CAssetID, CResourceEntry*> mResourceEntries;
|
||||
std::map<CAssetID, CResourceEntry*> mLoadedResources;
|
||||
|
||||
// Directory to look for transient resources in
|
||||
// Directory paths
|
||||
TWideString mDatabasePath;
|
||||
TWideString mDatabaseName;
|
||||
TWideString mRawDir;
|
||||
TWideString mCookedDir;
|
||||
TWideString mTransientLoadDir;
|
||||
|
||||
// Game exporter currently in use - lets us load from paks being exported
|
||||
@@ -39,26 +45,28 @@ class CResourceStore
|
||||
};
|
||||
|
||||
public:
|
||||
CResourceStore();
|
||||
CResourceStore(CGameExporter *pExporter);
|
||||
CResourceStore(const TWideString& rkDatabasePath);
|
||||
CResourceStore(CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game);
|
||||
CResourceStore(CGameProject *pProject);
|
||||
~CResourceStore();
|
||||
void SerializeResourceDatabase(IArchive& rArc);
|
||||
void LoadResourceDatabase();
|
||||
void SaveResourceDatabase();
|
||||
void LoadCacheFile();
|
||||
void SaveCacheFile();
|
||||
void SetActiveProject(CGameProject *pProj);
|
||||
void CloseActiveProject();
|
||||
void SetProject(CGameProject *pProj);
|
||||
void CloseProject();
|
||||
CVirtualDirectory* GetVirtualDirectory(const TWideString& rkPath, bool Transient, bool AllowCreate);
|
||||
|
||||
bool IsResourceRegistered(const CAssetID& rkID) const;
|
||||
CResourceEntry* RegisterResource(const CAssetID& rkID, EResType Type, const TWideString& rkDir, const TWideString& rkFileName);
|
||||
CResourceEntry* FindEntry(const CAssetID& rkID) const;
|
||||
CResourceEntry* FindEntry(const TWideString& rkPath) const;
|
||||
CResourceEntry* RegisterTransientResource(EResType Type, const TWideString& rkDir = L"", const TWideString& rkFileName = L"");
|
||||
CResourceEntry* RegisterTransientResource(EResType Type, const CAssetID& rkID, const TWideString& rkDir = L"", const TWideString& rkFileName = L"");
|
||||
|
||||
CResource* LoadResource(const CAssetID& rkID, const CFourCC& rkType);
|
||||
CResource* LoadResource(const TString& rkPath);
|
||||
CResource* LoadResource(const TWideString& rkPath);
|
||||
void TrackLoadedResource(CResourceEntry *pEntry);
|
||||
CFourCC ResourceTypeByID(const CAssetID& rkID, const TStringList& rkPossibleTypes) const;
|
||||
void DestroyUnreferencedResources();
|
||||
@@ -66,12 +74,19 @@ public:
|
||||
void SetTransientLoadDir(const TString& rkDir);
|
||||
|
||||
// Accessors
|
||||
inline CGameProject* ActiveProject() const { return mpProj; }
|
||||
inline CVirtualDirectory* RootDirectory() const { return mpProjectRoot; }
|
||||
inline u32 NumTotalResources() const { return mResourceEntries.size(); }
|
||||
inline u32 NumLoadedResources() const { return mLoadedResources.size(); }
|
||||
inline CGameProject* Project() const { return mpProj; }
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline TWideString DatabaseRootPath() const { return mDatabasePath; }
|
||||
inline TWideString RawDir(bool Relative) const { return Relative ? mRawDir : mDatabasePath + mRawDir; }
|
||||
inline TWideString CookedDir(bool Relative) const { return Relative ? mCookedDir : mDatabasePath + mCookedDir; }
|
||||
inline TWideString DatabasePath() const { return DatabaseRootPath() + mDatabaseName; }
|
||||
inline TWideString CacheDataPath() const { return DatabaseRootPath() + L"ResourceCacheData.rcd"; }
|
||||
inline CVirtualDirectory* RootDirectory() const { return mpDatabaseRoot; }
|
||||
inline u32 NumTotalResources() const { return mResourceEntries.size(); }
|
||||
inline u32 NumLoadedResources() const { return mLoadedResources.size(); }
|
||||
};
|
||||
|
||||
extern CResourceStore *gpResourceStore;
|
||||
extern CResourceStore *gpEditorStore;
|
||||
|
||||
#endif // CRESOURCEDATABASE_H
|
||||
|
||||
@@ -78,12 +78,24 @@ CVirtualDirectory* CVirtualDirectory::FindChildDirectory(const TWideString& rkNa
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CResourceEntry* CVirtualDirectory::FindChildResource(const TWideString& rkName) const
|
||||
CResourceEntry* CVirtualDirectory::FindChildResource(const TWideString& rkPath)
|
||||
{
|
||||
for (u32 iRes = 0; iRes < mResources.size(); iRes++)
|
||||
TWideString Dir = rkPath.GetFileDirectory();
|
||||
TWideString Name = rkPath.GetFileName(false);
|
||||
|
||||
if (!Dir.IsEmpty())
|
||||
{
|
||||
if (mResources[iRes]->Name() == rkName)
|
||||
return mResources[iRes];
|
||||
CVirtualDirectory *pDir = FindChildDirectory(Dir, false);
|
||||
if (pDir) return pDir->FindChildResource(Name);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
for (u32 iRes = 0; iRes < mResources.size(); iRes++)
|
||||
{
|
||||
if (mResources[iRes]->Name() == Name)
|
||||
return mResources[iRes];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@@ -25,7 +25,7 @@ public:
|
||||
TWideString FullPath() const;
|
||||
CVirtualDirectory* GetRoot();
|
||||
CVirtualDirectory* FindChildDirectory(const TWideString& rkName, bool AllowCreate);
|
||||
CResourceEntry* FindChildResource(const TWideString& rkName) const;
|
||||
CResourceEntry* FindChildResource(const TWideString& rkPath);
|
||||
void AddChild(const TWideString& rkPath, CResourceEntry *pEntry);
|
||||
bool RemoveChildDirectory(CVirtualDirectory *pSubdir);
|
||||
bool RemoveChildResource(CResourceEntry *pEntry);
|
||||
|
||||
Reference in New Issue
Block a user