Added support for tracking AGSC dependencies

This commit is contained in:
parax0 2016-09-16 02:47:46 -06:00
parent 2e1add84be
commit 10c87779b3
15 changed files with 224 additions and 74 deletions

View File

@ -1,4 +1,5 @@
#include "CDependencyTree.h" #include "CDependencyTree.h"
#include "Core/GameProject/CGameProject.h"
#include "Core/Resource/Script/CMasterTemplate.h" #include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptLayer.h"
#include "Core/Resource/Script/CScriptObject.h" #include "Core/Resource/Script/CScriptObject.h"
@ -120,6 +121,22 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
if (Type == eStructProperty || Type == eArrayProperty) if (Type == eStructProperty || Type == eArrayProperty)
ParseStructDependencies(pInst, static_cast<CPropertyStruct*>(pProp)); 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) else if (Type == eAssetProperty)
{ {
CAssetID ID = static_cast<TAssetProperty*>(pProp)->Get(); CAssetID ID = static_cast<TAssetProperty*>(pProp)->Get();

View File

@ -19,11 +19,12 @@
CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir) CGameExporter::CGameExporter(const TString& rkInputDir, const TString& rkOutputDir)
{ {
mGame = eUnknownGame;
mGameDir = FileUtil::MakeAbsolute(rkInputDir); mGameDir = FileUtil::MakeAbsolute(rkInputDir);
mExportDir = FileUtil::MakeAbsolute(rkOutputDir); mExportDir = FileUtil::MakeAbsolute(rkOutputDir);
mpProject = new CGameProject(mExportDir); mpProject = new CGameProject(mExportDir);
mDiscDir = mpProject->DiscDir(true); mDiscDir = L"Disc\\";
mWorldsDirName = L"Worlds\\"; mWorldsDirName = L"Worlds\\";
} }
@ -38,12 +39,18 @@ bool CGameExporter::Export()
FileUtil::CreateDirectory(mExportDir); FileUtil::CreateDirectory(mExportDir);
FileUtil::ClearDirectory(mExportDir); FileUtil::ClearDirectory(mExportDir);
// Initial analyze/copy of disc data
CopyDiscData(); 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); mContentDir = mpStore->RawDir(false);
mCookedDir = mpStore->CookedDir(false); mCookedDir = mpStore->CookedDir(false);
// Export game data
CResourceStore *pOldStore = gpResourceStore; CResourceStore *pOldStore = gpResourceStore;
gpResourceStore = mpStore; gpResourceStore = mpStore;
@ -51,10 +58,12 @@ bool CGameExporter::Export()
LoadPaks(); LoadPaks();
ExportWorlds(); ExportWorlds();
ExportCookedResources(); ExportCookedResources();
mpProject->AudioManager()->LoadAssets();
ExportResourceEditorData();
// Export finished!
delete mpProject;
gpResourceStore = pOldStore; gpResourceStore = pOldStore;
delete mpStore;
mpStore = nullptr;
return true; return true;
} }
@ -89,16 +98,16 @@ void CGameExporter::CopyDiscData()
continue; continue;
// Hack to determine game // Hack to determine game
if (Game() == eUnknownGame) if (mGame == eUnknownGame)
{ {
TWideString Name = FullPath.GetFileName(false); TWideString Name = FullPath.GetFileName(false);
if (Name == L"MetroidCWP") SetGame(ePrimeDemo); if (Name == L"MetroidCWP") mGame = ePrimeDemo;
else if (Name == L"NESemu") SetGame(ePrime); else if (Name == L"NESemu") mGame = ePrime;
else if (Name == L"PirateGun") SetGame(eEchoesDemo); else if (Name == L"PirateGun") mGame = eEchoesDemo;
else if (Name == L"AtomicBeta") SetGame(eEchoes); else if (Name == L"AtomicBeta") mGame = eEchoes;
else if (Name == L"InGameAudio") SetGame(eCorruptionProto); else if (Name == L"InGameAudio") mGame = eCorruptionProto;
else if (Name == L"GuiDVD") SetGame(eCorruption); else if (Name == L"GuiDVD") mGame = eCorruption;
else if (Name == L"PreloadData") SetGame(eReturns); else if (Name == L"PreloadData") mGame = eReturns;
} }
// Detect paks // Detect paks
@ -116,9 +125,7 @@ void CGameExporter::CopyDiscData()
#endif #endif
} }
ASSERT(Game() != eUnknownGame); ASSERT(mGame != eUnknownGame);
mpProject->SetGame(Game());
mpProject->SetProjectName(CMasterTemplate::FindGameName(Game()));
} }
void CGameExporter::LoadAssetList() void CGameExporter::LoadAssetList()
@ -128,7 +135,7 @@ void CGameExporter::LoadAssetList()
// Determine the asset list to use // Determine the asset list to use
TString ListFile = "../resources/list/AssetList"; TString ListFile = "../resources/list/AssetList";
switch (Game()) switch (mGame)
{ {
case ePrimeDemo: ListFile += "MP1Demo"; break; case ePrimeDemo: ListFile += "MP1Demo"; break;
case ePrime: ListFile += "MP1"; break; case ePrime: ListFile += "MP1"; break;
@ -177,7 +184,6 @@ void CGameExporter::LoadPaks()
{ {
#if LOAD_PAKS #if LOAD_PAKS
SCOPED_TIMER(LoadPaks); SCOPED_TIMER(LoadPaks);
EIDLength IDLength = (Game() < eCorruptionProto ? e32Bit : e64Bit);
for (auto It = mPaks.begin(); It != mPaks.end(); It++) for (auto It = mPaks.begin(); It != mPaks.end(); It++)
{ {
@ -196,7 +202,7 @@ void CGameExporter::LoadPaks()
CResourceCollection *pCollection = pPackage->AddCollection("Default"); CResourceCollection *pCollection = pPackage->AddCollection("Default");
// MP1-MP3Proto // MP1-MP3Proto
if (Game() < eCorruption) if (mGame < eCorruption)
{ {
u32 PakVersion = Pak.ReadLong(); u32 PakVersion = Pak.ReadLong();
Pak.Seek(0x4, SEEK_CUR); Pak.Seek(0x4, SEEK_CUR);
@ -211,7 +217,7 @@ void CGameExporter::LoadPaks()
for (u32 iName = 0; iName < NumNamedResources; iName++) for (u32 iName = 0; iName < NumNamedResources; iName++)
{ {
CFourCC ResType = Pak.ReadLong(); CFourCC ResType = Pak.ReadLong();
CAssetID ResID(Pak, IDLength); CAssetID ResID(Pak, mGame);
u32 NameLen = Pak.ReadLong(); u32 NameLen = Pak.ReadLong();
TString Name = Pak.ReadString(NameLen); TString Name = Pak.ReadString(NameLen);
pCollection->AddResource(Name, ResID, ResType); pCollection->AddResource(Name, ResID, ResType);
@ -228,7 +234,7 @@ void CGameExporter::LoadPaks()
{ {
bool Compressed = (Pak.ReadLong() == 1); bool Compressed = (Pak.ReadLong() == 1);
CFourCC ResType = Pak.ReadLong(); CFourCC ResType = Pak.ReadLong();
CAssetID ResID(Pak, IDLength); CAssetID ResID(Pak, mGame);
u32 ResSize = Pak.ReadLong(); u32 ResSize = Pak.ReadLong();
u32 ResOffset = Pak.ReadLong(); u32 ResOffset = Pak.ReadLong();
@ -288,7 +294,7 @@ void CGameExporter::LoadPaks()
{ {
TString Name = Pak.ReadString(); TString Name = Pak.ReadString();
CFourCC ResType = Pak.ReadLong(); CFourCC ResType = Pak.ReadLong();
CAssetID ResID(Pak, IDLength); CAssetID ResID(Pak, mGame);
pCollection->AddResource(Name, ResID, ResType); pCollection->AddResource(Name, ResID, ResType);
SetResourcePath(ResID, PakName + L"\\", Name.ToUTF16()); SetResourcePath(ResID, PakName + L"\\", Name.ToUTF16());
} }
@ -308,7 +314,7 @@ void CGameExporter::LoadPaks()
{ {
bool Compressed = (Pak.ReadLong() == 1); bool Compressed = (Pak.ReadLong() == 1);
CFourCC Type = Pak.ReadLong(); CFourCC Type = Pak.ReadLong();
CAssetID ResID(Pak, IDLength); CAssetID ResID(Pak, mGame);
u32 Size = Pak.ReadLong(); u32 Size = Pak.ReadLong();
u32 Offset = DataStart + Pak.ReadLong(); u32 Offset = DataStart + Pak.ReadLong();
@ -316,7 +322,7 @@ void CGameExporter::LoadPaks()
mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false }; mResourceMap[ResID] = SResourceInstance { PakPath, ResID, Type, Offset, Size, Compressed, false };
// Check for duplicate resources (unnecessary for DKCR) // Check for duplicate resources (unnecessary for DKCR)
if (Game() != eReturns) if (mGame != eReturns)
{ {
if (Type == "MREA") if (Type == "MREA")
{ {
@ -357,9 +363,9 @@ void CGameExporter::LoadResource(const SResourceInstance& rkResource, std::vecto
// Handle compression // Handle compression
if (rkResource.Compressed) 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); std::vector<u8> CompressedData(rkResource.PakSize);
@ -539,6 +545,10 @@ void CGameExporter::ExportCookedResources()
#endif #endif
mpProject->Save(); mpProject->Save();
} }
}
void CGameExporter::ExportResourceEditorData()
{
{ {
// Save raw versions of resources + resource cache data files // Save raw versions of resources + resource cache data files
// Note this has to be done after all cooked resources are exported // Note this has to be done after all cooked resources are exported

View File

@ -14,6 +14,7 @@ class CGameExporter
// Project // Project
CGameProject *mpProject; CGameProject *mpProject;
CResourceStore *mpStore; CResourceStore *mpStore;
EGame mGame;
// Directories // Directories
TWideString mGameDir; TWideString mGameDir;
@ -59,6 +60,7 @@ protected:
void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer); void LoadResource(const SResourceInstance& rkResource, std::vector<u8>& rBuffer);
void ExportWorlds(); void ExportWorlds();
void ExportCookedResources(); void ExportCookedResources();
void ExportResourceEditorData();
void ExportResource(SResourceInstance& rRes); void ExportResource(SResourceInstance& rRes);
// Convenience Functions // Convenience Functions
@ -80,9 +82,6 @@ protected:
{ {
mResourcePaths[rkID] = SResourcePath { rkDir, rkName }; mResourcePaths[rkID] = SResourcePath { rkDir, rkName };
} }
inline EGame Game() const { return mpProject->Game(); }
inline void SetGame(EGame Game) { mpProject->SetGame(Game); }
}; };
#endif // CGAMEEXPORTER_H #endif // CGAMEEXPORTER_H

View File

@ -8,6 +8,9 @@ CGameProject::~CGameProject()
{ {
if (IsActive()) if (IsActive())
mspActiveProject = nullptr; mspActiveProject = nullptr;
delete mpAudioManager;
delete mpResourceStore;
} }
bool CGameProject::Load(const TWideString& rkPath) bool CGameProject::Load(const TWideString& rkPath)
@ -20,7 +23,7 @@ bool CGameProject::Load(const TWideString& rkPath)
Serialize(Reader); Serialize(Reader);
mpResourceStore->LoadResourceDatabase(); mpResourceStore->LoadResourceDatabase();
mAudioManager.LoadAssets(); mpAudioManager->LoadAssets();
return true; return true;
} }

View File

@ -4,6 +4,7 @@
#include "CPackage.h" #include "CPackage.h"
#include "CResourceStore.h" #include "CResourceStore.h"
#include "Core/CAudioManager.h" #include "Core/CAudioManager.h"
#include "Core/Resource/Script/CMasterTemplate.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>
@ -18,7 +19,7 @@ class CGameProject
TWideString mResourceDBPath; TWideString mResourceDBPath;
std::vector<CPackage*> mPackages; std::vector<CPackage*> mPackages;
CResourceStore *mpResourceStore; CResourceStore *mpResourceStore;
CAudioManager mAudioManager; CAudioManager *mpAudioManager;
enum EProjectVersion enum EProjectVersion
{ {
@ -34,9 +35,10 @@ public:
CGameProject() CGameProject()
: mGame(eUnknownGame) : mGame(eUnknownGame)
, mProjectName("Unnamed Project") , mProjectName("Unnamed Project")
, mAudioManager(this) , mResourceDBPath(L"ResourceDB.rdb")
{ {
mpResourceStore = new CResourceStore(this); mpResourceStore = new CResourceStore(this);
mpAudioManager = new CAudioManager(this);
} }
CGameProject(const TWideString& rkProjRootDir) CGameProject(const TWideString& rkProjRootDir)
@ -44,9 +46,20 @@ public:
, mProjectName("Unnamed Project") , mProjectName("Unnamed Project")
, mProjectRoot(rkProjRootDir) , mProjectRoot(rkProjRootDir)
, mResourceDBPath(L"ResourceDB.rdb") , mResourceDBPath(L"ResourceDB.rdb")
, mAudioManager(this)
{ {
mpResourceStore = new CResourceStore(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"\\"); mProjectRoot.Replace(L"/", L"\\");
} }
@ -69,14 +82,13 @@ public:
inline TWideString ResourceCachePath(bool Relative) const { return ResourceDBPath(Relative).GetFileDirectory() + L"ResourceCacheData.rcd"; } inline TWideString ResourceCachePath(bool Relative) const { return ResourceDBPath(Relative).GetFileDirectory() + L"ResourceCacheData.rcd"; }
// Accessors // Accessors
inline void SetGame(EGame Game) { mGame = Game; }
inline void SetProjectName(const TString& rkName) { mProjectName = rkName; } inline void SetProjectName(const TString& rkName) { mProjectName = rkName; }
inline u32 NumPackages() const { return mPackages.size(); } inline u32 NumPackages() const { return mPackages.size(); }
inline CPackage* PackageByIndex(u32 Index) const { return mPackages[Index]; } inline CPackage* PackageByIndex(u32 Index) const { return mPackages[Index]; }
inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); } inline void AddPackage(CPackage *pPackage) { mPackages.push_back(pPackage); }
inline CResourceStore* ResourceStore() const { return mpResourceStore; } inline CResourceStore* ResourceStore() const { return mpResourceStore; }
inline CAudioManager* AudioManager() { return &mAudioManager; } inline CAudioManager* AudioManager() const { return mpAudioManager; }
inline EGame Game() const { return mGame; } inline EGame Game() const { return mGame; }
inline bool IsActive() const { return mspActiveProject == this; } inline bool IsActive() const { return mspActiveProject == this; }

View File

@ -16,8 +16,9 @@ CResourceEntry::CResourceEntry(CResourceStore *pStore, const CAssetID& rkID,
, mpStore(pStore) , mpStore(pStore)
, mpDependencies(nullptr) , mpDependencies(nullptr)
, mID(rkID) , mID(rkID)
, mName(rkFilename)
, mType(Type) , mType(Type)
, mpDirectory(nullptr)
, mName(rkFilename)
, mCachedSize(-1) , mCachedSize(-1)
, mCachedUppercaseName(rkFilename.ToUpper()) , mCachedUppercaseName(rkFilename.ToUpper())
{ {

View File

@ -24,13 +24,14 @@ CResourceStore::CResourceStore(const TWideString& rkDatabasePath)
mDatabaseName = rkDatabasePath.GetFileName(); 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) : mpProj(nullptr)
, mGame(Game) , mGame(Game)
, mRawDir(rkRawDir) , mRawDir(rkRawDir)
, mCookedDir(rkCookedDir) , mCookedDir(rkCookedDir)
, mpExporter(pExporter) , mpExporter(pExporter)
{ {
SetProject(pProject);
} }
CResourceStore::CResourceStore(CGameProject *pProject) CResourceStore::CResourceStore(CGameProject *pProject)

View File

@ -46,7 +46,7 @@ class CResourceStore
public: public:
CResourceStore(const TWideString& rkDatabasePath); 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(CGameProject *pProject);
~CResourceStore(); ~CResourceStore();
void SerializeResourceDatabase(IArchive& rArc); void SerializeResourceDatabase(IArchive& rArc);

View File

@ -273,14 +273,13 @@ void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurE
for (u32 iChild = 0; iChild < pNode->NumChildren(); iChild++) for (u32 iChild = 0; iChild < pNode->NumChildren(); iChild++)
EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut); EvaluateDependencyNode(pCurEntry, pNode->ChildByIndex(iChild), rOut);
if (Type == eDNT_ScriptInstance) if (Type == eDNT_ScriptInstance)
mIsPlayerActor = false; mIsPlayerActor = false;
} }
} }
// ************ CAreaDependencyListBuilder ************ // ************ 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()); CAreaDependencyTree *pTree = static_cast<CAreaDependencyTree*>(mpAreaEntry->Dependencies());
@ -331,7 +330,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list<CAssetID>& rAsset
continue; 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++) for (u32 iDep = 0; iDep < BaseEndIndex; iDep++)
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(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); CResourceEntry *pEntry = gpResourceStore->FindEntry(rkID);
if (!pEntry) return; if (!pEntry) return;
EResType ResType = pEntry->ResourceType(); EResType ResType = pEntry->ResourceType();
// Check if this is a valid dependency // If this is an audio group, for MP1, save it in the output set. For MP2, treat audio groups as a normal dependency.
bool IsValid = ResType != eMidi && if (mGame <= ePrime && ResType == eAudioGroup)
ResType != eWorld && {
ResType != eArea && if (pAudioGroupsOut) pAudioGroupsOut->insert(rkID);
(ResType != eAudioGroup || mGame >= eEchoesDemo); 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()) if (mBaseUsedAssets.find(rkID) != mBaseUsedAssets.end() || mLayerUsedAssets.find(rkID) != mLayerUsedAssets.end())
return; return;
@ -378,7 +380,7 @@ void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list<C
{ {
CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep)); CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
ASSERT(pDep->Type() == eDNT_ResourceDependency); ASSERT(pDep->Type() == eDNT_ResourceDependency);
AddDependency(pDep->ID(), rOut); AddDependency(pDep->ID(), rOut, pAudioGroupsOut);
} }
for (u32 iChar = 0; iChar < pTree->NumCharacters(); iChar++) 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)); CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
ASSERT(pDep->Type() == eDNT_ResourceDependency); 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)); CResourceDependency *pDep = static_cast<CResourceDependency*>(pTree->ChildByIndex(iDep));
ASSERT(pDep->Type() == eDNT_ResourceDependency); 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);
} }

