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:
Aruki 2017-02-10 14:52:47 -07:00
parent 6d77604667
commit 882973d9d5
21 changed files with 321 additions and 78 deletions

View File

@ -18,17 +18,30 @@ public:
// Load XML and set current element to the root element; read version // Load XML and set current element to the root element; read version
mDoc.LoadFile(*rkFileName); mDoc.LoadFile(*rkFileName);
mpCurElem = mDoc.FirstChildElement(); mpCurElem = mDoc.FirstChildElement();
ASSERT(mpCurElem != nullptr);
mArchiveVersion = (u16) TString( mpCurElem->Attribute("ArchiveVer") ).ToInt32(10); if (mpCurElem != nullptr)
mFileVersion = (u16) TString( mpCurElem->Attribute("FileVer") ).ToInt32(10); {
const char *pkGameAttr = mpCurElem->Attribute("Game"); mArchiveVersion = (u16) TString( mpCurElem->Attribute("ArchiveVer") ).ToInt32(10);
mGame = pkGameAttr ? GetGameForID( CFourCC(pkGameAttr) ) : eUnknownGame; mFileVersion = (u16) TString( mpCurElem->Attribute("FileVer") ).ToInt32(10);
const char *pkGameAttr = mpCurElem->Attribute("Game");
mGame = pkGameAttr ? GetGameForID( CFourCC(pkGameAttr) ) : eUnknownGame;
}
else
{
Log::Error("Failed to open XML for read: " + rkFileName);
}
}
inline bool IsValid() const
{
return mpCurElem != nullptr;
} }
// Interface // Interface
virtual bool ParamBegin(const char *pkName) virtual bool ParamBegin(const char *pkName)
{ {
ASSERT(IsValid());
// Push new parent if needed // Push new parent if needed
if (!mJustEndedParam) if (!mJustEndedParam)
{ {

View File

@ -11,11 +11,13 @@ class CXMLWriter : public IArchive
tinyxml2::XMLDocument mDoc; tinyxml2::XMLDocument mDoc;
TString mOutFilename; TString mOutFilename;
tinyxml2::XMLElement *mpCurElem; tinyxml2::XMLElement *mpCurElem;
bool mSaved;
public: public:
CXMLWriter(const TString& rkFileName, const TString& rkRootName, u16 FileVersion, EGame Game = eUnknownGame) CXMLWriter(const TString& rkFileName, const TString& rkRootName, u16 FileVersion, EGame Game = eUnknownGame)
: IArchive(false, true) : IArchive(false, true)
, mOutFilename(rkFileName) , mOutFilename(rkFileName)
, mSaved(false)
{ {
SetVersion(skCurrentArchiveVersion, FileVersion, Game); SetVersion(skCurrentArchiveVersion, FileVersion, Game);
@ -34,12 +36,43 @@ public:
~CXMLWriter() ~CXMLWriter()
{ {
mDoc.SaveFile(*mOutFilename); if (!mSaved)
{
bool SaveSuccess = Save();
ASSERT(SaveSuccess);
}
}
inline bool Save()
{
if (mSaved)
{
Log::Error("Attempted to save XML twice!");
return false;
}
tinyxml2::XMLError Error = mDoc.SaveFile(*mOutFilename);
mSaved = true;
if (Error != tinyxml2::XML_SUCCESS)
{
Log::Error("Failed to save XML file: " + mOutFilename);
return false;
}
else
return true;
}
inline bool IsValid() const
{
return mpCurElem != nullptr && !mSaved;
} }
// Interface // Interface
virtual bool ParamBegin(const char *pkName) virtual bool ParamBegin(const char *pkName)
{ {
ASSERT(IsValid());
tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName); tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName);
mpCurElem->LinkEndChild(pElem); mpCurElem->LinkEndChild(pElem);
mpCurElem = pElem; mpCurElem = pElem;

View File

@ -1,15 +1,22 @@
#include "CAssetNameMap.h" #include "CAssetNameMap.h"
void CAssetNameMap::LoadAssetNames(TString Path /*= gkAssetMapPath*/) bool CAssetNameMap::LoadAssetNames(TString Path /*= gkAssetMapPath*/)
{ {
CXMLReader Reader(Path); 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); CXMLWriter Writer(Path, "AssetNameMap", 0, eUnknownGame);
Serialize(Writer); Serialize(Writer);
return Writer.Save();
} }
bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName) bool CAssetNameMap::GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName)

View File

@ -50,8 +50,8 @@ class CAssetNameMap
public: public:
CAssetNameMap() : mIsValid(true) {} CAssetNameMap() : mIsValid(true) {}
void LoadAssetNames(TString Path = gkAssetMapPath); bool LoadAssetNames(TString Path = gkAssetMapPath);
void SaveAssetNames(TString Path = gkAssetMapPath); bool SaveAssetNames(TString Path = gkAssetMapPath);
bool GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName); bool GetNameInfo(CAssetID ID, TString& rOutDirectory, TString& rOutName);
void CopyFromStore(CResourceStore *pStore); void CopyFromStore(CResourceStore *pStore);

View File

@ -342,7 +342,8 @@ void CGameExporter::LoadPaks()
// Add package to project and save // Add package to project and save
mpProject->AddPackage(pPackage); mpProject->AddPackage(pPackage);
#if SAVE_PACKAGE_DEFINITIONS #if SAVE_PACKAGE_DEFINITIONS
pPackage->Save(); bool SaveSuccess = pPackage->Save();
ASSERT(SaveSuccess);
#endif #endif
} }
#endif #endif
@ -461,7 +462,8 @@ void CGameExporter::ExportCookedResources()
#if EXPORT_COOKED #if EXPORT_COOKED
mpStore->SaveResourceDatabase(); mpStore->SaveResourceDatabase();
#endif #endif
mpProject->Save(); bool SaveSuccess = mpProject->Save();
ASSERT(SaveSuccess);
} }
} }

