CGameProject: Make use of unique_ptr where applicable

Makes the ownership semantics explicit.
This commit is contained in:
Lioncash 2020-06-12 14:56:23 -04:00
parent 1bdcdb85de
commit 1ae5462cd7
6 changed files with 83 additions and 104 deletions

View File

@ -94,7 +94,7 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs
// Export finished! // Export finished!
mProjectPath = mpProject->ProjectPath(); mProjectPath = mpProject->ProjectPath();
delete mpProject; mpProject.reset();
if (pOldStore) gpResourceStore = pOldStore; if (pOldStore) gpResourceStore = pOldStore;
return !mpProgress->ShouldCancel(); return !mpProgress->ShouldCancel();
} }
@ -280,7 +280,7 @@ void CGameExporter::LoadPaks()
} }
TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false)); TString RelPakPath = FileUtil::MakeRelative(PakPath.GetFileDirectory(), mpProject->DiscFilesystemRoot(false));
CPackage *pPackage = new CPackage(mpProject, PakPath.GetFileName(false), RelPakPath); auto pPackage = std::make_unique<CPackage>(mpProject.get(), PakPath.GetFileName(false), RelPakPath);
// MP1-MP3Proto // MP1-MP3Proto
if (mGame < EGame::Corruption) if (mGame < EGame::Corruption)
@ -327,15 +327,17 @@ void CGameExporter::LoadPaks()
mAreaDuplicateMap[ResID] = AreaHasDuplicates; mAreaDuplicateMap[ResID] = AreaHasDuplicates;
AreaHasDuplicates = false; AreaHasDuplicates = false;
} }
else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end()) else if (!AreaHasDuplicates && PakResourceSet.find(ResID) != PakResourceSet.end())
{
AreaHasDuplicates = true; AreaHasDuplicates = true;
}
else else
{
PakResourceSet.insert(ResID); PakResourceSet.insert(ResID);
} }
} }
} }
}
// MP3 + DKCR // MP3 + DKCR
else else
@ -423,11 +425,12 @@ void CGameExporter::LoadPaks()
} }
// Add package to project and save // Add package to project and save
mpProject->AddPackage(pPackage);
#if SAVE_PACKAGE_DEFINITIONS #if SAVE_PACKAGE_DEFINITIONS
bool SaveSuccess = pPackage->Save(); [[maybe_unused]] const bool SaveSuccess = pPackage->Save();
ASSERT(SaveSuccess); ASSERT(SaveSuccess);
#endif #endif
mpProject->AddPackage(std::move(pPackage));
} }
#endif #endif
} }

View File