View File

@ -72,8 +72,8 @@ public:
ASSERT(mpAreaEntry->ResourceType() == eArea); ASSERT(mpAreaEntry->ResourceType() == eArea);
} }
void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut); void BuildDependencyList(std::list<CAssetID>& rAssetsOut, std::list<u32>& rLayerOffsetsOut, std::set<CAssetID> *pAudioGroupsOut = nullptr);
void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut); void AddDependency(const CAssetID& rkID, std::list<CAssetID>& rOut, std::set<CAssetID> *pAudioGroupsOut);
}; };
#endif // DEPENDENCYLISTBUILDERS #endif // DEPENDENCYLISTBUILDERS

View File

@ -49,6 +49,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
// Areas // Areas
rMLVL.WriteLong(pWorld->mAreas.size()); rMLVL.WriteLong(pWorld->mAreas.size());
if (Game <= ePrime) rMLVL.WriteLong(1); // Unknown if (Game <= ePrime) rMLVL.WriteLong(1); // Unknown
std::set<CAssetID> AudioGroups;
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++) for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
{ {
@ -79,7 +80,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
std::list<CAssetID> Dependencies; std::list<CAssetID> Dependencies;
std::list<u32> LayerDependsOffsets; std::list<u32> LayerDependsOffsets;
CAreaDependencyListBuilder Builder(pAreaEntry); CAreaDependencyListBuilder Builder(pAreaEntry);
Builder.BuildDependencyList(Dependencies, LayerDependsOffsets); Builder.BuildDependencyList(Dependencies, LayerDependsOffsets, &AudioGroups);
rMLVL.WriteLong(0); rMLVL.WriteLong(0);
rMLVL.WriteLong( Dependencies.size() ); rMLVL.WriteLong( Dependencies.size() );
@ -156,6 +157,59 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
// Audio Groups // Audio Groups
if (Game <= ePrime) if (Game <= ePrime)
{ {
#if 0
// Debug: make sure our generated list matches the original, no missing or extra audio groups
std::set<CAssetID> OriginalGroups;
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
{
CWorld::SAudioGrp& rAudioGroup = pWorld->mAudioGrps[iGrp];
OriginalGroups.insert(rAudioGroup.ResID);
if (AudioGroups.find(rAudioGroup.ResID) == AudioGroups.end())
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(rAudioGroup.ResID);
Log::Error("Missing audio group: " + pEntry->Name().ToUTF8());
}
}
for (auto It = AudioGroups.begin(); It != AudioGroups.end(); It++)
{
if (OriginalGroups.find(*It) == OriginalGroups.end())
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(*It);
Log::Error("Extra audio group: " + pEntry->Name().ToUTF8());
}
}
#endif
#if 0
// Create sorted list of audio groups (sort by group ID)
std::vector<CAudioGroup*> SortedAudioGroups;
for (auto It = AudioGroups.begin(); It != AudioGroups.end(); It++)
{
CAudioGroup *pGroup = (CAudioGroup*) gpResourceStore->LoadResource(*It, "AGSC");
ASSERT(pGroup);
SortedAudioGroups.push_back(pGroup);
}
std::sort(SortedAudioGroups.begin(), SortedAudioGroups.end(), [](CAudioGroup *pLeft, CAudioGroup *pRight) -> bool {
return pLeft->GroupID() < pRight->GroupID();
});
// Write sorted audio group list to file
rMLVL.WriteLong(SortedAudioGroups.size());
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
{
CAudioGroup *pGroup = SortedAudioGroups[iGroup];
rMLVL.WriteLong(pGroup->GroupID());
pGroup->ID().Write(rMLVL);
}
#endif
#if 1
rMLVL.WriteLong(pWorld->mAudioGrps.size()); rMLVL.WriteLong(pWorld->mAudioGrps.size());
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++) for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
@ -164,6 +218,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
rMLVL.WriteLong(rAudioGroup.GroupID); rMLVL.WriteLong(rAudioGroup.GroupID);
rAudioGroup.ResID.Write(rMLVL); rAudioGroup.ResID.Write(rMLVL);
} }
#endif
rMLVL.WriteByte(0); rMLVL.WriteByte(0);
} }