View File

@ -1,29 +1,35 @@
#include "CGameInfo.h" #include "CGameInfo.h"
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
void CGameInfo::LoadGameInfo(EGame Game) bool CGameInfo::LoadGameInfo(EGame Game)
{ {
Game = RoundGame(Game); Game = RoundGame(Game);
mGame = Game; mGame = Game;
TString Path = GetDefaultGameInfoPath(Game); TString Path = GetDefaultGameInfoPath(Game);
if (FileUtil::Exists(Path)) return LoadGameInfo(Path);
LoadGameInfo(Path);
} }
void CGameInfo::LoadGameInfo(TString Path) bool CGameInfo::LoadGameInfo(TString Path)
{ {
CXMLReader Reader(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 ASSERT(mGame != eUnknownGame); // can't save game info that was never loaded
if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame); if (Path.IsEmpty()) Path = GetDefaultGameInfoPath(mGame);
CXMLWriter Writer(Path, "GameInfo", 0, mGame); CXMLWriter Writer(Path, "GameInfo", 0, mGame);
Serialize(Writer); Serialize(Writer);
return Writer.Save();
} }
void CGameInfo::Serialize(IArchive& rArc) void CGameInfo::Serialize(IArchive& rArc)

View File

@ -21,9 +21,9 @@ public:
: mGame(eUnknownGame) : mGame(eUnknownGame)
{} {}
void LoadGameInfo(EGame Game); bool LoadGameInfo(EGame Game);
void LoadGameInfo(TString Path); bool LoadGameInfo(TString Path);
void SaveGameInfo(TString Path = ""); bool SaveGameInfo(TString Path = "");
void Serialize(IArchive& rArc); void Serialize(IArchive& rArc);
TString GetAreaName(const CAssetID& rkID) const; TString GetAreaName(const CAssetID& rkID) const;

View File

