From 560706d285f72dd3b07b1f354fe0dfd67934393a Mon Sep 17 00:00:00 2001 From: Aruki Date: Tue, 9 May 2017 14:16:41 -0600 Subject: [PATCH] Fixed issues in MP3 package list building --- src/Common/CAssetID.cpp | 12 ++- src/Common/CAssetID.h | 4 +- src/Common/Serialization/CBasicBinaryWriter.h | 2 +- src/Common/Serialization/CBinaryWriter.h | 2 +- src/Common/Serialization/CXMLWriter.h | 2 +- src/Core/Core.pro | 3 +- src/Core/GameProject/CGameProject.cpp | 18 +++++ src/Core/GameProject/CGameProject.h | 1 + src/Core/GameProject/CPackage.cpp | 64 +++++++++++----- .../GameProject/DependencyListBuilders.cpp | 63 +++++++++++++++- src/Core/GameProject/DependencyListBuilders.h | 3 + .../Animation/CAnimationParameters.cpp | 2 +- src/Core/Resource/CMapArea.h | 25 +++++++ src/Core/Resource/CResTypeInfo.cpp | 3 +- src/Core/Resource/CResource.h | 6 +- src/Core/Resource/Factory/CResourceFactory.h | 8 ++ .../Factory/CUnsupportedFormatLoader.cpp | 75 ++++++++++++++++++- .../Factory/CUnsupportedFormatLoader.h | 2 + src/Core/Resource/Factory/CWorldLoader.cpp | 2 +- src/Core/Scene/CScriptNode.cpp | 6 +- src/Editor/CProjectSettingsDialog.cpp | 10 ++- src/Editor/ModelEditor/CModelEditorWindow.cpp | 4 +- 22 files changed, 269 insertions(+), 48 deletions(-) create mode 100644 src/Core/Resource/CMapArea.h diff --git a/src/Common/CAssetID.cpp b/src/Common/CAssetID.cpp index a82f21be..4919c450 100644 --- a/src/Common/CAssetID.cpp +++ b/src/Common/CAssetID.cpp @@ -33,9 +33,11 @@ CAssetID::CAssetID(u64 ID, EIDLength Length) mID &= 0xFFFFFFFF; } -void CAssetID::Write(IOutputStream& rOutput) const +void CAssetID::Write(IOutputStream& rOutput, EIDLength ForcedLength /*= eInvalidIDLength*/) const { - if (mLength == e32Bit) + EIDLength Length = (ForcedLength == eInvalidIDLength ? mLength : ForcedLength); + + if (Length == e32Bit) rOutput.WriteLong(ToLong()); else rOutput.WriteLongLong(ToLongLong()); @@ -53,9 +55,11 @@ CAssetID::CAssetID(IInputStream& rInput, EGame Game) *this = CAssetID(rInput, (Game <= eEchoes ? e32Bit : e64Bit)); } -TString CAssetID::ToString() const +TString CAssetID::ToString(EIDLength ForcedLength /*= eInvalidIDLength*/) const { - if (mLength == e32Bit) + EIDLength Length = (ForcedLength == eInvalidIDLength ? mLength : ForcedLength); + + if (Length == e32Bit) return TString::HexString(ToLong(), 8, false, true); else return TString::FromInt64(ToLongLong(), 16, 16).ToUpper(); diff --git a/src/Common/CAssetID.h b/src/Common/CAssetID.h index 107efbf6..3775f11c 100644 --- a/src/Common/CAssetID.h +++ b/src/Common/CAssetID.h @@ -24,8 +24,8 @@ public: CAssetID(u64 ID, EIDLength Length); CAssetID(IInputStream& rInput, EIDLength Length); CAssetID(IInputStream& rInput, EGame Game); - void Write(IOutputStream& rOutput) const; - TString ToString() const; + void Write(IOutputStream& rOutput, EIDLength ForcedLength = eInvalidIDLength) const; + TString ToString(EIDLength ForcedLength = eInvalidIDLength) const; bool IsValid() const; // Operators diff --git a/src/Common/Serialization/CBasicBinaryWriter.h b/src/Common/Serialization/CBasicBinaryWriter.h index c51e5802..30da25e6 100644 --- a/src/Common/Serialization/CBasicBinaryWriter.h +++ b/src/Common/Serialization/CBasicBinaryWriter.h @@ -68,7 +68,7 @@ public: virtual void SerializePrimitive(TString& rValue) { mpStream->WriteSizedString(rValue); } virtual void SerializePrimitive(TWideString& rValue) { mpStream->WriteSizedWideString(rValue); } virtual void SerializePrimitive(CFourCC& rValue) { rValue.Write(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } virtual void SerializeHexPrimitive(u8& rValue) { mpStream->WriteByte(rValue); } virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); } diff --git a/src/Common/Serialization/CBinaryWriter.h b/src/Common/Serialization/CBinaryWriter.h index 2abd7006..05faa5a8 100644 --- a/src/Common/Serialization/CBinaryWriter.h +++ b/src/Common/Serialization/CBinaryWriter.h @@ -120,7 +120,7 @@ public: virtual void SerializePrimitive(TString& rValue) { mpStream->WriteSizedString(rValue); } virtual void SerializePrimitive(TWideString& rValue) { mpStream->WriteSizedWideString(rValue); } virtual void SerializePrimitive(CFourCC& rValue) { rValue.Write(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } virtual void SerializeHexPrimitive(u8& rValue) { mpStream->WriteByte(rValue); } virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); } diff --git a/src/Common/Serialization/CXMLWriter.h b/src/Common/Serialization/CXMLWriter.h index 5375dc00..21698ad7 100644 --- a/src/Common/Serialization/CXMLWriter.h +++ b/src/Common/Serialization/CXMLWriter.h @@ -116,7 +116,7 @@ public: virtual void SerializePrimitive(TString& rValue) { WriteParam(*rValue); } virtual void SerializePrimitive(TWideString& rValue) { WriteParam(*rValue.ToUTF8()); } virtual void SerializePrimitive(CFourCC& rValue) { WriteParam(*rValue.ToString()); } - virtual void SerializePrimitive(CAssetID& rValue) { WriteParam(*rValue.ToString()); } + virtual void SerializePrimitive(CAssetID& rValue) { WriteParam(*rValue.ToString( CAssetID::GameIDLength(Game()) )); } virtual void SerializeHexPrimitive(u8& rValue) { WriteParam(*TString::HexString(rValue, 2)); } virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); } diff --git a/src/Core/Core.pro b/src/Core/Core.pro index e8559f98..0f14781c 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -225,7 +225,8 @@ HEADERS += \ Resource/Cooker/CResourceCooker.h \ Resource/CAudioMacro.h \ CompressionUtil.h \ - Resource/Animation/CSourceAnimData.h + Resource/Animation/CSourceAnimData.h \ + Resource/CMapArea.h # Source Files SOURCES += \ diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index 46a6f698..3f1ac56e 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -143,6 +143,24 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const return CAssetID::InvalidID(mGame); } +CPackage* CGameProject::FindPackage(const TString& rkName) const +{ + if (mGame == eCorruptionProto || mGame == eCorruption) + { + for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) + { + CPackage *pPackage = mPackages[iPkg]; + + if (pPackage->Name() == rkName) + { + return pPackage; + } + } + } + + return nullptr; +} + CGameProject* CGameProject::CreateProjectForExport( const TString& rkProjRootDir, EGame Game, diff --git a/src/Core/GameProject/CGameProject.h b/src/Core/GameProject/CGameProject.h index f555bf01..0f21f3f5 100644 --- a/src/Core/GameProject/CGameProject.h +++ b/src/Core/GameProject/CGameProject.h @@ -67,6 +67,7 @@ public: void Serialize(IArchive& rArc); void GetWorldList(std::list& rOut) const; CAssetID FindNamedResource(const TString& rkName) const; + CPackage* FindPackage(const TString& rkName) const; // Static static CGameProject* CreateProjectForExport( diff --git a/src/Core/GameProject/CPackage.cpp b/src/Core/GameProject/CPackage.cpp index 7fc38138..f761935f 100644 --- a/src/Core/GameProject/CPackage.cpp +++ b/src/Core/GameProject/CPackage.cpp @@ -236,28 +236,56 @@ void CPackage::CompareOriginalAssetList(const std::list& rkNewList) return; } - // Skip past header + named resources + // Determine pak version u32 PakVersion = Pak.ReadLong(); - ASSERT(PakVersion == 0x00030005); - Pak.Seek(0x4, SEEK_CUR); - u32 NumNamedResources = Pak.ReadLong(); - - for (u32 iName = 0; iName < NumNamedResources; iName++) - { - Pak.Seek(0x8, SEEK_CUR); - u32 NameLen = Pak.ReadLong(); - Pak.Seek(NameLen, SEEK_CUR); - } - - // Build a set out of the original pak resource list - u32 NumResources = Pak.ReadLong(); std::set OldListSet; - for (u32 iRes = 0; iRes < NumResources; iRes++) + // Read MP1/2 pak + if (PakVersion == 0x00030005) { - Pak.Seek(0x8, SEEK_CUR); - OldListSet.insert( CAssetID(Pak, e32Bit) ); - Pak.Seek(0x8, SEEK_CUR); + Pak.Seek(0x4, SEEK_CUR); + u32 NumNamedResources = Pak.ReadLong(); + + for (u32 iName = 0; iName < NumNamedResources; iName++) + { + Pak.Seek(0x8, SEEK_CUR); + u32 NameLen = Pak.ReadLong(); + Pak.Seek(NameLen, SEEK_CUR); + } + + // Build a set out of the original pak resource list + u32 NumResources = Pak.ReadLong(); + + for (u32 iRes = 0; iRes < NumResources; iRes++) + { + Pak.Seek(0x8, SEEK_CUR); + OldListSet.insert( CAssetID(Pak, e32Bit) ); + Pak.Seek(0x8, SEEK_CUR); + } + } + + // Read MP3/DKCR pak + else + { + ASSERT(PakVersion == 0x2); + + // Skip named resources + Pak.Seek(0x44, SEEK_SET); + CFourCC StringSecType = Pak.ReadLong(); + u32 StringSecSize = Pak.ReadLong(); + ASSERT(StringSecType == "STRG"); + + Pak.Seek(0x80 + StringSecSize, SEEK_SET); + + // Read resource table + u32 NumResources = Pak.ReadLong(); + + for (u32 iRes = 0; iRes < NumResources; iRes++) + { + Pak.Seek(0x8, SEEK_CUR); + OldListSet.insert( CAssetID(Pak, e64Bit) ); + Pak.Seek(0x8, SEEK_CUR); + } } // Check for missing resources in the new list diff --git a/src/Core/GameProject/DependencyListBuilders.cpp b/src/Core/GameProject/DependencyListBuilders.cpp index 33da023e..2b5fc36f 100644 --- a/src/Core/GameProject/DependencyListBuilders.cpp +++ b/src/Core/GameProject/DependencyListBuilders.cpp @@ -3,6 +3,7 @@ // ************ CCharacterUsageMap ************ bool CCharacterUsageMap::IsCharacterUsed(const CAssetID& rkID, u32 CharacterIndex) const { + if (mpStore->Game() >= eCorruptionProto) return true; auto Find = mUsageMap.find(rkID); if (Find == mUsageMap.end()) return false; @@ -172,6 +173,7 @@ void CCharacterUsageMap::ParseDependencyNode(IDependencyNode *pNode) void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, std::list& rOut) { mEnableDuplicates = AllowDuplicates; + FindUniversalAreaAssets(); // Iterate over all resources and parse their dependencies for (u32 iRes = 0; iRes < mpkPackage->NumNamedResources(); iRes++) @@ -186,6 +188,8 @@ void CPackageDependencyListBuilder::BuildDependencyList(bool AllowDuplicates, st continue; } + mIsUniversalAreaAsset = (mUniversalAreaAssets.find(rkRes.ID) != mUniversalAreaAssets.end()); + if (rkRes.Type == "MLVL") { mpWorld = (CWorld*) pEntry->Load(); @@ -217,7 +221,8 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con if (!IsValid) return; if ( ( mCurrentAreaHasDuplicates && mAreaUsedAssets.find(rkID) != mAreaUsedAssets.end()) || - (!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) ) + (!mCurrentAreaHasDuplicates && mPackageUsedAssets.find(rkID) != mPackageUsedAssets.end()) || + (!mIsUniversalAreaAsset && mUniversalAreaAssets.find(rkID) != mUniversalAreaAssets.end() ) ) return; // Entry is valid, parse its sub-dependencies @@ -258,6 +263,10 @@ void CPackageDependencyListBuilder::AddDependency(CResourceEntry *pCurEntry, con // Revert current animset ID if (ResType == eAnimSet) mCurrentAnimSetID = CAssetID::InvalidID(mGame); + + // Revert duplicate flag + else if (ResType == eArea) + mCurrentAreaHasDuplicates = false; } void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list& rOut) @@ -316,6 +325,58 @@ void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurE } } +void CPackageDependencyListBuilder::FindUniversalAreaAssets() +{ + CGameProject *pProject = mpStore->Project(); + CPackage *pPackage = pProject->FindPackage("UniverseArea"); + + if (pPackage) + { + // Iterate over all the package contents, keep track of all universal area assets + for (u32 ResIdx = 0; ResIdx < pPackage->NumNamedResources(); ResIdx++) + { + const SNamedResource& rkRes = pPackage->NamedResourceByIndex(ResIdx); + + if (rkRes.ID.IsValid()) + { + mUniversalAreaAssets.insert(rkRes.ID); + + // For the universal area world, load it into memory to make sure we can exclude the area/map IDs + if (rkRes.Type == "MLVL") + { + CWorld *pUniverseWorld = gpResourceStore->LoadResource(rkRes.ID); + + if (pUniverseWorld) + { + // Area IDs + for (u32 AreaIdx = 0; AreaIdx < pUniverseWorld->NumAreas(); AreaIdx++) + { + CAssetID AreaID = pUniverseWorld->AreaResourceID(AreaIdx); + + if (AreaID.IsValid()) + mUniversalAreaAssets.insert(AreaID); + } + + // Map IDs + CDependencyGroup *pMapWorld = (CDependencyGroup*) pUniverseWorld->MapWorld(); + + if (pMapWorld) + { + for (u32 DepIdx = 0; DepIdx < pMapWorld->NumDependencies(); DepIdx++) + { + CAssetID DepID = pMapWorld->DependencyByIndex(DepIdx); + + if (DepID.IsValid()) + mUniversalAreaAssets.insert(DepID); + } + } + } + } + } + } + } +} + // ************ CAreaDependencyListBuilder ************ void CAreaDependencyListBuilder::BuildDependencyList(std::list& rAssetsOut, std::list& rLayerOffsetsOut, std::set *pAudioGroupsOut) { diff --git a/src/Core/GameProject/DependencyListBuilders.h b/src/Core/GameProject/DependencyListBuilders.h index 2a0371f3..ede95d9c 100644 --- a/src/Core/GameProject/DependencyListBuilders.h +++ b/src/Core/GameProject/DependencyListBuilders.h @@ -46,8 +46,10 @@ class CPackageDependencyListBuilder CCharacterUsageMap mCharacterUsageMap; std::set mPackageUsedAssets; std::set mAreaUsedAssets; + std::set mUniversalAreaAssets; bool mEnableDuplicates; bool mCurrentAreaHasDuplicates; + bool mIsUniversalAreaAsset; bool mIsPlayerActor; public: @@ -64,6 +66,7 @@ public: void BuildDependencyList(bool AllowDuplicates, std::list& rOut); void AddDependency(CResourceEntry *pCurEntry, const CAssetID& rkID, std::list& rOut); void EvaluateDependencyNode(CResourceEntry *pCurEntry, IDependencyNode *pNode, std::list& rOut); + void FindUniversalAreaAssets(); }; // ************ CAreaDependencyListBuilder ************ diff --git a/src/Core/Resource/Animation/CAnimationParameters.cpp b/src/Core/Resource/Animation/CAnimationParameters.cpp index 4ea015ed..9518d766 100644 --- a/src/Core/Resource/Animation/CAnimationParameters.cpp +++ b/src/Core/Resource/Animation/CAnimationParameters.cpp @@ -140,7 +140,7 @@ const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(s32 NodeIndex { CAnimSet *pSet = AnimSet(); - if (pSet && pSet->Type() == eAnimSet) + if (pSet && (pSet->Type() == eAnimSet || pSet->Type() == eCharacter)) { if (NodeIndex == -1) NodeIndex = mCharIndex; diff --git a/src/Core/Resource/CMapArea.h b/src/Core/Resource/CMapArea.h new file mode 100644 index 00000000..d2f4216b --- /dev/null +++ b/src/Core/Resource/CMapArea.h @@ -0,0 +1,25 @@ +#ifndef CMAPAREA_H +#define CMAPAREA_H + +#include "CResource.h" + +// Barebones class +class CMapArea : public CResource +{ + friend class CUnsupportedFormatLoader; + CAssetID mNameString; + +public: + CMapArea(CResourceEntry *pEntry = 0) + : CResource(pEntry) + {} + + CDependencyTree* BuildDependencyTree() const + { + CDependencyTree *pTree = new CDependencyTree(); + pTree->AddDependency(mNameString); + return pTree; + } +}; + +#endif // CMAPAREA_H diff --git a/src/Core/Resource/CResTypeInfo.cpp b/src/Core/Resource/CResTypeInfo.cpp index 3cc3eec9..d908f19d 100644 --- a/src/Core/Resource/CResTypeInfo.cpp +++ b/src/Core/Resource/CResTypeInfo.cpp @@ -242,7 +242,6 @@ void CResTypeInfo::CResTypeInfoFactory::InitTypes() CResTypeInfo *pType = new CResTypeInfo(eMapArea, "Area Map"); AddExtension(pType, "MAPA", ePrimeDemo, eCorruption); pType->mHidden = true; - pType->mCanHaveDependencies = false; } { CResTypeInfo *pType = new CResTypeInfo(eMapWorld, "World Map"); @@ -371,7 +370,7 @@ void CResTypeInfo::CResTypeInfoFactory::InitTypes() } { CResTypeInfo *pType = new CResTypeInfo(eStateMachine2, "State Machine 2"); - AddExtension(pType, "FSM2", eEchoesDemo, eEchoes); + AddExtension(pType, "FSM2", eEchoesDemo, eCorruption); pType->mRawExtension = "fsm2"; } { diff --git a/src/Core/Resource/CResource.h b/src/Core/Resource/CResource.h index 606da38d..036e2eef 100644 --- a/src/Core/Resource/CResource.h +++ b/src/Core/Resource/CResource.h @@ -16,11 +16,6 @@ // Must be included on every CResource subclass. #define DECLARE_RESOURCE_TYPE(ResTypeEnum) \ public: \ - virtual EResType Type() const \ - { \ - return ResTypeEnum; \ - } \ - \ static EResType StaticType() \ { \ return ResTypeEnum; \ @@ -52,6 +47,7 @@ public: inline CResourceEntry* Entry() const { return mpEntry; } inline CResTypeInfo* TypeInfo() const { return mpEntry->TypeInfo(); } + inline EResType Type() const { return mpEntry->TypeInfo()->Type(); } inline TString Source() const { return mpEntry ? mpEntry->CookedAssetPath(true).GetFileName() : ""; } inline TString FullSource() const { return mpEntry ? mpEntry->CookedAssetPath(true) : ""; } inline CAssetID ID() const { return mpEntry ? mpEntry->ID() : CAssetID::skInvalidID64; } diff --git a/src/Core/Resource/Factory/CResourceFactory.h b/src/Core/Resource/Factory/CResourceFactory.h index bc264b80..6e9bd1de 100644 --- a/src/Core/Resource/Factory/CResourceFactory.h +++ b/src/Core/Resource/Factory/CResourceFactory.h @@ -45,6 +45,7 @@ public: case eDynamicCollision: return new CCollisionMeshGroup(pEntry); case eDependencyGroup: return new CDependencyGroup(pEntry); case eFont: return new CFont(pEntry); + case eMapArea: return new CMapArea(pEntry); case eModel: return new CModel(pEntry); case eScan: return new CScan(pEntry); case eSkeleton: return new CSkeleton(pEntry); @@ -81,6 +82,7 @@ public: case eFont: pRes = CFontLoader::LoadFONT(rInput, pEntry); break; case eGuiFrame: pRes = CUnsupportedFormatLoader::LoadFRME(rInput, pEntry); break; case eHintSystem: pRes = CUnsupportedFormatLoader::LoadHINT(rInput, pEntry); break; + case eMapArea: pRes = CUnsupportedFormatLoader::LoadMAPA(rInput, pEntry); break; case eMapWorld: pRes = CUnsupportedFormatLoader::LoadMAPW(rInput, pEntry); break; case eMapUniverse: pRes = CUnsupportedFormatLoader::LoadMAPU(rInput, pEntry); break; case eMidi: pRes = CUnsupportedFormatLoader::LoadCSNG(rInput, pEntry); break; @@ -97,6 +99,12 @@ public: case eTexture: pRes = CTextureDecoder::LoadTXTR(rInput, pEntry); break; case eWorld: pRes = CWorldLoader::LoadMLVL(rInput, pEntry); break; + case eStateMachine: + // AFSM and FSMC currently unsupported + if (pEntry->Game() == eCorruptionProto || pEntry->Game() == eCorruption) + pRes = CUnsupportedFormatLoader::LoadFSM2(rInput, pEntry); + break; + case eBurstFireData: case eParticle: case eParticleElectric: diff --git a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp index ccba8b3e..ee1cb6ab 100644 --- a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp @@ -1,5 +1,7 @@ #include "CUnsupportedFormatLoader.h" #include "Core/GameProject/CGameProject.h" +#include "Core/GameProject/CResourceIterator.h" +#include "Core/Resource/CWorld.h" CAudioMacro* CUnsupportedFormatLoader::LoadCAUD(IInputStream& rCAUD, CResourceEntry *pEntry) { @@ -253,11 +255,12 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou u32 NumUnkA = rFSM2.ReadLong(); u32 NumUnkB = rFSM2.ReadLong(); u32 NumUnkC = rFSM2.ReadLong(); - ASSERT(Version == 1); + ASSERT(Version == 1 || Version == 2); for (u32 iState = 0; iState < NumStates; iState++) { rFSM2.ReadString(); + if (Version >= 2) rFSM2.Seek(0x10, SEEK_CUR); u32 UnkCount = rFSM2.ReadLong(); for (u32 iUnk = 0; iUnk < UnkCount; iUnk++) @@ -270,6 +273,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou for (u32 iUnkA = 0; iUnkA < NumUnkA; iUnkA++) { rFSM2.ReadString(); + if (Version >= 2) rFSM2.Seek(0x10, SEEK_CUR); rFSM2.Seek(0x4, SEEK_CUR); u32 UnkCount = rFSM2.ReadLong(); @@ -285,6 +289,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou for (u32 iUnkB = 0; iUnkB < NumUnkB; iUnkB++) { rFSM2.ReadString(); + if (Version >= 2) rFSM2.Seek(0x10, SEEK_CUR); u32 UnkCount = rFSM2.ReadLong(); for (u32 iUnkB2 = 0; iUnkB2 < UnkCount; iUnkB2++) @@ -297,6 +302,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou for (u32 iUnkC = 0; iUnkC < NumUnkC; iUnkC++) { rFSM2.ReadString(); + if (Version >= 2) rFSM2.Seek(0x10, SEEK_CUR); u32 UnkCount = rFSM2.ReadLong(); for (u32 iUnkC2 = 0; iUnkC2 < UnkCount; iUnkC2++) @@ -305,7 +311,7 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou rFSM2.Seek(0x4, SEEK_CUR); } - pOut->AddDependency( CAssetID(rFSM2, eEchoes) ); + pOut->AddDependency( CAssetID(rFSM2, pEntry->Game()) ); } return pOut; @@ -362,20 +368,83 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResou rHINT.ReadString(); // Skip hint name rHINT.Seek(0x8, SEEK_CUR); // Skip unknown + appear time pGroup->AddDependency( CAssetID(rHINT, Game) ); // Pop-up STRG - rHINT.Seek(0x8, SEEK_CUR); // Skip unknowns + rHINT.Seek(0x4, SEEK_CUR); // Skip unknowns if (Game <= eEchoes) { + rHINT.Seek(0x4, SEEK_CUR); pGroup->AddDependency( CAssetID(rHINT, Game) ); // Target MLVL pGroup->AddDependency( CAssetID(rHINT, Game) ); // Target MREA rHINT.Seek(0x4, SEEK_CUR); // Skip target room index pGroup->AddDependency( CAssetID(rHINT, Game) ); // Map STRG } + + else + { + u32 NumLocations = rHINT.ReadLong(); + + for (u32 iLoc = 0; iLoc < NumLocations; iLoc++) + { + rHINT.Seek(0x14, SEEK_CUR); // Skip world/area ID, area index + pGroup->AddDependency( CAssetID(rHINT, Game) ); // Objective string + rHINT.Seek(0xC, SEEK_CUR); // Skip unknown data + } + } } return pGroup; } +CMapArea* CUnsupportedFormatLoader::LoadMAPA(IInputStream& /*rMAPA*/, CResourceEntry *pEntry) +{ + TResPtr pMap = new CMapArea(pEntry); + + // We don't actually read the file. Just fetch the name string so we can build the dependency tree. + CAssetID MapAreaID = pMap->ID(); + + // Find a MapWorld that contains this MapArea + CAssetID MapWorldID; + u32 WorldIndex = -1; + + for (TResourceIterator It; It; ++It) + { + CDependencyGroup *pGroup = (CDependencyGroup*) It->Load(); + + for (u32 AreaIdx = 0; AreaIdx < pGroup->NumDependencies(); AreaIdx++) + { + if (pGroup->DependencyByIndex(AreaIdx) == MapAreaID) + { + WorldIndex = AreaIdx; + MapWorldID = pGroup->ID(); + break; + } + } + + if (WorldIndex != -1) + break; + } + + // Find a world that contains this MapWorld + if (WorldIndex != -1) + { + for (TResourceIterator It; It; ++It) + { + CWorld *pWorld = (CWorld*) It->Load(); + CDependencyGroup *pMapWorld = (CDependencyGroup*) pWorld->MapWorld(); + + if (pMapWorld && pMapWorld->ID() == MapWorldID) + { + CStringTable *pNameString = pWorld->AreaName(WorldIndex); + pMap->mNameString = (pNameString ? pNameString->ID() : CAssetID::InvalidID(pEntry->Game())); + break; + } + } + } + + pMap->Entry()->ResourceStore()->DestroyUnreferencedResources(); + return pMap; +} + CDependencyGroup* CUnsupportedFormatLoader::LoadMAPW(IInputStream& rMAPW, CResourceEntry *pEntry) { u32 Magic = rMAPW.ReadLong(); diff --git a/src/Core/Resource/Factory/CUnsupportedFormatLoader.h b/src/Core/Resource/Factory/CUnsupportedFormatLoader.h index 10faacf3..a5845ded 100644 --- a/src/Core/Resource/Factory/CUnsupportedFormatLoader.h +++ b/src/Core/Resource/Factory/CUnsupportedFormatLoader.h @@ -3,6 +3,7 @@ #include "Core/Resource/CAudioMacro.h" #include "Core/Resource/CDependencyGroup.h" +#include "Core/Resource/CMapArea.h" // This class is responsible for loading formats that aren't yet fully supported. // This is needed so we have access to the full dependency list of all resource types. @@ -19,6 +20,7 @@ public: static CDependencyGroup* LoadFSM2(IInputStream& rFSM2, CResourceEntry *pEntry); static CDependencyGroup* LoadHIER(IInputStream& rHIER, CResourceEntry *pEntry); static CDependencyGroup* LoadHINT(IInputStream& rHINT, CResourceEntry *pEntry); + static CMapArea* LoadMAPA(IInputStream& rMAPA, CResourceEntry *pEntry); static CDependencyGroup* LoadMAPW(IInputStream& rMAPW, CResourceEntry *pEntry); static CDependencyGroup* LoadMAPU(IInputStream& rMAPU, CResourceEntry *pEntry); static CDependencyGroup* LoadRULE(IInputStream& rRULE, CResourceEntry *pEntry); diff --git a/src/Core/Resource/Factory/CWorldLoader.cpp b/src/Core/Resource/Factory/CWorldLoader.cpp index 5fb62875..e5d7edd4 100644 --- a/src/Core/Resource/Factory/CWorldLoader.cpp +++ b/src/Core/Resource/Factory/CWorldLoader.cpp @@ -27,7 +27,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL) { mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), eStringTable); rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value - mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), eStringTable); + mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), eSaveWorld); mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), eModel); } diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 07ddfc9d..162a3f41 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -655,7 +655,7 @@ CModel* CScriptNode::ActiveModel() const { if (mpDisplayAsset->Type() == eModel) return static_cast(mpDisplayAsset.RawPointer()); - else if (mpDisplayAsset->Type() == eAnimSet) + else if (mpDisplayAsset->Type() == eAnimSet || mpDisplayAsset->Type() == eCharacter) return static_cast(mpDisplayAsset.RawPointer())->Character(mCharIndex)->pModel; } @@ -664,7 +664,7 @@ CModel* CScriptNode::ActiveModel() const CAnimSet* CScriptNode::ActiveAnimSet() const { - if (mpDisplayAsset && mpDisplayAsset->Type() == eAnimSet) + if (mpDisplayAsset && (mpDisplayAsset->Type() == eAnimSet || mpDisplayAsset->Type() == eCharacter)) return static_cast(mpDisplayAsset.RawPointer()); else return nullptr; @@ -739,7 +739,7 @@ void CScriptNode::SetDisplayAsset(CResource *pRes) { mpDisplayAsset = pRes; - bool IsAnimSet = (pRes && pRes->Type() == eAnimSet); + bool IsAnimSet = (pRes && (pRes->Type() == eAnimSet || pRes->Type() == eCharacter)); mCharIndex = (IsAnimSet ? mpInstance->ActiveCharIndex() : -1); mAnimIndex = (IsAnimSet ? mpInstance->ActiveAnimIndex() : -1); diff --git a/src/Editor/CProjectSettingsDialog.cpp b/src/Editor/CProjectSettingsDialog.cpp index f06475d4..08534d9b 100644 --- a/src/Editor/CProjectSettingsDialog.cpp +++ b/src/Editor/CProjectSettingsDialog.cpp @@ -78,9 +78,13 @@ void CProjectSettingsDialog::SetupPackagesList() void CProjectSettingsDialog::CookPackage() { u32 PackageIdx = mpUI->PackagesList->currentRow(); - CPackage *pPackage = mpProject->PackageByIndex(PackageIdx); - pPackage->Cook(); - SetupPackagesList(); + + if (PackageIdx != -1) + { + CPackage *pPackage = mpProject->PackageByIndex(PackageIdx); + pPackage->Cook(); + SetupPackagesList(); + } } void CProjectSettingsDialog::CookAllDirtyPackages() diff --git a/src/Editor/ModelEditor/CModelEditorWindow.cpp b/src/Editor/ModelEditor/CModelEditorWindow.cpp index 60659472..cd606da9 100644 --- a/src/Editor/ModelEditor/CModelEditorWindow.cpp +++ b/src/Editor/ModelEditor/CModelEditorWindow.cpp @@ -763,7 +763,7 @@ void CModelEditorWindow::ConvertToDDS() if (Input.isEmpty()) return; TString TexFilename = TO_TSTRING(Input); - TResPtr pTex = gpResourceStore->LoadResource(TexFilename); + CTexture *pTex = CTextureDecoder::LoadDDS( CFileInStream(TexFilename, IOUtil::eLittleEndian), nullptr ); TString OutName = TexFilename.GetFilePathWithoutExtension() + ".dds"; CFileOutStream Out(OutName, IOUtil::eLittleEndian); @@ -775,6 +775,8 @@ void CModelEditorWindow::ConvertToDDS() if (!Success) QMessageBox::warning(this, "Error", "Couldn't write output DDS!"); else QMessageBox::information(this, "Success", "Successfully converted to DDS!"); } + + delete pTex; } void CModelEditorWindow::ConvertToTXTR()