View File

@ -1,4 +1,5 @@
#include "CUnsupportedFormatLoader.h" #include "CUnsupportedFormatLoader.h"
#include "Core/GameProject/CGameProject.h"
#include "Core/Resource/ParticleParameters.h" #include "Core/Resource/ParticleParameters.h"
CDependencyGroup* CUnsupportedFormatLoader::LoadCSNG(IInputStream& rCSNG, CResourceEntry *pEntry) CDependencyGroup* CUnsupportedFormatLoader::LoadCSNG(IInputStream& rCSNG, CResourceEntry *pEntry)
@ -67,8 +68,16 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadEVNT(IInputStream& rEVNT, CResou
{ {
rEVNT.Seek(0x2, SEEK_CUR); rEVNT.Seek(0x2, SEEK_CUR);
rEVNT.ReadString(); rEVNT.ReadString();
rEVNT.Seek(0x27, SEEK_CUR); rEVNT.Seek(0x1B, SEEK_CUR);
u32 SoundID = rEVNT.ReadLong() & 0xFFFF;
rEVNT.Seek(0x8, SEEK_CUR);
if (IsEchoes) rEVNT.Seek(0xC, SEEK_CUR); if (IsEchoes) rEVNT.Seek(0xC, SEEK_CUR);
if (SoundID != 0xFFFF)
{
SSoundInfo SoundInfo = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID);
pGroup->AddDependency(SoundInfo.pAudioGroup);
}
} }
} }