@ -7,7 +7,10 @@ CGameProject *CGameProject::mspActiveProject = nullptr;
CGameProject::~CGameProject() CGameProject::~CGameProject()
{ {
ASSERT(!mpResourceStore->IsDirty()); if (mpResourceStore)
{
ASSERT(!mpResourceStore->IsDirty());
}
if (IsActive()) if (IsActive())
{ {
@ -15,16 +18,23 @@ CGameProject::~CGameProject()
gpResourceStore = nullptr; gpResourceStore = nullptr;
} }
for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
delete mPackages[iPkg];
delete mpAudioManager; delete mpAudioManager;
delete mpGameInfo; delete mpGameInfo;
delete mpResourceStore; delete mpResourceStore;
} }
void CGameProject::Save() bool CGameProject::Save()
{ {
mProjFileLock.Release();
TString ProjPath = ProjectPath().ToUTF8(); TString ProjPath = ProjectPath().ToUTF8();
CXMLWriter Writer(ProjPath, "GameProject", eVer_Current, mGame); CXMLWriter Writer(ProjPath, "GameProject", eVer_Current, mGame);
Serialize(Writer); Serialize(Writer);
bool SaveSuccess = Writer.Save();
mProjFileLock.Lock(*ProjPath);
return SaveSuccess;
} }
void CGameProject::Serialize(IArchive& rArc) void CGameProject::Serialize(IArchive& rArc)
@ -60,22 +70,31 @@ void CGameProject::Serialize(IArchive& rArc)
// Load resource store // Load resource store
ASSERT(mpResourceStore == nullptr); ASSERT(mpResourceStore == nullptr);
mpResourceStore = new CResourceStore(this); mpResourceStore = new CResourceStore(this);
mpResourceStore->LoadResourceDatabase();
// Load packages if (!mpResourceStore->LoadResourceDatabase())
for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) mLoadSuccess = false;
delete mPackages[iPkg];
mPackages.clear();
for (u32 iPkg = 0; iPkg < PackageList.size(); iPkg++) else
{ {
const TWideString& rkPackagePath = PackageList[iPkg]; // Load packages
TString PackageName = TWideString(rkPackagePath.GetFileName(false)).ToUTF8(); ASSERT(mPackages.empty());
TWideString PackageDir = rkPackagePath.GetFileDirectory();
CPackage *pPackage = new CPackage(this, PackageName, PackageDir); for (u32 iPkg = 0; iPkg < PackageList.size(); iPkg++)
pPackage->Load(); {
mPackages.push_back(pPackage); 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->mProjectRoot.Replace(L"/", L"\\");
pProj->mpResourceStore = new CResourceStore(pProj, pExporter, L"Content\\", L"Cooked\\", Game); pProj->mpResourceStore = new CResourceStore(pProj, pExporter, L"Content\\", L"Cooked\\", Game);
pProj->mpGameInfo->LoadGameInfo(Game); pProj->mpGameInfo->LoadGameInfo(Game);
pProj->mLoadSuccess = true;
return pProj; return pProj;
} }
@ -171,10 +191,24 @@ CGameProject* CGameProject::LoadProject(const TWideString& rkProjPath)
TString ProjPath = rkProjPath.ToUTF8(); TString ProjPath = rkProjPath.ToUTF8();
CXMLReader Reader(ProjPath); CXMLReader Reader(ProjPath);
if (!Reader.IsValid())
{
delete pProj;
return nullptr;
}
pProj->mGame = Reader.Game(); pProj->mGame = Reader.Game();
pProj->Serialize(Reader); 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->mpGameInfo->LoadGameInfo(pProj->mGame);
pProj->mpAudioManager->LoadAssets(); pProj->mpAudioManager->LoadAssets();
return pProj; return pProj;

View File

@ -6,6 +6,7 @@
#include "CResourceStore.h" #include "CResourceStore.h"
#include "Core/CAudioManager.h" #include "Core/CAudioManager.h"
#include "Core/Resource/Script/CMasterTemplate.h" #include "Core/Resource/Script/CMasterTemplate.h"
#include <FileIO/CFileLock.h>
#include <Common/CAssetID.h> #include <Common/CAssetID.h>
#include <Common/EGame.h> #include <Common/EGame.h>
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
@ -31,6 +32,11 @@ class CGameProject
CGameInfo *mpGameInfo; CGameInfo *mpGameInfo;
CAudioManager *mpAudioManager; 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 enum EProjectVersion
{ {
eVer_Initial, eVer_Initial,
@ -50,6 +56,7 @@ class CGameProject
, mBuildVersion(0.f) , mBuildVersion(0.f)
, mResourceDBPath(L"ResourceDB.rdb") , mResourceDBPath(L"ResourceDB.rdb")
, mpResourceStore(nullptr) , mpResourceStore(nullptr)
, mLoadSuccess(true)
{ {
mpGameInfo = new CGameInfo(); mpGameInfo = new CGameInfo();
mpAudioManager = new CAudioManager(this); mpAudioManager = new CAudioManager(this);
@ -58,7 +65,7 @@ class CGameProject
public: public:
~CGameProject(); ~CGameProject();
void Save(); bool Save();
void Serialize(IArchive& rArc); void Serialize(IArchive& rArc);
void SetActive(); void SetActive();
void GetWorldList(std::list<CAssetID>& rOut) const; void GetWorldList(std::list<CAssetID>& rOut) const;

View File

@ -10,21 +10,28 @@
using namespace tinyxml2; using namespace tinyxml2;
void CPackage::Load() bool CPackage::Load()
{ {
TWideString DefPath = DefinitionPath(false); TWideString DefPath = DefinitionPath(false);
CXMLReader Reader(DefPath.ToUTF8()); 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); TWideString DefPath = DefinitionPath(false);
FileUtil::MakeDirectory(DefPath.GetFileDirectory()); FileUtil::MakeDirectory(DefPath.GetFileDirectory());
CXMLWriter Writer(DefPath.ToUTF8(), "PackageDefinition", 0, mpProject ? mpProject->Game() : eUnknownGame); CXMLWriter Writer(DefPath.ToUTF8(), "PackageDefinition", 0, mpProject ? mpProject->Game() : eUnknownGame);
Serialize(Writer); Serialize(Writer);
return Writer.Save();
} }
void CPackage::Serialize(IArchive& rArc) void CPackage::Serialize(IArchive& rArc)

View File

@ -71,8 +71,8 @@ public:
, mNeedsRecook(false) , mNeedsRecook(false)
{} {}
void Load(); bool Load();
void Save(); bool Save();
void Serialize(IArchive& rArc); void Serialize(IArchive& rArc);
void UpdateDependencyCache(); void UpdateDependencyCache();

View File

@ -195,9 +195,17 @@ bool CResourceEntry::Save(bool SkipCacheSave /*= false*/)
TString SerialName = mpTypeInfo->TypeName(); TString SerialName = mpTypeInfo->TypeName();
SerialName.RemoveWhitespace(); SerialName.RemoveWhitespace();
CXMLWriter Writer(Path, SerialName, 0, mGame); CXMLWriter Writer(Path, SerialName, 0, mGame);
mpResource->Serialize(Writer); mpResource->Serialize(Writer);
if (!Writer.Save())
{
Log::Error("Failed to save raw resource: " + Path);
DEBUG_BREAK;
return false;
}
mFlags |= eREF_NeedsRecook; mFlags |= eREF_NeedsRecook;
} }
@ -286,16 +294,28 @@ CResource* CResourceEntry::Load()
gpResourceStore = mpStore; gpResourceStore = mpStore;
CXMLReader Reader(RawAssetPath()); 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); CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian);

