diff --git a/src/Core/GameProject/CDependencyTree.cpp b/src/Core/GameProject/CDependencyTree.cpp index 9e18e731..94143de7 100644 --- a/src/Core/GameProject/CDependencyTree.cpp +++ b/src/Core/GameProject/CDependencyTree.cpp @@ -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(pProp)); + else if (Type == eSoundProperty) + { + u32 SoundID = static_cast(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(pProp)->Get(); diff --git a/src/Core/GameProject/CGameExporter.cpp b/src/Core/GameProject/CGameExporter.cpp index ff0c51e5..2cf7e8d9 100644 --- a/src/Core/GameProject/CGameExporter.cpp +++ b/src/Core/GameProject/CGameExporter.cpp @@ -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 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 diff --git a/src/Core/GameProject/CGameExporter.h b/src/Core/GameProject/CGameExporter.h index 5317b40e..f3cb713a 100644 --- a/src/Core/GameProject/CGameExporter.h +++ b/src/Core/GameProject/CGameExporter.h @@ -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& 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 diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index a47b431e..bee0d30c 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -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; } diff --git a/src/Core/GameProject/CGameProject.h b/src/Core/GameProject/CGameProject.h index 90393f9f..ac10d1c1 100644 --- a/src/Core/GameProject/CGameProject.h +++ b/src/Core/GameProject/CGameProject.h @@ -4,6 +4,7 @@ #include "CPackage.h" #include "CResourceStore.h" #include "Core/CAudioManager.h" +#include "Core/Resource/Script/CMasterTemplate.h" #include #include #include @@ -18,7 +19,7 @@ class CGameProject TWideString mResourceDBPath; std::vector 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; } diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index 05911c21..ed24ab69 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -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()) { diff --git a/src/Core/GameProject/CResourceStore.cpp b/src/Core/GameProject/CResourceStore.cpp index 90edc35b..48a3ac93 100644 --- a/src/Core/GameProject/CResourceStore.cpp +++ b/src/Core/GameProject/CResourceStore.cpp @@ -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) diff --git a/src/Core/GameProject/CResourceStore.h b/src/Core/GameProject/CResourceStore.h index 0a11684e..7f33fd80 100644 --- a/src/Core/GameProject/CResourceStore.h +++ b/src/Core/GameProject/CResourceStore.h @@ -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); diff --git a/src/Core/GameProject/DependencyListBuilders.cpp b/src/Core/GameProject/DependencyListBuilders.cpp index fa83da1b..6ae845ea 100644 --- a/src/Core/GameProject/DependencyListBuilders.cpp +++ b/src/Core/GameProject/DependencyListBuilders.cpp @@ -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& rAssetsOut, std::list& rLayerOffsetsOut) +void CAreaDependencyListBuilder::BuildDependencyList(std::list& rAssetsOut, std::list& rLayerOffsetsOut, std::set *pAudioGroupsOut) { CAreaDependencyTree *pTree = static_cast(mpAreaEntry->Dependencies()); @@ -331,7 +330,7 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list& rAsset continue; } - AddDependency(pDep->ID(), rAssetsOut); + AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut); } } } @@ -344,24 +343,27 @@ void CAreaDependencyListBuilder::BuildDependencyList(std::list& rAsset for (u32 iDep = 0; iDep < BaseEndIndex; iDep++) { CResourceDependency *pDep = static_cast(pTree->ChildByIndex(iDep)); - AddDependency(pDep->ID(), rAssetsOut); + AddDependency(pDep->ID(), rAssetsOut, pAudioGroupsOut); } } -void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list& rOut) +void CAreaDependencyListBuilder::AddDependency(const CAssetID& rkID, std::list& rOut, std::set *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(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(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(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); } diff --git a/src/Core/GameProject/DependencyListBuilders.h b/src/Core/GameProject/DependencyListBuilders.h index 49c71653..48376009 100644 --- a/src/Core/GameProject/DependencyListBuilders.h +++ b/src/Core/GameProject/DependencyListBuilders.h @@ -72,8 +72,8 @@ public: ASSERT(mpAreaEntry->ResourceType() == eArea); } - void BuildDependencyList(std::list& rAssetsOut, std::list& rLayerOffsetsOut); - void AddDependency(const CAssetID& rkID, std::list& rOut); + void BuildDependencyList(std::list& rAssetsOut, std::list& rLayerOffsetsOut, std::set *pAudioGroupsOut = nullptr); + void AddDependency(const CAssetID& rkID, std::list& rOut, std::set *pAudioGroupsOut); }; #endif // DEPENDENCYLISTBUILDERS diff --git a/src/Core/Resource/Cooker/CWorldCooker.cpp b/src/Core/Resource/Cooker/CWorldCooker.cpp index fe42c713..5f8826a3 100644 --- a/src/Core/Resource/Cooker/CWorldCooker.cpp +++ b/src/Core/Resource/Cooker/CWorldCooker.cpp @@ -49,6 +49,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL) // Areas rMLVL.WriteLong(pWorld->mAreas.size()); if (Game <= ePrime) rMLVL.WriteLong(1); // Unknown + std::set AudioGroups; for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++) { @@ -79,7 +80,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL) std::list Dependencies; std::list LayerDependsOffsets; CAreaDependencyListBuilder Builder(pAreaEntry); - Builder.BuildDependencyList(Dependencies, LayerDependsOffsets); + Builder.BuildDependencyList(Dependencies, LayerDependsOffsets, &AudioGroups); rMLVL.WriteLong(0); rMLVL.WriteLong( Dependencies.size() ); @@ -156,6 +157,59 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL) // Audio Groups if (Game <= ePrime) { +#if 0 + // Debug: make sure our generated list matches the original, no missing or extra audio groups + std::set 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 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()); for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++) @@ -164,6 +218,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL) rMLVL.WriteLong(rAudioGroup.GroupID); rAudioGroup.ResID.Write(rMLVL); } +#endif rMLVL.WriteByte(0); } diff --git a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp index 184af3ad..9ca727b4 100644 --- a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp @@ -1,4 +1,5 @@ #include "CUnsupportedFormatLoader.h" +#include "Core/GameProject/CGameProject.h" #include "Core/Resource/ParticleParameters.h" CDependencyGroup* CUnsupportedFormatLoader::LoadCSNG(IInputStream& rCSNG, CResourceEntry *pEntry) @@ -67,8 +68,16 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadEVNT(IInputStream& rEVNT, CResou { rEVNT.Seek(0x2, SEEK_CUR); 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 (SoundID != 0xFFFF) + { + SSoundInfo SoundInfo = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID); + pGroup->AddDependency(SoundInfo.pAudioGroup); + } } } diff --git a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp index 7756b979..60c3a957 100644 --- a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp @@ -1,4 +1,5 @@ #include "CUnsupportedParticleLoader.h" +#include // ************ PARAMETER LOADING ************ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) @@ -462,8 +463,7 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC) case kWeaponVMD2: ParseBoolFunction(rWPSC); break; - - case kWeaponPJFX: + case kWeaponPSLT: ParseIntFunction(rWPSC); break; @@ -509,6 +509,10 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC) case kWeaponTTEX: ParseUVFunction(rWPSC); break; + + case kWeaponPJFX: + ParseSoundFunction(rWPSC); + break; case kWeaponAPSM: case kWeaponAPS1: @@ -570,26 +574,12 @@ bool CUnsupportedParticleLoader::ParseCollisionResponseParameter(IInputStream& r case kColi6GRN: case kColi2MUD: case kColi2SAN: - case kColiBHFX: - case kColiCHFX: - case kColiCSFX: - case kColiCZFX: case kColiDCSH: - case kColiDSFX: case kColiDSHX: - case kColiGOFX: - case kColiGRFX: - case kColiHBFX: - case kColiICFX: - case kColiMSFX: case kColiPBHX: case kColiPBOS: case kColiPBSX: - case kColiSHFX: - case kColiTAFX: case kColiTASP: - case kColiWSFX: - case kColiWTFX: ParseIntFunction(rCRSC); break; @@ -597,7 +587,24 @@ bool CUnsupportedParticleLoader::ParseCollisionResponseParameter(IInputStream& r case kColiRNGE: ParseFloatFunction(rCRSC); 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 kColi3LAV: 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) { u32 FuncOffset = rFile.Tell(); diff --git a/src/Core/Resource/Factory/CUnsupportedParticleLoader.h b/src/Core/Resource/Factory/CUnsupportedParticleLoader.h index 7e9ddcce..3be9960c 100644 --- a/src/Core/Resource/Factory/CUnsupportedParticleLoader.h +++ b/src/Core/Resource/Factory/CUnsupportedParticleLoader.h @@ -31,6 +31,7 @@ class CUnsupportedParticleLoader void ParseColorFunction(IInputStream& rFile); void ParseUVFunction(IInputStream& rFile); void ParseEmitterFunction(IInputStream& rFile); + void ParseSoundFunction(IInputStream& rFile); void ParseAssetFunction(IInputStream& rFile); void ParseSpawnSystemKeyframeData(IInputStream& rFile); void ParseKeyframeEmitterData(IInputStream& rFile, const CFourCC& rkFunc, u32 ElemSize); diff --git a/src/Core/Resource/ParticleParameters.h b/src/Core/Resource/ParticleParameters.h index ce9d7d77..e87eabca 100644 --- a/src/Core/Resource/ParticleParameters.h +++ b/src/Core/Resource/ParticleParameters.h @@ -515,6 +515,8 @@ FUNC(Color, VRTC, 'V', 'R', 'T', 'C') // Vector, Float // UV Functions FUNC(UV, CNST, 'C', 'N', 'S', 'T') // Asset (TXTR) 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 FUNC(Asset, CNST, 'C', 'N', 'S', 'T') // Asset ID // Emitter Functions