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 "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();

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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; }

View File

@ -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())
{

View File

@ -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)

View File

@ -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);

View File

@ -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);
}
}
// 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);
}
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

View File

@ -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<CAssetID> AudioGroups;
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<u32> 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<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());
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);
}

View File

@ -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);
}
}
}

View File

@ -1,4 +1,5 @@
#include "CUnsupportedParticleLoader.h"
#include <Core/GameProject/CGameProject.h>
// ************ PARAMETER LOADING ************
bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART)
@ -463,7 +464,6 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC)
ParseBoolFunction(rWPSC);
break;
case kWeaponPJFX:
case kWeaponPSLT:
ParseIntFunction(rWPSC);
break;
@ -510,6 +510,10 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC)
ParseUVFunction(rWPSC);
break;
case kWeaponPJFX:
ParseSoundFunction(rWPSC);
break;
case kWeaponAPSM:
case kWeaponAPS1:
case kWeaponAPS2:
@ -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;
@ -598,6 +588,23 @@ bool CUnsupportedParticleLoader::ParseCollisionResponseParameter(IInputStream& r
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();

View File

@ -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);

View File

@ -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