View File

@ -108,7 +108,7 @@ void CResourceStore::SerializeResourceDatabase(IArchive& rArc)
} }
} }
void CResourceStore::LoadResourceDatabase() bool CResourceStore::LoadResourceDatabase()
{ {
ASSERT(!mDatabasePath.IsEmpty()); ASSERT(!mDatabasePath.IsEmpty());
TString Path = DatabasePath().ToUTF8(); TString Path = DatabasePath().ToUTF8();
@ -118,27 +118,45 @@ void CResourceStore::LoadResourceDatabase()
CXMLReader Reader(Path); CXMLReader Reader(Path);
if (!Reader.IsValid())
{
Log::Error("Failed to open resource database for load: " + Path);
return false;
}
if (mpProj) if (mpProj)
ASSERT(mpProj->Game() == Reader.Game()); ASSERT(mpProj->Game() == Reader.Game());
mGame = Reader.Game(); mGame = Reader.Game();
SerializeResourceDatabase(Reader); SerializeResourceDatabase(Reader);
LoadCacheFile(); return LoadCacheFile();
} }
void CResourceStore::SaveResourceDatabase() bool CResourceStore::SaveResourceDatabase()
{ {
TString Path = DatabasePath().ToUTF8(); TString Path = DatabasePath().ToUTF8();
CXMLWriter Writer(Path, "ResourceDB", 0, mGame); CXMLWriter Writer(Path, "ResourceDB", 0, mGame);
SerializeResourceDatabase(Writer); 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(); TString CachePath = CacheDataPath().ToUTF8();
CFileInStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian); 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 // Cache header
CFourCC Magic(CacheFile); CFourCC Magic(CacheFile);
@ -146,7 +164,7 @@ void CResourceStore::LoadCacheFile()
if (Magic != "CACH") if (Magic != "CACH")
{ {
Log::Error("Invalid resource cache data magic: " + Magic.ToString()); Log::Error("Invalid resource cache data magic: " + Magic.ToString());
return; return false;
} }
CSerialVersion Version(CacheFile); CSerialVersion Version(CacheFile);
@ -173,13 +191,19 @@ void CResourceStore::LoadCacheFile()
CacheFile.Seek(EntryCacheEnd, SEEK_SET); CacheFile.Seek(EntryCacheEnd, SEEK_SET);
} }
return true;
} }
void CResourceStore::SaveCacheFile() bool CResourceStore::SaveCacheFile()
{ {
TString CachePath = CacheDataPath().ToUTF8(); TString CachePath = CacheDataPath().ToUTF8();
CFileOutStream CacheFile(CachePath.ToStdString(), IOUtil::eBigEndian); 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 // Cache header
CFourCC("CACH").Write(CacheFile); CFourCC("CACH").Write(CacheFile);
@ -219,6 +243,7 @@ void CResourceStore::SaveCacheFile()
CacheFile.Seek(ResCountOffset, SEEK_SET); CacheFile.Seek(ResCountOffset, SEEK_SET);
CacheFile.WriteLong(ResCount); CacheFile.WriteLong(ResCount);
mCacheFileDirty = false; mCacheFileDirty = false;
return true;
} }
void CResourceStore::ConditionalSaveStore() void CResourceStore::ConditionalSaveStore()