View File

@ -1,4 +1,5 @@
#include "CUnsupportedParticleLoader.h" #include "CUnsupportedParticleLoader.h"
#include <Core/GameProject/CGameProject.h>
// ************ PARAMETER LOADING ************ // ************ PARAMETER LOADING ************
bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART)
@ -462,8 +463,7 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC)
case kWeaponVMD2: case kWeaponVMD2:
ParseBoolFunction(rWPSC); ParseBoolFunction(rWPSC);
break; break;
case kWeaponPJFX:
case kWeaponPSLT: case kWeaponPSLT:
ParseIntFunction(rWPSC); ParseIntFunction(rWPSC);
break; break;
@ -509,6 +509,10 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC)
case kWeaponTTEX: case kWeaponTTEX:
ParseUVFunction(rWPSC); ParseUVFunction(rWPSC);
break; break;
case kWeaponPJFX:
ParseSoundFunction(rWPSC);
break;
case kWeaponAPSM: case kWeaponAPSM:
case kWeaponAPS1: case kWeaponAPS1:
@ -570,26 +574,12 @@ bool CUnsupportedParticleLoader::ParseCollisionResponseParameter(IInputStream& r
case kColi6GRN: case kColi6GRN:
case kColi2MUD: case kColi2MUD:
case kColi2SAN: case kColi2SAN:
case kColiBHFX:
case kColiCHFX:
case kColiCSFX:
case kColiCZFX:
case kColiDCSH: case kColiDCSH:
case kColiDSFX:
case kColiDSHX: case kColiDSHX:
case kColiGOFX:
case kColiGRFX:
case kColiHBFX:
case kColiICFX:
case kColiMSFX:
case kColiPBHX: case kColiPBHX:
case kColiPBOS: case kColiPBOS:
case kColiPBSX: case kColiPBSX:
case kColiSHFX:
case kColiTAFX:
case kColiTASP: case kColiTASP:
case kColiWSFX:
case kColiWTFX:
ParseIntFunction(rCRSC); ParseIntFunction(rCRSC);
break; break;
@ -597,7 +587,24 @@ bool CUnsupportedParticleLoader::ParseCollisionResponseParameter(IInputStream& r
case kColiRNGE: case kColiRNGE:
ParseFloatFunction(rCRSC); ParseFloatFunction(rCRSC);
break; break;
case kColiBHFX:
case kColiCHFX:
case kColiCSFX:
case kColiCZFX:
case kColiDSFX:
case kColiGOFX:
case kColiGRFX:
case kColiHBFX:
case kColiICFX:
case kColiMSFX:
case kColiSHFX:
case kColiTAFX:
case kColiWSFX:
case kColiWTFX:
ParseSoundFunction(rCRSC);
break;
case kColi1LAV: case kColi1LAV:
case kColi3LAV: case kColi3LAV:
case kColi1MUD: case kColi1MUD:
@ -1275,6 +1282,35 @@ void CUnsupportedParticleLoader::ParseEmitterFunction(IInputStream& rFile)
} }
} }
void CUnsupportedParticleLoader::ParseSoundFunction(IInputStream& rFile)
{
u32 FuncOffset = rFile.Tell();
CFourCC Func = rFile.ReadLong();
switch (Func.ToLong())
{
case kFuncNONE:
break;
case kSoundCNST:
{
u32 SoundID = rFile.ReadLong() & 0xFFFF;
if (SoundID != 0xFFFF)
{
SSoundInfo SoundInfo = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID);
mpGroup->AddDependency(SoundInfo.pAudioGroup);
}
break;
}
default:
Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown sound function: " + Func.ToString());
break;
}
}
void CUnsupportedParticleLoader::ParseAssetFunction(IInputStream& rFile) void CUnsupportedParticleLoader::ParseAssetFunction(IInputStream& rFile)
{ {
u32 FuncOffset = rFile.Tell(); u32 FuncOffset = rFile.Tell();

View File

@ -31,6 +31,7 @@ class CUnsupportedParticleLoader
void ParseColorFunction(IInputStream& rFile); void ParseColorFunction(IInputStream& rFile);
void ParseUVFunction(IInputStream& rFile); void ParseUVFunction(IInputStream& rFile);
void ParseEmitterFunction(IInputStream& rFile); void ParseEmitterFunction(IInputStream& rFile);
void ParseSoundFunction(IInputStream& rFile);
void ParseAssetFunction(IInputStream& rFile); void ParseAssetFunction(IInputStream& rFile);
void ParseSpawnSystemKeyframeData(IInputStream& rFile); void ParseSpawnSystemKeyframeData(IInputStream& rFile);
void ParseKeyframeEmitterData(IInputStream& rFile, const CFourCC& rkFunc, u32 ElemSize); void ParseKeyframeEmitterData(IInputStream& rFile, const CFourCC& rkFunc, u32 ElemSize);

View File

@ -515,6 +515,8 @@ FUNC(Color, VRTC, 'V', 'R', 'T', 'C') // Vector, Float
// UV Functions // UV Functions
FUNC(UV, CNST, 'C', 'N', 'S', 'T') // Asset (TXTR) FUNC(UV, CNST, 'C', 'N', 'S', 'T') // Asset (TXTR)
FUNC(UV, ATEX, 'A', 'T', 'E', 'X') // Asset (TXTR), Int, Int, Int, Int, Int, Bool FUNC(UV, ATEX, 'A', 'T', 'E', 'X') // Asset (TXTR), Int, Int, Int, Int, Int, Bool
// Sound Functions
FUNC(Sound, CNST, 'C', 'N', 'S', 'T') // Sound ID
// Asset Functions // Asset Functions
FUNC(Asset, CNST, 'C', 'N', 'S', 'T') // Asset ID FUNC(Asset, CNST, 'C', 'N', 'S', 'T') // Asset ID
// Emitter Functions // Emitter Functions