diff --git a/src/Core/GameProject/AssetNameGeneration.cpp b/src/Core/GameProject/AssetNameGeneration.cpp index 3419df3b..629869e2 100644 --- a/src/Core/GameProject/AssetNameGeneration.cpp +++ b/src/Core/GameProject/AssetNameGeneration.cpp @@ -122,18 +122,13 @@ void GenerateAssetNames(CGameProject *pProj) { CPackage *pPkg = pProj->PackageByIndex(iPkg); - for (u32 iCol = 0; iCol < pPkg->NumCollections(); iCol++) + for (u32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) { - CResourceCollection *pCol = pPkg->CollectionByIndex(iCol); + const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); + if (rkRes.Name.EndsWith("NODEPEND")) continue; - for (u32 iRes = 0; iRes < pCol->NumResources(); iRes++) - { - const SNamedResource& rkRes = pCol->ResourceByIndex(iRes); - if (rkRes.Name.EndsWith("NODEPEND")) continue; - - CResourceEntry *pRes = pStore->FindEntry(rkRes.ID); - ApplyGeneratedName(pRes, pPkg->Name().ToUTF16(), rkRes.Name.ToUTF16()); - } + CResourceEntry *pRes = pStore->FindEntry(rkRes.ID); + ApplyGeneratedName(pRes, pPkg->Name().ToUTF16(), rkRes.Name.ToUTF16()); } } #endif diff --git a/src/Core/GameProject/CGameExporter.cpp b/src/Core/GameProject/CGameExporter.cpp index f282fe4a..7f3852f7 100644 --- a/src/Core/GameProject/CGameExporter.cpp +++ b/src/Core/GameProject/CGameExporter.cpp @@ -197,7 +197,6 @@ void CGameExporter::LoadPaks() } CPackage *pPackage = new CPackage(mpProject, CharPak.GetFileName(false), FileUtil::MakeRelative(PakPath.GetFileDirectory(), mExportDir + mDiscDir)); - CResourceCollection *pCollection = pPackage->AddCollection("Default"); // MP1-MP3Proto if (mGame < eCorruption) @@ -218,7 +217,7 @@ void CGameExporter::LoadPaks() CAssetID ResID(Pak, mGame); u32 NameLen = Pak.ReadLong(); TString Name = Pak.ReadString(NameLen); - pCollection->AddResource(Name, ResID, ResType); + pPackage->AddResource(Name, ResID, ResType); } u32 NumResources = Pak.ReadLong(); @@ -292,7 +291,7 @@ void CGameExporter::LoadPaks() TString Name = Pak.ReadString(); CFourCC ResType = Pak.ReadLong(); CAssetID ResID(Pak, mGame); - pCollection->AddResource(Name, ResID, ResType); + pPackage->AddResource(Name, ResID, ResType); } } diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index 9e561ff2..7f918b1e 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -100,17 +100,12 @@ void CGameProject::GetWorldList(std::list& rOut) const { CPackage *pPkg = mPackages[iPkg]; - for (u32 iCol = 0; iCol < pPkg->NumCollections(); iCol++) + for (u32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) { - CResourceCollection *pCol = pPkg->CollectionByIndex(iCol); + const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); - for (u32 iRes = 0; iRes < pCol->NumResources(); iRes++) - { - const SNamedResource& rkRes = pCol->ResourceByIndex(iRes); - - if (rkRes.Type == "MLVL" && !rkRes.Name.EndsWith("NODEPEND")) - rOut.push_back(rkRes.ID); - } + if (rkRes.Type == "MLVL" && !rkRes.Name.EndsWith("NODEPEND")) + rOut.push_back(rkRes.ID); } } } @@ -121,17 +116,12 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const { CPackage *pPkg = mPackages[iPkg]; - for (u32 iCol = 0; iCol < pPkg->NumCollections(); iCol++) + for (u32 iRes = 0; iRes < pPkg->NumNamedResources(); iRes++) { - CResourceCollection *pCol = pPkg->CollectionByIndex(iCol); + const SNamedResource& rkRes = pPkg->NamedResourceByIndex(iRes); - for (u32 iRes = 0; iRes < pCol->NumResources(); iRes++) - { - const SNamedResource& rkRes = pCol->ResourceByIndex(iRes); - - if (rkRes.Name == rkName) - return rkRes.ID; - } + if (rkRes.Name == rkName) + return rkRes.ID; } } diff --git a/src/Core/GameProject/CPackage.cpp b/src/Core/GameProject/CPackage.cpp index 69387d11..fbc8ba79 100644 --- a/src/Core/GameProject/CPackage.cpp +++ b/src/Core/GameProject/CPackage.cpp @@ -18,7 +18,7 @@ bool CPackage::Load() if (Reader.IsValid()) { Serialize(Reader); - UpdateDependencyCache(); + mCacheDirty = true; return true; } else return false; @@ -37,17 +37,26 @@ bool CPackage::Save() void CPackage::Serialize(IArchive& rArc) { rArc << SERIAL("NeedsRecook", mNeedsRecook) - << SERIAL_CONTAINER("Collections", mCollections, "ResourceCollection"); + << SERIAL_CONTAINER("NamedResources", mResources, "Resource"); } -void CPackage::UpdateDependencyCache() +void CPackage::AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType) +{ + mResources.push_back( SNamedResource { rkName, rkID, rkType } ); + mCacheDirty = true; +} + +void CPackage::UpdateDependencyCache() const { CPackageDependencyListBuilder Builder(this); std::list AssetList; Builder.BuildDependencyList(false, AssetList); + mCachedDependencies.clear(); for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++) mCachedDependencies.insert(*Iter); + + mCacheDirty = false; } void CPackage::Cook() @@ -58,17 +67,6 @@ void CPackage::Cook() Builder.BuildDependencyList(true, AssetList); Log::Write(TString::FromInt32(AssetList.size(), 0, 10) + " assets in " + Name() + ".pak"); - // Get named resources - std::list NamedResources; - - for (u32 iCol = 0; iCol < mCollections.size(); iCol++) - { - CResourceCollection *pCol = mCollections[iCol]; - - for (u32 iRes = 0; iRes < pCol->NumResources(); iRes++) - NamedResources.push_back(&pCol->ResourceByIndex(iRes)); - } - // Write new pak TWideString PakPath = CookedPackagePath(false); CFileOutStream Pak(PakPath.ToUTF8().ToStdString(), IOUtil::eBigEndian); @@ -84,15 +82,15 @@ void CPackage::Cook() Pak.WriteLong(0); // Unknown // Named Resources - Pak.WriteLong(NamedResources.size()); + Pak.WriteLong(mResources.size()); - for (auto Iter = NamedResources.begin(); Iter != NamedResources.end(); Iter++) + for (auto Iter = mResources.begin(); Iter != mResources.end(); Iter++) { - const SNamedResource *pkRes = *Iter; - pkRes->Type.Write(Pak); - pkRes->ID.Write(Pak); - Pak.WriteLong(pkRes->Name.Size()); - Pak.WriteString(pkRes->Name.ToStdString(), pkRes->Name.Size()); // Note: Explicitly specifying size means we don't write the terminating 0 + const SNamedResource& rkRes = *Iter; + rkRes.Type.Write(Pak); + rkRes.ID.Write(Pak); + Pak.WriteLong(rkRes.Name.Size()); + Pak.WriteString(rkRes.Name.ToStdString(), rkRes.Name.Size()); // Note: Explicitly specifying size means we don't write the terminating 0 } // Fill in table of contents with junk, write later @@ -290,6 +288,14 @@ void CPackage::CompareOriginalAssetList(const std::list& rkNewList) } } +bool CPackage::ContainsAsset(const CAssetID& rkID) const +{ + if (mCacheDirty) + UpdateDependencyCache(); + + return mCachedDependencies.find(rkID) != mCachedDependencies.end(); +} + TWideString CPackage::DefinitionPath(bool Relative) const { TWideString RelPath = mPakPath + mPakName.ToUTF16() + L".pkd"; @@ -301,30 +307,3 @@ TWideString CPackage::CookedPackagePath(bool Relative) const TWideString RelPath = mPakPath + mPakName.ToUTF16() + L".pak"; return Relative ? RelPath : mpProject->DiscDir(false) + RelPath; } - -CResourceCollection* CPackage::AddCollection(const TString& rkName) -{ - CResourceCollection *pCollection = new CResourceCollection(rkName); - mCollections.push_back(pCollection); - return pCollection; -} - -void CPackage::RemoveCollection(CResourceCollection *pCollection) -{ - for (u32 iCol = 0; iCol < mCollections.size(); iCol++) - { - if (mCollections[iCol] == pCollection) - { - RemoveCollection(iCol); - break; - } - } -} - -void CPackage::RemoveCollection(u32 Index) -{ - ASSERT(Index < mCollections.size()); - auto Iter = mCollections.begin() + Index; - delete *Iter; - mCollections.erase(Iter); -} diff --git a/src/Core/GameProject/CPackage.h b/src/Core/GameProject/CPackage.h index 5e8504e7..2a3f49b4 100644 --- a/src/Core/GameProject/CPackage.h +++ b/src/Core/GameProject/CPackage.h @@ -20,39 +20,18 @@ struct SNamedResource } }; -class CResourceCollection -{ - TString mName; - std::vector mNamedResources; - -public: - CResourceCollection() : mName("UNNAMED") {} - CResourceCollection(const TString& rkName) : mName(rkName) {} - - void Serialize(IArchive& rArc) - { - rArc << SERIAL("Name", mName) << SERIAL_CONTAINER("Resources", mNamedResources, "Resource"); - } - - inline TString Name() const { return mName; } - inline u32 NumResources() const { return mNamedResources.size(); } - inline const SNamedResource& ResourceByIndex(u32 Idx) const { return mNamedResources[Idx]; } - - inline void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType) - { - mNamedResources.push_back( SNamedResource { rkName, rkID, rkType } ); - } -}; - class CPackage { CGameProject *mpProject; TString mPakName; TWideString mPakPath; - std::vector mCollections; - std::set mCachedDependencies; + std::vector mResources; bool mNeedsRecook; + // Cached dependency list; used to figure out if a given resource is in this package + mutable bool mCacheDirty; + mutable std::set mCachedDependencies; + enum EPackageDefinitionVersion { eVer_Initial, @@ -69,31 +48,29 @@ public: , mPakName(rkName) , mPakPath(rkPath) , mNeedsRecook(false) + , mCacheDirty(true) {} bool Load(); bool Save(); void Serialize(IArchive& rArc); - void UpdateDependencyCache(); + void AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType); + void UpdateDependencyCache() const; void Cook(); void CompareOriginalAssetList(const std::list& rkNewList); + bool ContainsAsset(const CAssetID& rkID) const; TWideString DefinitionPath(bool Relative) const; TWideString CookedPackagePath(bool Relative) const; - CResourceCollection* AddCollection(const TString& rkName); - void RemoveCollection(CResourceCollection *pCollection); - void RemoveCollection(u32 Index); - // Accessors - inline TString Name() const { return mPakName; } - inline TWideString Path() const { return mPakPath; } - inline CGameProject* Project() const { return mpProject; } - inline u32 NumCollections() const { return mCollections.size(); } - inline CResourceCollection* CollectionByIndex(u32 Idx) const { return mCollections[Idx]; } - inline bool ContainsAsset(const CAssetID& rkID) const { return mCachedDependencies.find(rkID) != mCachedDependencies.end(); } - inline bool NeedsRecook() const { return mNeedsRecook; } + inline TString Name() const { return mPakName; } + inline TWideString Path() const { return mPakPath; } + inline CGameProject* Project() const { return mpProject; } + inline u32 NumNamedResources() const { return mResources.size(); } + inline const SNamedResource& NamedResourceByIndex(u32 Idx) const { return mResources[Idx]; } + inline bool NeedsRecook() const { return mNeedsRecook; } inline void SetPakName(TString NewName) { mPakName = NewName; } inline void MarkDirty() { mNeedsRecook = true; Save(); UpdateDependencyCache(); } diff --git a/src/Core/GameProject/DependencyListBuilders.cpp b/src/Core/GameProject/DependencyListBuilders.cpp index fa77284a..8d1d071d 100644 --- a/src/Core/GameProject/DependencyListBuilders.cpp +++ b/src/Core/GameProject/DependencyListBuilders.cpp @@ -176,35 +176,30 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st { mEnableDuplicates = AllowDuplicates; - // Iterate over all resource collections and resources and parse their dependencies - for (u32 iCol = 0; iCol < mpPackage->NumCollections(); iCol++) + // Iterate over all resources and parse their dependencies + for (u32 iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++) { - CResourceCollection *pCollection = mpPackage->CollectionByIndex(iCol); + const SNamedResource& rkRes = mpkPackage->NamedResourceByIndex(iRes); + CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID); + if (!pEntry) continue; - for (u32 iRes = 0; iRes < pCollection->NumResources(); iRes++) + if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG") { - const SNamedResource& rkRes = pCollection->ResourceByIndex(iRes); - CResourceEntry *pEntry = mpStore->FindEntry(rkRes.ID); - if (!pEntry) continue; - - if (rkRes.Name.EndsWith("NODEPEND") || rkRes.Type == "CSNG") - { - rOut.push_back(rkRes.ID); - continue; - } - - if (rkRes.Type == "MLVL") - { - mpWorld = (CWorld*) pEntry->Load(); - ASSERT(mpWorld); - } - - else - mCharacterUsageMap.FindUsagesForAsset(pEntry); - - AddDependency(nullptr, rkRes.ID, rOut); - mpWorld = nullptr; + rOut.push_back(rkRes.ID); + continue; } + + if (rkRes.Type == "MLVL") + { + mpWorld = (CWorld*) pEntry->Load(); + ASSERT(mpWorld); + } + + else + mCharacterUsageMap.FindUsagesForAsset(pEntry); + + AddDependency(nullptr, rkRes.ID, rOut); + mpWorld = nullptr; } } diff --git a/src/Core/GameProject/DependencyListBuilders.h b/src/Core/GameProject/DependencyListBuilders.h index 781dbcb0..2a0371f3 100644 --- a/src/Core/GameProject/DependencyListBuilders.h +++ b/src/Core/GameProject/DependencyListBuilders.h @@ -38,7 +38,7 @@ protected: // ************ CPackageDependencyListBuilder ************ class CPackageDependencyListBuilder { - CPackage *mpPackage; + const CPackage *mpkPackage; CResourceStore *mpStore; EGame mGame; TResPtr mpWorld; @@ -51,11 +51,11 @@ class CPackageDependencyListBuilder bool mIsPlayerActor; public: - CPackageDependencyListBuilder(CPackage *pPackage) - : mpPackage(pPackage) - , mGame(pPackage->Project()->Game()) - , mpStore(pPackage->Project()->ResourceStore()) - , mCharacterUsageMap(pPackage->Project()->ResourceStore()) + CPackageDependencyListBuilder(const CPackage *pkPackage) + : mpkPackage(pkPackage) + , mGame(pkPackage->Project()->Game()) + , mpStore(pkPackage->Project()->ResourceStore()) + , mCharacterUsageMap(pkPackage->Project()->ResourceStore()) , mCurrentAreaHasDuplicates(false) , mIsPlayerActor(false) { diff --git a/src/Editor/CProjectOverviewDialog.ui b/src/Editor/CProjectOverviewDialog.ui index 7598281c..7bb0e26e 100644 --- a/src/Editor/CProjectOverviewDialog.ui +++ b/src/Editor/CProjectOverviewDialog.ui @@ -13,131 +13,53 @@ Dialog - - - - - - - - - Open Project - - - - - - - Export Game - - - - - - - - - View Resources - - - - - - - - - - - - - - 2 - 0 - - - - Worlds - - - - - - - - - false - - - Load - - - - - - - - - - - 3 - 0 - - - - Areas - - - - - - false - - - - - - - false - - - Launch World Editor - - - - - - - - - - - - Packages - - - - - - - - - Cook Package - - - - - - - Cook All Dirty Packages - - - - - - - - - + + + + 100 + 130 + 280 + 287 + + + + Packages + + + + + + + 10 + + + + true + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + + + + + Cook Package + + + + + + + Cook All Dirty Packages + + + + + diff --git a/src/Editor/WorldEditor/CWorldInfoSidebar.cpp b/src/Editor/WorldEditor/CWorldInfoSidebar.cpp index 77abe949..bc5f078d 100644 --- a/src/Editor/WorldEditor/CWorldInfoSidebar.cpp +++ b/src/Editor/WorldEditor/CWorldInfoSidebar.cpp @@ -18,7 +18,7 @@ CWorldInfoSidebar::CWorldInfoSidebar(CWorldEditor *pEditor) connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(OnActiveProjectChanged(CGameProject*))); connect(mpUI->AreaSearchLineEdit, SIGNAL(StoppedTyping(QString)), this, SLOT(OnAreaFilterStringChanged(QString))); - connect(mpUI->WorldTreeView, SIGNAL(clicked(QModelIndex)), this, SLOT(OnWorldTreeClicked(QModelIndex))); + connect(mpUI->WorldTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnWorldTreeClicked(QModelIndex))); connect(mpUI->WorldTreeView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnWorldTreeDoubleClicked(QModelIndex))); // Set up UI for world/area info; disable editing for now