View File

@ -52,10 +52,10 @@ public:
CResourceStore(CGameProject *pProject); CResourceStore(CGameProject *pProject);
~CResourceStore(); ~CResourceStore();
void SerializeResourceDatabase(IArchive& rArc); void SerializeResourceDatabase(IArchive& rArc);
void LoadResourceDatabase(); bool LoadResourceDatabase();
void SaveResourceDatabase(); bool SaveResourceDatabase();
void LoadCacheFile(); bool LoadCacheFile();
void SaveCacheFile(); bool SaveCacheFile();
void ConditionalSaveStore(); void ConditionalSaveStore();
void SetProject(CGameProject *pProj); void SetProject(CGameProject *pProj);
void CloseProject(); void CloseProject();

View File

@ -335,12 +335,20 @@ void CExportGameDialog::Export()
CAssetNameMap NameMap; CAssetNameMap NameMap;
if (!NameMapPath.isEmpty()) if (!NameMapPath.isEmpty())
NameMap.LoadAssetNames( TO_TSTRING(NameMapPath) );
if (!NameMap.IsValid())
{ {
UICommon::ErrorMsg(this, "The Asset Name Map is invalid and cannot be used! See the log for more information."); bool LoadSuccess = NameMap.LoadAssetNames( TO_TSTRING(NameMapPath) );
return;
if (!LoadSuccess)
{
UICommon::ErrorMsg(this, "Failed to load the asset name map!");
return;
}
else if (!NameMap.IsValid())
{
UICommon::ErrorMsg(this, "The Asset Name Map is invalid and cannot be used! See the log for more information.");
return;
}
} }
// Verify game info is valid // Verify game info is valid
@ -350,12 +358,20 @@ void CExportGameDialog::Export()
return; return;
} }
// Do export
close();
CGameInfo GameInfo; CGameInfo GameInfo;
if (!GameInfoPath.isEmpty()) if (!GameInfoPath.isEmpty())
GameInfo.LoadGameInfo( TO_TSTRING(GameInfoPath) ); {
bool LoadSuccess = GameInfo.LoadGameInfo( TO_TSTRING(GameInfoPath) );
if (!LoadSuccess)
{
UICommon::ErrorMsg(this, "Failed to load game info!");
return;
}
}
// Do export
close();
CGameExporter Exporter(mGame, mRegion, mGameTitle, mGameID, mBuildVer); CGameExporter Exporter(mGame, mRegion, mGameTitle, mGameID, mBuildVer);
TString StrExportDir = TO_TSTRING(ExportDir); TString StrExportDir = TO_TSTRING(ExportDir);

View File

@ -49,7 +49,9 @@ void CProjectOverviewDialog::InternalLoadProject(const QString& rkPath)
} }
else else
Log::Error("Failed to load project"); {
UICommon::ErrorMsg(this, "Failed to open project! Is it already open in another Prime World Editor instance?");
}
} }
void CProjectOverviewDialog::OpenProject() void CProjectOverviewDialog::OpenProject()

View File

