mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-17 08:57:09 +00:00
Added support for tracking AGSC dependencies
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "CDependencyTree.h"
|
||||
#include "Core/GameProject/CGameProject.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptLayer.h"
|
||||
#include "Core/Resource/Script/CScriptObject.h"
|
||||
@@ -120,6 +121,22 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
|
||||
if (Type == eStructProperty || Type == eArrayProperty)
|
||||
ParseStructDependencies(pInst, static_cast<CPropertyStruct*>(pProp));
|
||||
|
||||
else if (Type == eSoundProperty)
|
||||
{
|
||||
u32 SoundID = static_cast<TSoundProperty*>(pProp)->Get();
|
||||
|
||||
if (SoundID != -1)
|
||||
{
|
||||
SSoundInfo Info = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID);
|
||||
|
||||
if (Info.pAudioGroup)
|
||||
{
|
||||
CPropertyDependency *pDep = new CPropertyDependency(pProp->IDString(true), Info.pAudioGroup->ID());
|
||||
pInst->mChildren.push_back(pDep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if (Type == eAssetProperty)
|
||||
{
|
||||
CAssetID ID = static_cast<TAssetProperty*>(pProp)->Get();
|
||||
|
||||
@@ -19,11 +19,12 @@
|
||||
|
||||
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
|
||||
{
|
||||
mGame = eUnknownGame;
|
||||
mGameDir = FileUtil::MakeAbsolute(rkInputDir);
|
||||
mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
|
||||
|
||||
mpProject = new CGameProject(mExportDir);
|
||||
mDiscDir = mpProject->DiscDir(true);
|
||||
mDiscDir = L"Disc\\";
|
||||
mWorldsDirName = L"Worlds\\";
|
||||
}
|
||||
|
||||
@@ -38,12 +39,18 @@ bool CGameExporter::Export()
|
||||
FileUtil::CreateDirectory(mExportDir);
|
||||
FileUtil::ClearDirectory(mExportDir);
|
||||
|
||||
// Initial analyze/copy of disc data
|
||||
CopyDiscData();
|
||||
mpStore = new CResourceStore(this, L"Content\\", L"Cooked\\", mpProject->Game());
|
||||
mpStore->SetProject(mpProject);
|
||||
|
||||
// Create project
|
||||
mpProject = new CGameProject(this, mExportDir, mGame);
|
||||
mpProject->SetProjectName(CMasterTemplate::FindGameName(mGame));
|
||||
mpProject->SetActive();
|
||||
mpStore = mpProject->ResourceStore();
|
||||
mContentDir = mpStore->RawDir(false);
|
||||
mCookedDir = mpStore->CookedDir(false);
|
||||
|
||||
// Export game data
|
||||
CResourceStore *pOldStore = gpResourceStore;
|
||||
gpResourceStore = mpStore;
|
||||
|
||||
@@ -51,10 +58,12 @@ bool CGameExporter::Export()
|
||||
LoadPaks();
|
||||
ExportWorlds();
|
||||
ExportCookedResources();
|
||||
mpProject->AudioManager()->LoadAssets();
|
||||
ExportResourceEditorData();
|
||||
|
||||
// Export finished!
|
||||
delete mpProject;
|
||||
gpResourceStore = pOldStore;
|
||||
delete mpStore;
|
||||
mpStore = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -89,16 +98,16 @@ void CGameExporter::CopyDiscData()
|
||||
continue;
|
||||
|
||||
// Hack to determine game
|
||||
if (Game() == eUnknownGame)
|
||||
if (mGame == eUnknownGame)
|
||||
{
|
||||
TWideString Name = FullPath.GetFileName(false);
|
||||
if (Name == L"MetroidCWP") SetGame(ePrimeDemo);
|
||||
else if (Name == L"NESemu") SetGame(ePrime);
|
||||
else if (Name == L"PirateGun") SetGame(eEchoesDemo);
|
||||
else if (Name == L"AtomicBeta") SetGame(eEchoes);
|
||||
else if (Name == L"InGameAudio") SetGame(eCorruptionProto);
|
||||
else if (Name == L"GuiDVD") SetGame(eCorruption);
|
||||
else if (Name == L"PreloadData") SetGame(eReturns);
|
||||
if (Name == L"MetroidCWP") mGame = ePrimeDemo;
|
||||
else if (Name == L"NESemu") mGame = ePrime;
|
||||
else if (Name == L"PirateGun") mGame = eEchoesDemo;
|
||||
else if (Name == L"AtomicBeta") mGame = eEchoes;
|
||||
else if (Name == L"InGameAudio") mGame = eCorruptionProto;
|
||||
else if (Name == L"GuiDVD") mGame = eCorruption;
|
||||
else if (Name == L"PreloadData") mGame = eReturns;
|
||||
}
|
||||
|
||||
// Detect paks
|
||||
@@ -116,9 +125,7 @@ void CGameExporter::CopyDiscData()
|
||||
#endif
|
||||
}
|
||||
|
||||
ASSERT(Game() != eUnknownGame);
|
||||
mpProject->SetGame(Game());
|
||||
mpProject->SetProjectName(CMasterTemplate::FindGameName(Game()));
|
||||
ASSERT(mGame != eUnknownGame);
|
||||
}
|
||||
|
||||
void CGameExporter::LoadAssetList()
|
||||
@@ -128,7 +135,7 @@ void CGameExporter::LoadAssetList()
|
||||
// Determine the asset list to use
|
||||
TString ListFile = "../resources/list/AssetList";
|
||||
|
||||
switch (Game())
|
||||
switch (mGame)
|
||||
{
|
||||
case ePrimeDemo: ListFile += "MP1Demo"; break;
|
||||
case ePrime: ListFile += "MP1"; break;
|
||||
@@ -177,7 +184,6 @@ void CGameExporter::LoadPaks()
|
||||
{
|
||||
#if LOAD_PAKS
|
||||
SCOPED_TIMER(LoadPaks);
|
||||
EIDLength IDLength = (Game() < eCorruptionProto ? e32Bit : e64Bit);
|
||||
|
||||
for (auto It = mPaks.begin(); It != mPaks.end(); It++)
|
||||
{
|
||||
@@ -196,7 +202,7 @@ void CGameExporter::LoadPaks()
|
||||
CResourceCollection *pCollection = pPackage->AddCollection("Default");
|
||||
|
||||
// MP1-MP3Proto
|
||||
if (Game() < eCorruption)
|
||||
if (mGame < eCorruption)
|
||||
{
|
||||
u32 PakVersion = Pak.ReadLong();
|
||||
Pak.Seek(0x4, SEEK_CUR);
|
||||
@@ -211,7 +217,7 @@ void CGameExporter::LoadPaks()
|
||||
for (u32 iName = 0; iName < NumNamedResources; iName++)
|
||||
{
|
||||
CFourCC ResType = Pak.ReadLong();
|
||||
CAssetID ResID(Pak, IDLength);
|
||||
CAssetID ResID(Pak, mGame);
|
||||
u32 NameLen = Pak.ReadLong();
|
||||
TString Name = Pak.ReadString(NameLen);
|
||||
pCollection->AddResource(Name, ResID, ResType);
|
||||
@@ -228,7 +234,7 @@ void CGameExporter::LoadPaks()
|
||||
{
|
||||
bool Compressed = (Pak.ReadLong() == 1);
|
||||
CFourCC ResType = Pak.ReadLong();
|
||||
CAssetID ResID(Pak, IDLength);
|
||||
CAssetID ResID(Pak, mGame);
|
||||
u32 ResSize = Pak.ReadLong();
|
||||
u32 ResOffset = Pak.ReadLong();
|
||||
|
||||
@@ -288,7 +294,7 @@ void CGameExporter::LoadPaks()
|
||||
{
|
||||
TString Name = Pak.ReadString();
|
||||
CFourCC ResType = Pak.ReadLong();
|
||||
CAssetID ResID(Pak, IDLength);
|
||||
CAssetID ResID(Pak, mGame);
|
||||
pCollection->AddResource(Name, ResID, ResType);
|
||||
SetResourcePath(ResID, PakName + L"\\", Name.ToUTF16());
|
||||
}
|
||||
@@ -308,7 +314,7 @@ void CGameExporter::LoadPaks()
|
||||
{
|
||||
bool Compressed = (Pak.ReadLong() == 1);
|
||||
CFourCC Type = Pak.ReadLong();
|
||||
CAssetID ResID(Pak, IDLength);
|
||||
CAssetID ResID(Pak, mGame);
|
||||
u32 Size = Pak.ReadLong();
|
||||
u32 Offset = DataStart + Pak.ReadLong();
|
||||
|
||||
@@ -316,7 +322,7 @@ void CGameExporter::LoadPaks()
|
||||
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
|
||||
|
||||
// Check for duplicate resources (unnecessary for DKCR)
|
||||
if (Game() != eReturns)
|
||||
if (mGame != eReturns)
|
||||
{
|
||||
if (Type == "MREA")
|
||||
{
|
||||
@@ -357,9 +363,9 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
|
||||
// Handle compression
|
||||
if (rkResource.Compressed)
|
||||
{
|
||||
bool ZlibCompressed = (Game() <= eEchoesDemo || Game() == eReturns);
|
||||
bool ZlibCompressed = (mGame <= eEchoesDemo || mGame == eReturns);
|
||||
|
||||
if (Game() <= eCorruptionProto)
|
||||
if (mGame <= eCorruptionProto)
|
||||
{
|
||||
std::vector<u8> CompressedData(rkResource.PakSize);
|
||||
|
||||
@@ -539,6 +545,10 @@ void CGameExporter::ExportCookedResources()
|
||||
#endif
|
||||
mpProject->Save();
|
||||
}
|
||||
}
|
||||
|
||||
void CGameExporter::ExportResourceEditorData()
|
||||
{
|
||||
{
|
||||
// Save raw versions of resources + resource cache data files
|
||||
// Note this has to be done after all cooked resources are exported
|
||||
|
||||
@@ -14,6 +14,7 @@ class CGameExporter
|
||||
// Project
|
||||
CGameProject *mpProject;
|
||||
CResourceStore *mpStore;
|
||||
EGame mGame;
|
||||
|
||||
// Directories
|
||||
TWideString mGameDir;
|
||||
@@ -59,6 +60,7 @@ protected:
|
||||
void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer);
|
||||
void ExportWorlds();
|
||||
void ExportCookedResources();
|
||||
void ExportResourceEditorData();
|
||||
void ExportResource(SResourceInstance& rRes);
|
||||
|
||||
// Convenience Functions
|
||||
@@ -80,9 +82,6 @@ protected:
|
||||
{
|
||||
mResourcePaths[rkID] = SResourcePath { rkDir, rkName };
|
||||
}
|
||||
|
||||
inline EGame Game() const { return mpProject->Game(); }
|
||||
inline void SetGame(EGame Game) { mpProject->SetGame(Game); }
|
||||
};
|
||||
|
||||
#endif // CGAMEEXPORTER_H
|
||||
|
||||
@@ -8,6 +8,9 @@ CGameProject::~CGameProject()
|
||||
{
|
||||
if (IsActive())
|
||||
mspActiveProject = nullptr;
|
||||
|
||||
delete mpAudioManager;
|
||||
delete mpResourceStore;
|
||||
}
|
||||
|
||||
bool CGameProject::Load(const TWideString& rkPath)
|
||||
@@ -20,7 +23,7 @@ bool CGameProject::Load(const TWideString& rkPath)
|
||||
Serialize(Reader);
|
||||
|
||||
mpResourceStore->LoadResourceDatabase();
|
||||
mAudioManager.LoadAssets();
|
||||
mpAudioManager->LoadAssets();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "CPackage.h"
|
||||
#include "CResourceStore.h"
|
||||
#include "Core/CAudioManager.h"
|
||||
#include "Core/Resource/Script/CMasterTemplate.h"
|
||||
#include <Common/CAssetID.h>
|
||||
#include <Common/EGame.h>
|
||||
#include <Common/FileUtil.h>
|
||||
@@ -18,7 +19,7 @@ class CGameProject
|
||||
TWideString mResourceDBPath;
|
||||
std::vector<CPackage*> mPackages;
|
||||
CResourceStore *mpResourceStore;
|
||||
CAudioManager mAudioManager;
|
||||
CAudioManager *mpAudioManager;
|
||||
|
||||
enum EProjectVersion
|
||||
{
|
||||
@@ -34,9 +35,10 @@ public:
|
||||
CGameProject()
|
||||
: mGame(eUnknownGame)
|
||||
, mProjectName("Unnamed Project")
|
||||
, mAudioManager(this)
|
||||
, mResourceDBPath(L"ResourceDB.rdb")
|
||||
{
|
||||
mpResourceStore = new CResourceStore(this);
|
||||
mpAudioManager = new CAudioManager(this);
|
||||
}
|
||||
|
||||
CGameProject(const TWideString& rkProjRootDir)
|
||||
@@ -44,9 +46,20 @@ public:
|
||||
, mProjectName("Unnamed Project")
|
||||
, mProjectRoot(rkProjRootDir)
|
||||
, mResourceDBPath(L"ResourceDB.rdb")
|
||||
, mAudioManager(this)
|
||||
{
|
||||
mpResourceStore = new CResourceStore(this);
|
||||
mpAudioManager = new CAudioManager(this);
|
||||
mProjectRoot.Replace(L"/", L"\\");
|
||||
}
|
||||
|
||||
CGameProject(CGameExporter *pExporter, const TWideString& rkProjRootDir, EGame Game)
|
||||
: mGame(Game)
|
||||
, mProjectName(CMasterTemplate::FindGameName(Game))
|
||||
, mProjectRoot(rkProjRootDir)
|
||||
, mResourceDBPath(L"ResourceDB.rdb")
|
||||
{
|
||||
mpResourceStore = new CResourceStore(this, pExporter, L"Content\\", L"Cooked\\", Game);
|
||||
mpAudioManager = new CAudioManager(this);
|
||||
mProjectRoot.Replace(L"/", L"\\");
|
||||
}
|
||||
|
||||
@@ -69,14 +82,13 @@ public:
|
||||
inline TWideString ResourceCachePath(bool Relative) const { return ResourceDBPath(Relative).GetFileDirectory() + L"ResourceCacheData.rcd"; }
|
||||
|
||||
// Accessors
|
||||
inline void SetGame(EGame Game) { mGame = Game; }
|
||||
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; }
|
||||
|
||||
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 CAudioManager* AudioManager() { return &mAudioManager; }
|
||||
inline CAudioManager* AudioManager() const { return mpAudioManager; }
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline bool IsActive() const { return mspActiveProject == this; }
|
||||
|
||||
|
||||
@@ -16,8 +16,9 @@ CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
|
||||
, mpStore(pStore)
|
||||
, mpDependencies(nullptr)
|
||||
, mID(rkID)
|
||||
, mName(rkFilename)
|
||||
, mType(Type)
|
||||
, mpDirectory(nullptr)
|
||||
, mName(rkFilename)
|
||||
, mCachedSize(-1)
|
||||
, mCachedUppercaseName(rkFilename.ToUpper())
|
||||
{
|
||||
|
||||
@@ -24,13 +24,14 @@ CResourceStore::CResourceStore(const TWideString& rkDatabasePath)
|
||||
mDatabaseName = rkDatabasePath.GetFileName();
|
||||
}
|
||||
|
||||
CResourceStore::CResourceStore(CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game)
|
||||
CResourceStore::CResourceStore(CGameProject *pProject, CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game)
|
||||
: mpProj(nullptr)
|
||||
, mGame(Game)
|
||||
, mRawDir(rkRawDir)
|
||||
, mCookedDir(rkCookedDir)
|
||||
, mpExporter(pExporter)
|
||||
{
|
||||
SetProject(pProject);
|
||||
}
|
||||
|
||||
CResourceStore::CResourceStore(CGameProject *pProject)
|
||||
|
||||
@@ -46,7 +46,7 @@ class CResourceStore
|
||||
|
||||
public:
|
||||
CResourceStore(const TWideString& rkDatabasePath);
|
||||
CResourceStore(CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game);
|
||||
CResourceStore(CGameProject *pProject, CGameExporter *pExporter, const TWideString& rkRawDir, const TWideString& rkCookedDir, EGame Game);
|
||||
CResourceStore(CGameProject *pProject);
|
||||
~CResourceStore();
|
||||
void SerializeResourceDatabase(IArchive& rArc);
|
||||
|
||||
@@ -273,14 +273,13 @@ void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurE
|
||||
for (u32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
|
||||
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
|
||||
|
||||
|
||||
if (Type == eDNT_ScriptInstance)
|
||||
mIsPlayerActor = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CAreaDependencyListBuilder ************
|
||||
void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut)
|
||||
void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut, std::set<CAssetID> *pAudioGroupsOut)
|
||||
{
|
||||
CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
|
||||
|
||||
@@ -331,7 +330,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||
continue;
|
||||
}
|
||||
|
||||
AddDependency(pDep->ID(), rAssetsOut);
|
||||
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,24 +343,27 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
|
||||
for (u32 iDep = 0; iDep < BaseEndIndex; iDep++)
|
||||
{
|
||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||
AddDependency(pDep->ID(), rAssetsOut);
|
||||
AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut);
|
||||
}
|
||||
}
|
||||
|
||||
void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut)
|
||||
void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut)
|
||||
{
|
||||
CResourceEntry *pEntry = gpResourceStore->FindEntry(rkID);
|
||||
if (!pEntry) return;
|
||||
|
||||
EResType ResType = pEntry->ResourceType();
|
||||
|
||||
// Check if this is a valid dependency
|
||||
bool IsValid = ResType != eMidi &&
|
||||
ResType != eWorld &&
|
||||
ResType != eArea &&
|
||||
(ResType != eAudioGroup || mGame >= eEchoesDemo);
|
||||
// If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
|
||||
if (mGame <= ePrime && ResType == eAudioGroup)
|
||||
{
|
||||
if (pAudioGroupsOut) pAudioGroupsOut->insert(rkID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsValid) return;
|
||||
// Check to ensure this is a valid/new dependency
|
||||
if (ResType == eWorld || ResType == eArea)
|
||||
return;
|
||||
|
||||
if (mBaseUsedAssets.find(rkID) != mBaseUsedAssets.end() || mLayerUsedAssets.find(rkID) != mLayerUsedAssets.end())
|
||||
return;
|
||||
@@ -378,7 +380,7 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
||||
{
|
||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
||||
AddDependency(pDep->ID(), rOut);
|
||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||
}
|
||||
|
||||
for (u32 iChar = 0; iChar < pTree->NumCharacters(); iChar++)
|
||||
@@ -395,7 +397,7 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
||||
{
|
||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
||||
AddDependency(pDep->ID(), rOut);
|
||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,9 +411,11 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
|
||||
{
|
||||
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
|
||||
ASSERT(pDep->Type() == eDNT_ResourceDependency);
|
||||
AddDependency(pDep->ID(), rOut);
|
||||
AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
|
||||
}
|
||||
}
|
||||
|
||||
rOut.push_back(rkID);
|
||||
// Don't add CSNGs to the output dependency list (we parse them because we need their AGSC dependencies in the output AudioGroup set)
|
||||
if (ResType != eMidi)
|
||||
rOut.push_back(rkID);
|
||||
}
|
||||
|
||||
@@ -72,8 +72,8 @@ public:
|
||||
ASSERT(mpAreaEntry->ResourceType() == eArea);
|
||||
}
|
||||
|
||||
void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut);
|
||||
void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut);
|
||||
void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut, std::set<CAssetID> *pAudioGroupsOut = nullptr);
|
||||
void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut);
|
||||
};
|
||||
|
||||
#endif // DEPENDENCYLISTBUILDERS
|
||||
|
||||
Reference in New Issue
Block a user