@ -9,6 +9,7 @@
#include <Common/Flags.h> #include <Common/Flags.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <map> #include <map>
#include <memory>
#include <nod/DiscBase.hpp> #include <nod/DiscBase.hpp>
enum class EDiscType enum class EDiscType
@ -21,7 +22,7 @@ enum class EDiscType
class CGameExporter class CGameExporter
{ {
// Project Data // Project Data
CGameProject *mpProject; std::unique_ptr<CGameProject> mpProject;
TString mProjectPath; TString mProjectPath;
CResourceStore *mpStore; CResourceStore *mpStore;
EGame mGame; EGame mGame;

View File

@ -14,18 +14,15 @@
CGameProject::~CGameProject() CGameProject::~CGameProject()
{ {
if (mpResourceStore) if (!mpResourceStore)
{ return;
ASSERT(!mpResourceStore->IsCacheDirty()); ASSERT(!mpResourceStore->IsCacheDirty());
if (gpResourceStore == mpResourceStore.get()) if (gpResourceStore == mpResourceStore.get())
gpResourceStore = nullptr; gpResourceStore = nullptr;
} }
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++)
delete mPackages[iPkg];
}
bool CGameProject::Save() bool CGameProject::Save()
{ {
mProjFileLock.Release(); mProjFileLock.Release();
@ -60,15 +57,14 @@ bool CGameProject::Serialize(IArchive& rArc)
{ {
ASSERT(mPackages.empty()); ASSERT(mPackages.empty());
for (uint32 iPkg = 0; iPkg < PackageList.size(); iPkg++) for (const TString& packagePath : PackageList)
{ {
const TString& rkPackagePath = PackageList[iPkg]; TString PackageName = packagePath.GetFileName(false);
TString PackageName = rkPackagePath.GetFileName(false); TString PackageDir = packagePath.GetFileDirectory();
TString PackageDir = rkPackagePath.GetFileDirectory();
CPackage *pPackage = new CPackage(this, PackageName, PackageDir); auto pPackage = std::make_unique<CPackage>(this, PackageName, PackageDir);
bool PackageLoadSuccess = pPackage->Load(); const bool PackageLoadSuccess = pPackage->Load();
mPackages.push_back(pPackage); mPackages.push_back(std::move(pPackage));
if (!PackageLoadSuccess) if (!PackageLoadSuccess)
{ {
@ -126,10 +122,8 @@ bool CGameProject::MergeISO(const TString& rkIsoPath, nod::DiscWii *pOriginalIso
void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (const auto& pPkg : mPackages)
{ {
CPackage *pPkg = mPackages[iPkg];
// Little workaround to fix some of Retro's paks having worlds listed in the wrong order... // Little workaround to fix some of Retro's paks having worlds listed in the wrong order...
// Construct a sorted list of worlds in this package // Construct a sorted list of worlds in this package
std::list<const SNamedResource*> PackageWorlds; std::list<const SNamedResource*> PackageWorlds;
@ -147,23 +141,20 @@ void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
}); });
// Add sorted worlds to the output world list // Add sorted worlds to the output world list
for (auto Iter = PackageWorlds.begin(); Iter != PackageWorlds.end(); Iter++) for (const auto* res : PackageWorlds)
{ {
const SNamedResource *pkRes = *Iter; rOut.push_back(res->ID);
rOut.push_back(pkRes->ID);
} }
} }
} }
CAssetID CGameProject::FindNamedResource(const TString& rkName) const CAssetID CGameProject::FindNamedResource(const TString& rkName) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (const auto& pkg : mPackages)
{ {
CPackage *pPkg = mPackages[iPkg]; for (uint32 iRes = 0; iRes < pkg->NumNamedResources(); iRes++)
for (uint32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++)
{ {
const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); const SNamedResource& rkRes = pkg->NamedResourceByIndex(iRes);
if (rkRes.Name == rkName) if (rkRes.Name == rkName)
return rkRes.ID; return rkRes.ID;
@ -175,20 +166,18 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const
CPackage* CGameProject::FindPackage(const TString& rkName) const CPackage* CGameProject::FindPackage(const TString& rkName) const
{ {
for (uint32 iPkg = 0; iPkg < mPackages.size(); iPkg++) for (const auto& pPackage : mPackages)
{ {
CPackage *pPackage = mPackages[iPkg];
if (pPackage->Name() == rkName) if (pPackage->Name() == rkName)
{ {
return pPackage; return pPackage.get();
} }
} }
return nullptr; return nullptr;
} }
CGameProject* CGameProject::CreateProjectForExport( std::unique_ptr<CGameProject> CGameProject::CreateProjectForExport(
const TString& rkProjRootDir, const TString& rkProjRootDir,
EGame Game, EGame Game,
ERegion Region, ERegion Region,
@ -196,7 +185,7 @@ CGameProject* CGameProject::CreateProjectForExport(
float BuildVer float BuildVer
) )
{ {
CGameProject *pProj = new CGameProject; auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mGame = Game; pProj->mGame = Game;
pProj->mRegion = Region; pProj->mRegion = Region;
pProj->mGameID = rkGameID; pProj->mGameID = rkGameID;
@ -204,15 +193,15 @@ CGameProject* CGameProject::CreateProjectForExport(
pProj->mProjectRoot = rkProjRootDir; pProj->mProjectRoot = rkProjRootDir;
pProj->mProjectRoot.Replace("\\", "/"); pProj->mProjectRoot.Replace("\\", "/");
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj); pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
pProj->mpGameInfo->LoadGameInfo(Game); pProj->mpGameInfo->LoadGameInfo(Game);
return pProj; return pProj;
} }
CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress) std::unique_ptr<CGameProject> CGameProject::LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress)
{ {
// Init project // Init project
CGameProject *pProj = new CGameProject; auto pProj = std::unique_ptr<CGameProject>(new CGameProject());
pProj->mProjectRoot = rkProjPath.GetFileDirectory(); pProj->mProjectRoot = rkProjPath.GetFileDirectory();
pProj->mProjectRoot.Replace("\\", "/"); pProj->mProjectRoot.Replace("\\", "/");
@ -228,7 +217,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
if (!Reader.IsValid()) if (!Reader.IsValid())
{ {
delete pProj;
return nullptr; return nullptr;
} }
@ -238,7 +226,7 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
{ {
// Load resource database // Load resource database
pProgress->Report("Loading resource database"); pProgress->Report("Loading resource database");
pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj); pProj->mpResourceStore = std::make_unique<CResourceStore>(pProj.get());
LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache(); LoadSuccess = pProj->mpResourceStore->LoadDatabaseCache();
// Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long // Removed database validation step. We used to do this on project load to make sure all data was correct, but this takes a long
@ -270,7 +258,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
if (!LoadSuccess) if (!LoadSuccess)
{ {
delete pProj;
return nullptr; return nullptr;
} }

View File

@ -13,6 +13,7 @@
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/TString.h> #include <Common/TString.h>
#include <Common/FileIO/CFileLock.h> #include <Common/FileIO/CFileLock.h>
#include <memory>
namespace nod { class DiscWii; } namespace nod { class DiscWii; }
@ -23,41 +24,30 @@ enum class EProjectVersion
// Add new versions before this line // Add new versions before this line
Max, Max,
Current = EProjectVersion::Max - 1 Current = Max - 1
}; };
class CGameProject class CGameProject
{ {
TString mProjectName; TString mProjectName{"Unnamed Project"};
EGame mGame; EGame mGame{EGame::Invalid};
ERegion mRegion; ERegion mRegion{ERegion::Unknown};
TString mGameID; TString mGameID{"000000"};
float mBuildVersion; float mBuildVersion = 0.f;
TString mProjectRoot; TString mProjectRoot;
std::vector<CPackage*> mPackages; std::vector<std::unique_ptr<CPackage>> mPackages;
std::unique_ptr<CResourceStore> mpResourceStore; std::unique_ptr<CResourceStore> mpResourceStore;
std::unique_ptr<CGameInfo> mpGameInfo; std::unique_ptr<CGameInfo> mpGameInfo = std::make_unique<CGameInfo>();
std::unique_ptr<CAudioManager> mpAudioManager; std::unique_ptr<CAudioManager> mpAudioManager = std::make_unique<CAudioManager>(this);
std::unique_ptr<CTweakManager> mpTweakManager; std::unique_ptr<CTweakManager> mpTweakManager = std::make_unique<CTweakManager>(this);
// Keep file handle open for the .prj file to prevent users from opening the same project // Keep file handle open for the .prj file to prevent users from opening the same project
// in multiple instances of PWE // in multiple instances of PWE
CFileLock mProjFileLock; CFileLock mProjFileLock;
// Private Constructor // Private Constructor
CGameProject() CGameProject() = default;
: mProjectName("Unnamed Project")
, mGame(EGame::Invalid)
, mRegion(ERegion::Unknown)
, mGameID("000000")
, mBuildVersion(0.f)
, mpResourceStore(nullptr)
{
mpGameInfo = std::make_unique<CGameInfo>();
mpAudioManager = std::make_unique<CAudioManager>(this);
mpTweakManager = std::make_unique<CTweakManager>(this);
}
public: public:
~CGameProject(); ~CGameProject();
@ -71,7 +61,7 @@ public:
CPackage* FindPackage(const TString& rkName) const; CPackage* FindPackage(const TString& rkName) const;
// Static // Static
static CGameProject* CreateProjectForExport( static std::unique_ptr<CGameProject> CreateProjectForExport(
const TString& rkProjRootDir, const TString& rkProjRootDir,
EGame Game, EGame Game,
ERegion Region, ERegion Region,
@ -79,7 +69,7 @@ public:
float BuildVer float BuildVer
); );
static CGameProject* LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress); static std::unique_ptr<CGameProject> LoadProject(const TString& rkProjPath, IProgressNotifier *pProgress);
// Directory Handling // Directory Handling
TString ProjectRoot() const { return mProjectRoot; } TString ProjectRoot() const { return mProjectRoot; }
@ -97,8 +87,8 @@ public:
TString Name() const { return mProjectName; } TString Name() const { return mProjectName; }
uint32 NumPackages() const { return mPackages.size(); } uint32 NumPackages() const { return mPackages.size(); }
CPackage* PackageByIndex(uint32 Index) const { return mPackages[Index]; } CPackage* PackageByIndex(uint32 Index) const { return mPackages[Index].get(); }
void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); } void AddPackage(std::unique_ptr<CPackage>&& package) { mPackages.push_back(std::move(package)); }
CResourceStore* ResourceStore() const { return mpResourceStore.get(); } CResourceStore* ResourceStore() const { return mpResourceStore.get(); }
CGameInfo* GameInfo() const { return mpGameInfo.get(); } CGameInfo* GameInfo() const { return mpGameInfo.get(); }
CAudioManager* AudioManager() const { return mpAudioManager.get(); } CAudioManager* AudioManager() const { return mpAudioManager.get(); }

View File

@ -77,11 +77,8 @@ bool CEditorApplication::CloseProject()
NDolphinIntegration::KillQuickplay(); NDolphinIntegration::KillQuickplay();
// Emit before actually deleting the project to allow editor references to clean up // Emit before actually deleting the project to allow editor references to clean up
CGameProject *pOldProj = mpActiveProject; auto pOldProj = std::move(mpActiveProject);
mpActiveProject = nullptr;
emit ActiveProjectChanged(nullptr); emit ActiveProjectChanged(nullptr);
delete pOldProj;
return true; return true;
} }
@ -96,14 +93,15 @@ bool CEditorApplication::OpenProject(const QString& rkProjPath)
CProgressDialog Dialog("Opening " + TO_QSTRING(Path.GetFileName()), true, true, mpWorldEditor); CProgressDialog Dialog("Opening " + TO_QSTRING(Path.GetFileName()), true, true, mpWorldEditor);
Dialog.DisallowCanceling(); Dialog.DisallowCanceling();
QFuture<CGameProject*> Future = QtConcurrent::run(&CGameProject::LoadProject, Path, &Dialog); // Gross, but necessary until QtConcurrent supports move only types.
mpActiveProject = Dialog.WaitForResults(Future); QFuture<CGameProject*> Future = QtConcurrent::run([](const auto& path, auto* dialog) { return CGameProject::LoadProject(path, dialog).release(); }, Path, &Dialog);
mpActiveProject = std::unique_ptr<CGameProject>(Dialog.WaitForResults(Future));
Dialog.close(); Dialog.close();
if (mpActiveProject) if (mpActiveProject)
{ {
gpResourceStore = mpActiveProject->ResourceStore(); gpResourceStore = mpActiveProject->ResourceStore();
emit ActiveProjectChanged(mpActiveProject); emit ActiveProjectChanged(mpActiveProject.get());
return true; return true;
} }
else else
@ -277,9 +275,8 @@ bool CEditorApplication::RebuildResourceDatabase()
if (mpActiveProject && CloseAllEditors()) if (mpActiveProject && CloseAllEditors())
{ {
// Fake-close the project, but keep it in memory so we can modify the resource store // Fake-close the project, but keep it in memory so we can modify the resource store
CGameProject *pProj = mpActiveProject; auto pProj = std::move(mpActiveProject);
mpActiveProject->TweakManager()->ClearTweaks(); mpActiveProject->TweakManager()->ClearTweaks();
mpActiveProject = nullptr;
emit ActiveProjectChanged(nullptr); emit ActiveProjectChanged(nullptr);
// Rebuild // Rebuild
@ -292,9 +289,9 @@ bool CEditorApplication::RebuildResourceDatabase()
Dialog.close(); Dialog.close();
// Set project to active again // Set project to active again
mpActiveProject = pProj; mpActiveProject = std::move(pProj);
mpActiveProject->TweakManager()->LoadTweaks(); mpActiveProject->TweakManager()->LoadTweaks();
emit ActiveProjectChanged(pProj); emit ActiveProjectChanged(mpActiveProject.get());
UICommon::InfoMsg(mpWorldEditor, "Success", "Resource database rebuilt successfully!"); UICommon::InfoMsg(mpWorldEditor, "Success", "Resource database rebuilt successfully!");
return true; return true;

View File

@ -5,6 +5,7 @@
#include <QApplication> #include <QApplication>
#include <QTimer> #include <QTimer>
#include <QVector> #include <QVector>
#include <memory>
class CBasicViewport; class CBasicViewport;
class CProjectSettingsDialog; class CProjectSettingsDialog;
@ -19,7 +20,7 @@ class CEditorApplication : public QApplication
{ {
Q_OBJECT Q_OBJECT
CGameProject *mpActiveProject; std::unique_ptr<CGameProject> mpActiveProject;
CWorldEditor *mpWorldEditor; CWorldEditor *mpWorldEditor;
CResourceBrowser *mpResourceBrowser; CResourceBrowser *mpResourceBrowser;
CProjectSettingsDialog *mpProjectDialog; CProjectSettingsDialog *mpProjectDialog;
@ -47,16 +48,16 @@ public:
bool RebuildResourceDatabase(); bool RebuildResourceDatabase();
inline CResourceBrowser* ResourceBrowser() const { return mpResourceBrowser; } CResourceBrowser* ResourceBrowser() const { return mpResourceBrowser; }
// Accessors // Accessors
inline CGameProject* ActiveProject() const { return mpActiveProject; } CGameProject* ActiveProject() const { return mpActiveProject.get(); }
inline CWorldEditor* WorldEditor() const { return mpWorldEditor; } CWorldEditor* WorldEditor() const { return mpWorldEditor; }
inline CProjectSettingsDialog* ProjectDialog() const { return mpProjectDialog; } CProjectSettingsDialog* ProjectDialog() const { return mpProjectDialog; }
inline EGame CurrentGame() const { return mpActiveProject ? mpActiveProject->Game() : EGame::Invalid; } EGame CurrentGame() const { return mpActiveProject ? mpActiveProject->Game() : EGame::Invalid; }
inline void SetEditorTicksEnabled(bool Enabled) { Enabled ? mRefreshTimer.start(gkTickFrequencyMS) : mRefreshTimer.stop(); } void SetEditorTicksEnabled(bool Enabled) { Enabled ? mRefreshTimer.start(gkTickFrequencyMS) : mRefreshTimer.stop(); }
inline bool AreEditorTicksEnabled() const { return mRefreshTimer.isActive(); } bool AreEditorTicksEnabled() const { return mRefreshTimer.isActive(); }
public slots: public slots:
void AddEditor(IEditor *pEditor); void AddEditor(IEditor *pEditor);