@ -322,7 +322,18 @@ void CResourceBrowser::OnGenerateAssetNames()
void CResourceBrowser::OnImportNamesFromAssetNameMap() void CResourceBrowser::OnImportNamesFromAssetNameMap()
{ {
CAssetNameMap Map; CAssetNameMap Map;
Map.LoadAssetNames(); bool LoadSuccess = Map.LoadAssetNames();
if (!LoadSuccess)
{
UICommon::ErrorMsg(this, "Import failed; couldn't load asset name map!");
return;
}
else if (!Map.IsValid())
{
UICommon::ErrorMsg(this, "Import failed; the input asset name map is invalid! See the log for details.");
return;
}
for (CResourceIterator It(mpStore); It; ++It) for (CResourceIterator It(mpStore); It; ++It)
{ {
@ -335,6 +346,7 @@ void CResourceBrowser::OnImportNamesFromAssetNameMap()
mpStore->ConditionalSaveStore(); mpStore->ConditionalSaveStore();
RefreshResources(); RefreshResources();
RefreshDirectories(); RefreshDirectories();
UICommon::InfoMsg(this, "Success", "New asset names imported successfully!");
} }
void CResourceBrowser::ExportAssetNames() void CResourceBrowser::ExportAssetNames()
@ -346,10 +358,29 @@ void CResourceBrowser::ExportAssetNames()
CAssetNameMap NameMap; CAssetNameMap NameMap;
if (FileUtil::Exists(OutFileStr)) if (FileUtil::Exists(OutFileStr))
NameMap.LoadAssetNames(OutFileStr); {
bool LoadSuccess = NameMap.LoadAssetNames(OutFileStr);
if (!LoadSuccess)
{
UICommon::ErrorMsg(this, "Unable to export; failed to load existing names from the original asset name map file!");
return;
}
else if (!NameMap.IsValid())
{
UICommon::ErrorMsg(this, "Unable to export; the original asset name map file is invalid! See the log for details.");
return;
}
}
NameMap.CopyFromStore(mpStore); NameMap.CopyFromStore(mpStore);
NameMap.SaveAssetNames(OutFileStr); bool SaveSuccess = NameMap.SaveAssetNames(OutFileStr);
if (SaveSuccess)
UICommon::ErrorMsg(this, "Failed to export asset names!");
else
UICommon::InfoMsg(this, "Success", "Asset names exported successfully!");
} }
void CResourceBrowser::UpdateFilter() void CResourceBrowser::UpdateFilter()

View File

@ -102,6 +102,11 @@ inline QString OpenDirDialog(QWidget *pParent, const QString& rkCaption, const Q
} }
// QMessageBox wrappers // QMessageBox wrappers
inline void InfoMsg(QWidget *pParent, QString InfoBoxTitle, QString InfoText)
{
QMessageBox::information(pParent, InfoBoxTitle, InfoText);
}
inline void ErrorMsg(QWidget *pParent, QString ErrorText) inline void ErrorMsg(QWidget *pParent, QString ErrorText)
{ {
QMessageBox::warning(pParent, "Error", ErrorText); QMessageBox::warning(pParent, "Error", ErrorText);

34
src/FileIO/CFileLock.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef CFILELOCK_H
#define CFILELOCK_H
#include <cstdio>
// Maintain a file handle to prevent other processes from accessing the file.
class CFileLock
{
FILE* mpFile;
public:
CFileLock()
: mpFile(nullptr)
{}
~CFileLock()
{
Release();
}
void Lock(const char *pkPath)
{
Release();
mpFile = fopen(pkPath, "a+");
}
void Release()
{
if (mpFile)
fclose(mpFile);
}
};
#endif // CFILELOCK_H

View File

@ -41,7 +41,8 @@ HEADERS += \
IOUtil.h \ IOUtil.h \
IInputStream.h \ IInputStream.h \
IOutputStream.h \ IOutputStream.h \
CBitStreamInWrapper.h CBitStreamInWrapper.h \
CFileLock.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -7,7 +7,7 @@
<enumerator ID="0x03" name="Immune"/> <enumerator ID="0x03" name="Immune"/>
<enumerator ID="0x04" name="Pass Through"/> <enumerator ID="0x04" name="Pass Through"/>
<enumerator ID="0x05" name="Direct/Double"/> <enumerator ID="0x05" name="Direct/Double"/>
<enumerator ID="0x06" name="Direct"/> <enumerator ID="0x06" name="Direct/Normal"/>
<enumerator ID="0x07" name="Immune?"/> <enumerator ID="0x07" name="Direct/Immune"/>
</enumerators> </enumerators>
</enum> </enum>