mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-17 08:57:09 +00:00
Improved error handling and reporting when loading/saving project files; added file lock class to prevent the same project from being opened in multiple PWE instances
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
#include "CAssetNameMap.h"
|
||||
|
||||
void CAssetNameMap::LoadAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||
bool CAssetNameMap::LoadAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||
{
|
||||
CXMLReader Reader(Path);
|
||||
Serialize(Reader);
|
||||
|
||||
if (Reader.IsValid())
|
||||
{
|
||||
Serialize(Reader);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
void CAssetNameMap::SaveAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||
bool CAssetNameMap::SaveAssetNames(TString Path /*= gkAssetMapPath*/)
|
||||
{
|
||||
CXMLWriter Writer(Path, "AssetNameMap", 0, eUnknownGame);
|
||||
Serialize(Writer);
|
||||
return Writer.Save();
|
||||
}
|
||||
|
||||
bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName)
|
||||
|
||||
@@ -50,8 +50,8 @@ class CAssetNameMap
|
||||
|
||||
public:
|
||||
CAssetNameMap() : mIsValid(true) {}
|
||||
void LoadAssetNames(TString Path = gkAssetMapPath);
|
||||
void SaveAssetNames(TString Path = gkAssetMapPath);
|
||||
bool LoadAssetNames(TString Path = gkAssetMapPath);
|
||||
bool SaveAssetNames(TString Path = gkAssetMapPath);
|
||||
bool GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName);
|
||||
void CopyFromStore(CResourceStore *pStore);
|
||||
|
||||
|
||||
@@ -342,7 +342,8 @@ void CGameExporter::LoadPaks()
|
||||
// Add package to project and save
|
||||
mpProject->AddPackage(pPackage);
|
||||
#if SAVE_PACKAGE_DEFINITIONS
|
||||
pPackage->Save();
|
||||
bool SaveSuccess = pPackage->Save();
|
||||
ASSERT(SaveSuccess);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -461,7 +462,8 @@ void CGameExporter::ExportCookedResources()
|
||||
#if EXPORT_COOKED
|
||||
mpStore->SaveResourceDatabase();
|
||||
#endif
|
||||
mpProject->Save();
|
||||
bool SaveSuccess = mpProject->Save();
|
||||
ASSERT(SaveSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
#include "CGameInfo.h"
|
||||
#include <Common/FileUtil.h>
|
||||
|
||||
void CGameInfo::LoadGameInfo(EGame Game)
|
||||
bool CGameInfo::LoadGameInfo(EGame Game)
|
||||
{
|
||||
Game = RoundGame(Game);
|
||||
mGame = Game;
|
||||
|
||||
TString Path = GetDefaultGameInfoPath(Game);
|
||||
if (FileUtil::Exists(Path))
|
||||
LoadGameInfo(Path);
|
||||
return LoadGameInfo(Path);
|
||||
}
|
||||
|
||||
void CGameInfo::LoadGameInfo(TString Path)
|
||||
bool CGameInfo::LoadGameInfo(TString Path)
|
||||
{
|
||||
CXMLReader Reader(Path);
|
||||
Serialize(Reader);
|
||||
|
||||
if (Reader.IsValid())
|
||||
{
|
||||
Serialize(Reader);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
void CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
||||
bool CGameInfo::SaveGameInfo(TString Path /*= ""*/)
|
||||
{
|
||||
ASSERT(mGame != eUnknownGame); // can't save game info that was never loaded
|
||||
|
||||
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
|
||||
CXMLWriter Writer(Path, "GameInfo", 0, mGame);
|
||||
Serialize(Writer);
|
||||
return Writer.Save();
|
||||
}
|
||||
|
||||
void CGameInfo::Serialize(IArchive& rArc)
|
||||
|
||||
@@ -21,9 +21,9 @@ public:
|
||||
: mGame(eUnknownGame)
|
||||
{}
|
||||
|
||||
void LoadGameInfo(EGame Game);
|
||||
void LoadGameInfo(TString Path);
|
||||
void SaveGameInfo(TString Path = "");
|
||||
bool LoadGameInfo(EGame Game);
|
||||
bool LoadGameInfo(TString Path);
|
||||
bool SaveGameInfo(TString Path = "");
|
||||
void Serialize(IArchive& rArc);
|
||||
|
||||
TString GetAreaName(const CAssetID& rkID) const;
|
||||
|
||||
@@ -7,7 +7,10 @@ CGameProject *CGameProject::mspActiveProject = nullptr;
|
||||
|
||||
CGameProject::~CGameProject()
|
||||
{
|
||||
ASSERT(!mpResourceStore->IsDirty());
|
||||
if (mpResourceStore)
|
||||
{
|
||||
ASSERT(!mpResourceStore->IsDirty());
|
||||
}
|
||||
|
||||
if (IsActive())
|
||||
{
|
||||
@@ -15,16 +18,23 @@ CGameProject::~CGameProject()
|
||||
gpResourceStore = nullptr;
|
||||
}
|
||||
|
||||
for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
||||
delete mPackages[iPkg];
|
||||
|
||||
delete mpAudioManager;
|
||||
delete mpGameInfo;
|
||||
delete mpResourceStore;
|
||||
}
|
||||
|
||||
void CGameProject::Save()
|
||||
bool CGameProject::Save()
|
||||
{
|
||||
mProjFileLock.Release();
|
||||
TString ProjPath = ProjectPath().ToUTF8();
|
||||
CXMLWriter Writer(ProjPath, "GameProject", eVer_Current, mGame);
|
||||
Serialize(Writer);
|
||||
bool SaveSuccess = Writer.Save();
|
||||
mProjFileLock.Lock(*ProjPath);
|
||||
return SaveSuccess;
|
||||
}
|
||||
|
||||
void CGameProject::Serialize(IArchive& rArc)
|
||||
@@ -60,22 +70,31 @@ void CGameProject::Serialize(IArchive& rArc)
|
||||
// Load resource store
|
||||
ASSERT(mpResourceStore == nullptr);
|
||||
mpResourceStore = new CResourceStore(this);
|
||||
mpResourceStore->LoadResourceDatabase();
|
||||
|
||||
// Load packages
|
||||
for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
|
||||
delete mPackages[iPkg];
|
||||
mPackages.clear();
|
||||
if (!mpResourceStore->LoadResourceDatabase())
|
||||
mLoadSuccess = false;
|
||||
|
||||
for (u32 iPkg = 0; iPkg < PackageList.size(); iPkg++)
|
||||
else
|
||||
{
|
||||
const TWideString& rkPackagePath = PackageList[iPkg];
|
||||
TString PackageName = TWideString(rkPackagePath.GetFileName(false)).ToUTF8();
|
||||
TWideString PackageDir = rkPackagePath.GetFileDirectory();
|
||||
// Load packages
|
||||
ASSERT(mPackages.empty());
|
||||
|
||||
CPackage *pPackage = new CPackage(this, PackageName, PackageDir);
|
||||
pPackage->Load();
|
||||
mPackages.push_back(pPackage);
|
||||
for (u32 iPkg = 0; iPkg < PackageList.size(); iPkg++)
|
||||
{
|
||||
const TWideString& rkPackagePath = PackageList[iPkg];
|
||||
TString PackageName = TWideString(rkPackagePath.GetFileName(false)).ToUTF8();
|
||||
TWideString PackageDir = rkPackagePath.GetFileDirectory();
|
||||
|
||||
CPackage *pPackage = new CPackage(this, PackageName, PackageDir);
|
||||
bool PackageLoadSuccess = pPackage->Load();
|
||||
mPackages.push_back(pPackage);
|
||||
|
||||
if (!PackageLoadSuccess)
|
||||
{
|
||||
mLoadSuccess = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +179,7 @@ CGameProject* CGameProject::CreateProjectForExport(
|
||||
pProj->mProjectRoot.Replace(L"/", L"\\");
|
||||
pProj->mpResourceStore = new CResourceStore(pProj, pExporter, L"Content\\", L"Cooked\\", Game);
|
||||
pProj->mpGameInfo->LoadGameInfo(Game);
|
||||
pProj->mLoadSuccess = true;
|
||||
return pProj;
|
||||
}
|
||||
|
||||
@@ -171,10 +191,24 @@ CGameProject* CGameProject::LoadProject(const TWideString& rkProjPath)
|
||||
|
||||
TString ProjPath = rkProjPath.ToUTF8();
|
||||
CXMLReader Reader(ProjPath);
|
||||
|
||||
if (!Reader.IsValid())
|
||||
{
|
||||
delete pProj;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pProj->mGame = Reader.Game();
|
||||
pProj->Serialize(Reader);
|
||||
CTemplateLoader::LoadGameTemplates(pProj->mGame);
|
||||
|
||||
if (!pProj->mLoadSuccess)
|
||||
{
|
||||
delete pProj;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CTemplateLoader::LoadGameTemplates(pProj->mGame);
|
||||
pProj->mProjFileLock.Lock(*ProjPath);
|
||||
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
||||
pProj->mpAudioManager->LoadAssets();
|
||||
return pProj;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "CResourceStore.h"
|
||||
#include "Core/CAudioManager.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include <FileIO/CFileLock.h>
|
||||
#include <Common/CAssetID.h>
|
||||
#include <Common/EGame.h>
|
||||
#include <Common/FileUtil.h>
|
||||
@@ -31,6 +32,11 @@ class CGameProject
|
||||
CGameInfo *mpGameInfo;
|
||||
CAudioManager *mpAudioManager;
|
||||
|
||||
// Keep file handle open for the .prj file to prevent users from opening the same project
|
||||
// in multiple instances of PWE
|
||||
CFileLock mProjFileLock;
|
||||
bool mLoadSuccess;
|
||||
|
||||
enum EProjectVersion
|
||||
{
|
||||
eVer_Initial,
|
||||
@@ -50,6 +56,7 @@ class CGameProject
|
||||
, mBuildVersion(0.f)
|
||||
, mResourceDBPath(L"ResourceDB.rdb")
|
||||
, mpResourceStore(nullptr)
|
||||
, mLoadSuccess(true)
|
||||
{
|
||||
mpGameInfo = new CGameInfo();
|
||||
mpAudioManager = new CAudioManager(this);
|
||||
@@ -58,7 +65,7 @@ class CGameProject
|
||||
public:
|
||||
~CGameProject();
|
||||
|
||||
void Save();
|
||||
bool Save();
|
||||
void Serialize(IArchive& rArc);
|
||||
void SetActive();
|
||||
void GetWorldList(std::list<CAssetID>& rOut) const;
|
||||
|
||||
@@ -10,21 +10,28 @@
|
||||
|
||||
using namespace tinyxml2;
|
||||
|
||||
void CPackage::Load()
|
||||
bool CPackage::Load()
|
||||
{
|
||||
TWideString DefPath = DefinitionPath(false);
|
||||
CXMLReader Reader(DefPath.ToUTF8());
|
||||
Serialize(Reader);
|
||||
UpdateDependencyCache();
|
||||
|
||||
if (Reader.IsValid())
|
||||
{
|
||||
Serialize(Reader);
|
||||
UpdateDependencyCache();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
void CPackage::Save()
|
||||
bool CPackage::Save()
|
||||
{
|
||||
TWideString DefPath = DefinitionPath(false);
|
||||
FileUtil::MakeDirectory(DefPath.GetFileDirectory());
|
||||
|
||||
CXMLWriter Writer(DefPath.ToUTF8(), "PackageDefinition", 0, mpProject ? mpProject->Game() : eUnknownGame);
|
||||
Serialize(Writer);
|
||||
return Writer.Save();
|
||||
}
|
||||
|
||||
void CPackage::Serialize(IArchive& rArc)
|
||||
|
||||
@@ -71,8 +71,8 @@ public:
|
||||
, mNeedsRecook(false)
|
||||
{}
|
||||
|
||||
void Load();
|
||||
void Save();
|
||||
bool Load();
|
||||
bool Save();
|
||||
void Serialize(IArchive& rArc);
|
||||
void UpdateDependencyCache();
|
||||
|
||||
|
||||
@@ -195,9 +195,17 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
|
||||
|
||||
TString SerialName = mpTypeInfo->TypeName();
|
||||
SerialName.RemoveWhitespace();
|
||||
|
||||
CXMLWriter Writer(Path, SerialName, 0, mGame);
|
||||
mpResource->Serialize(Writer);
|
||||
|
||||
if (!Writer.Save())
|
||||
{
|
||||
Log::Error("Failed to save raw resource: " + Path);
|
||||
DEBUG_BREAK;
|
||||
return false;
|
||||
}
|
||||
|
||||
mFlags |= eREF_NeedsRecook;
|
||||
}
|
||||
|
||||
@@ -286,16 +294,28 @@ CResource* CResourceEntry::Load()
|
||||
gpResourceStore = mpStore;
|
||||
|
||||
CXMLReader Reader(RawAssetPath());
|
||||
mpResource->Serialize(Reader);
|
||||
mpStore->TrackLoadedResource(this);
|
||||
|
||||
gpResourceStore = pOldStore;
|
||||
if (!Reader.IsValid())
|
||||
{
|
||||
Log::Error("Failed to load raw resource; falling back on cooked. Raw path: " + RawAssetPath());
|
||||
delete mpResource;
|
||||
mpResource = nullptr;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
mpResource->Serialize(Reader);
|
||||
mpStore->TrackLoadedResource(this);
|
||||
gpResourceStore = pOldStore;
|
||||
}
|
||||
}
|
||||
|
||||
return mpResource;
|
||||
if (mpResource)
|
||||
return mpResource;
|
||||
}
|
||||
|
||||
else if (HasCookedVersion())
|
||||
ASSERT(!mpResource);
|
||||
if (HasCookedVersion())
|
||||
{
|
||||
CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ void CResourceStore::SerializeResourceDatabase(IArchive& rArc)
|
||||
}
|
||||
}
|
||||
|
||||
void CResourceStore::LoadResourceDatabase()
|
||||
bool CResourceStore::LoadResourceDatabase()
|
||||
{
|
||||
ASSERT(!mDatabasePath.IsEmpty());
|
||||
TString Path = DatabasePath().ToUTF8();
|
||||
@@ -118,27 +118,45 @@ void CResourceStore::LoadResourceDatabase()
|
||||
|
||||
CXMLReader Reader(Path);
|
||||
|
||||
if (!Reader.IsValid())
|
||||
{
|
||||
Log::Error("Failed to open resource database for load: " + Path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mpProj)
|
||||
ASSERT(mpProj->Game() == Reader.Game());
|
||||
|
||||
mGame = Reader.Game();
|
||||
SerializeResourceDatabase(Reader);
|
||||
LoadCacheFile();
|
||||
return LoadCacheFile();
|
||||
}
|
||||
|
||||
void CResourceStore::SaveResourceDatabase()
|
||||
bool CResourceStore::SaveResourceDatabase()
|
||||
{
|
||||
TString Path = DatabasePath().ToUTF8();
|
||||
CXMLWriter Writer(Path, "ResourceDB", 0, mGame);
|
||||
SerializeResourceDatabase(Writer);
|
||||
mDatabaseDirty = false;
|
||||
bool SaveSuccess = Writer.Save();
|
||||
|
||||
if (SaveSuccess)
|
||||
mDatabaseDirty = false;
|
||||
else
|
||||
Log::Error("Failed to save resource database: " + Path);
|
||||
|
||||
return SaveSuccess;
|
||||
}
|
||||
|
||||
void CResourceStore::LoadCacheFile()
|
||||
bool CResourceStore::LoadCacheFile()
|
||||
{
|
||||
TString CachePath = CacheDataPath().ToUTF8();
|
||||
CFileInStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian);
|
||||
ASSERT(CacheFile.IsValid());
|
||||
|
||||
if (!CacheFile.IsValid())
|
||||
{
|
||||
Log::Error("Failed to open cache file for load: " + CachePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache header
|
||||
CFourCC Magic(CacheFile);
|
||||
@@ -146,7 +164,7 @@ void CResourceStore::LoadCacheFile()
|
||||
if (Magic != "CACH")
|
||||
{
|
||||
Log::Error("Invalid resource cache data magic: " + Magic.ToString());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
CSerialVersion Version(CacheFile);
|
||||
@@ -173,13 +191,19 @@ void CResourceStore::LoadCacheFile()
|
||||
|
||||
CacheFile.Seek(EntryCacheEnd, SEEK_SET);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CResourceStore::SaveCacheFile()
|
||||
bool CResourceStore::SaveCacheFile()
|
||||
{
|
||||
TString CachePath = CacheDataPath().ToUTF8();
|
||||
CFileOutStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian);
|
||||
ASSERT(CacheFile.IsValid());
|
||||
|
||||
if (!CacheFile.IsValid())
|
||||
{
|
||||
Log::Error("Failed to open cache file for save: " + CachePath);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache header
|
||||
CFourCC("CACH").Write(CacheFile);
|
||||
@@ -219,6 +243,7 @@ void CResourceStore::SaveCacheFile()
|
||||
CacheFile.Seek(ResCountOffset, SEEK_SET);
|
||||
CacheFile.WriteLong(ResCount);
|
||||
mCacheFileDirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CResourceStore::ConditionalSaveStore()
|
||||
|
||||
@@ -52,10 +52,10 @@ public:
|
||||
CResourceStore(CGameProject *pProject);
|
||||
~CResourceStore();
|
||||
void SerializeResourceDatabase(IArchive& rArc);
|
||||
void LoadResourceDatabase();
|
||||
void SaveResourceDatabase();
|
||||
void LoadCacheFile();
|
||||
void SaveCacheFile();
|
||||
bool LoadResourceDatabase();
|
||||
bool SaveResourceDatabase();
|
||||
bool LoadCacheFile();
|
||||
bool SaveCacheFile();
|
||||
void ConditionalSaveStore();
|
||||
void SetProject(CGameProject *pProj);
|
||||
void CloseProject();
|
||||
|
||||
Reference in New Issue
Block a user