diff --git a/src/Common/FileUtil.cpp b/src/Common/FileUtil.cpp index e770f38b..100ab243 100644 --- a/src/Common/FileUtil.cpp +++ b/src/Common/FileUtil.cpp @@ -364,6 +364,13 @@ TString SanitizeName(TString Name, bool Directory, bool RootDir /*= false*/) if (NumLeadingSpaces > 0) Name = Name.ChopFront(NumLeadingSpaces); + // Ensure the name is below the character limit + if (Name.Size() > 255) + { + u32 ChopNum = Name.Size() - 255; + Name = Name.ChopBack(ChopNum); + } + return Name; } diff --git a/src/Core/GameProject/CDependencyTree.cpp b/src/Core/GameProject/CDependencyTree.cpp index c1a3b2c5..82da94f8 100644 --- a/src/Core/GameProject/CDependencyTree.cpp +++ b/src/Core/GameProject/CDependencyTree.cpp @@ -207,6 +207,7 @@ CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& pTree->AddDependency(rkChar.pSkeleton); pTree->AddDependency(rkChar.pSkin); pTree->AddDependency(rkChar.AnimDataID); + pTree->AddDependency(rkChar.CollisionPrimitivesID); const std::vector *pkParticleVectors[5] = { &rkChar.GenericParticles, &rkChar.ElectricParticles, diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index fc057dfd..2b4a506c 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -174,16 +174,13 @@ CAssetID CGameProject::FindNamedResource(const TString& rkName) const CPackage* CGameProject::FindPackage(const TString& rkName) const { - if (mGame == eCorruptionProto || mGame == eCorruption) + for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) { - for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) - { - CPackage *pPackage = mPackages[iPkg]; + CPackage *pPackage = mPackages[iPkg]; - if (pPackage->Name() == rkName) - { - return pPackage; - } + if (pPackage->Name() == rkName) + { + return pPackage; } } diff --git a/src/Core/Render/CCamera.cpp b/src/Core/Render/CCamera.cpp index c1ecb4f1..1b1c047e 100644 --- a/src/Core/Render/CCamera.cpp +++ b/src/Core/Render/CCamera.cpp @@ -7,7 +7,7 @@ CCamera::CCamera() : mMode(eFreeCamera) , mPosition(0) , mAspectRatio(1.7777777f) - , mYaw(-Math::skHalfPi) + , mYaw(Math::skHalfPi) , mPitch(0.f) , mMoveSpeed(1.f) , mLookSpeed(1.f) @@ -26,7 +26,7 @@ CCamera::CCamera(CVector3f Position, CVector3f /*Target*/) , mMoveSpeed(1.f) , mLookSpeed(1.f) , mPosition(Position) - , mYaw(-Math::skHalfPi) + , mYaw(Math::skHalfPi) , mPitch(0.f) { } @@ -75,7 +75,7 @@ void CCamera::Zoom(float Amount) void CCamera::Snap(CVector3f Position) { mPosition = Position; - mYaw = -Math::skHalfPi; + mYaw = Math::skHalfPi; mPitch = 0.0f; mTransformDirty = true; mViewDirty = true; diff --git a/src/Core/Resource/Animation/CAnimSet.h b/src/Core/Resource/Animation/CAnimSet.h index d474e190..adbf6d53 100644 --- a/src/Core/Resource/Animation/CAnimSet.h +++ b/src/Core/Resource/Animation/CAnimSet.h @@ -69,6 +69,7 @@ struct SSetCharacter TResPtr pSkeleton; std::vector OverlayModels; CAssetID AnimDataID; + CAssetID CollisionPrimitivesID; std::vector GenericParticles; std::vector ElectricParticles; @@ -76,6 +77,7 @@ struct SSetCharacter std::vector SpawnParticles; std::vector EffectParticles; std::vector SoundEffects; + std::vector DKDependencies; CAssetID SpatialPrimitives; std::set UsedAnimationIndices; }; @@ -149,7 +151,7 @@ public: } } - else + else if (Game() <= eCorruption) { const SSetCharacter& rkChar = mCharacters[0]; std::set PrimitiveSet; @@ -165,19 +167,27 @@ public: if (pAnimData) pAnimData->AddTransitionDependencies(pTree); - // Event particles/sounds for (auto Iter = PrimitiveSet.begin(); Iter != PrimitiveSet.end(); Iter++) { const CAnimPrimitive& rkPrim = *Iter; pTree->AddDependency(rkPrim.Animation()); } + // Event sounds for (u32 iSound = 0; iSound < rkChar.SoundEffects.size(); iSound++) { pTree->AddDependency(rkChar.SoundEffects[iSound]); } } + else + { + const SSetCharacter& rkChar = mCharacters[0]; + + for (u32 iDep = 0; iDep < rkChar.DKDependencies.size(); iDep++) + pTree->AddDependency(rkChar.DKDependencies[iDep]); + } + return pTree; } diff --git a/src/Core/Resource/Factory/CAnimSetLoader.cpp b/src/Core/Resource/Factory/CAnimSetLoader.cpp index 617f1a5a..8087c697 100644 --- a/src/Core/Resource/Factory/CAnimSetLoader.cpp +++ b/src/Core/Resource/Factory/CAnimSetLoader.cpp @@ -98,17 +98,137 @@ CAnimSet* CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR) CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR) { - // For now, we only read enough to fetch the model - rCHAR.Seek(0x16, SEEK_CUR); + rCHAR.Skip(0x14); + u8 Flag = rCHAR.ReadByte(); + rCHAR.Skip(1); pSet->mCharacters.emplace_back( SSetCharacter() );; SSetCharacter& rChar = pSet->mCharacters.back(); + // Character Header rChar.ID = 0; rChar.Name = rCHAR.ReadString(); - rCHAR.Seek(0x14, SEEK_CUR); - rCHAR.ReadString(); - rChar.pModel = gpResourceStore->LoadResource(rCHAR.ReadLongLong()); + rChar.pSkeleton = gpResourceStore->LoadResource( rCHAR.ReadLongLong() ); + rChar.CollisionPrimitivesID = rCHAR.ReadLongLong(); + + u32 NumModels = rCHAR.ReadLong(); + + for (u32 ModelIdx = 0; ModelIdx < NumModels; ModelIdx++) + { + rCHAR.ReadString(); + CAssetID ModelID(rCHAR, eReturns); + CAssetID SkinID(rCHAR, eReturns); + rCHAR.Skip(0x18); + + if (ModelIdx == 0) + { + rChar.pModel = gpResourceStore->LoadResource(ModelID); + rChar.pSkin = gpResourceStore->LoadResource(SkinID); + } + else + { + rChar.DKDependencies.push_back(ModelID); + rChar.DKDependencies.push_back(SkinID); + } + } + + // Animations + u32 NumAnims = rCHAR.ReadLong(); + + for (u32 AnimIdx = 0; AnimIdx < NumAnims; AnimIdx++) + { + rCHAR.ReadString(); + CAssetID AnimID(rCHAR, eReturns); + rCHAR.Skip(0x25); + rChar.DKDependencies.push_back(AnimID); + } + + // The only other thing we care about right now is the dependency list. If this file doesn't have a dependency list, exit out. + if ((Flag & 0x10) == 0) + return pSet; + + // Anim ID Map + if (Flag & 0x20) + { + u32 NumIDs = rCHAR.ReadLong(); + rCHAR.Skip(NumIDs * 4); + } + + // Transitions + if (Flag & 0x80) + { + u32 NumAdditiveAnims = rCHAR.ReadLong(); + rCHAR.Skip(NumAdditiveAnims * 0x10); + + u32 NumTransitionTypes = rCHAR.ReadLong(); + + for (u32 TypeIdx = 0; TypeIdx < NumTransitionTypes; TypeIdx++) + { + u16 Type = rCHAR.ReadShort(); + + switch (Type) + { + case 0: + break; + case 1: + case 2: + rCHAR.Skip(9); + break; + case 3: + rCHAR.Skip(0xC); + break; + default: + Log::FileError(rCHAR.GetSourceString(), rCHAR.Tell() - 2, "Invalid transition type: " + TString::FromInt32(Type, 0, 10)); + return pSet; + } + } + + u32 NumFullTransitions = rCHAR.ReadLong(); + rCHAR.Skip(NumFullTransitions * 0xC); + + u32 NumHalfTransitions = rCHAR.ReadLong(); + rCHAR.Skip(NumHalfTransitions * 0x8); + + rCHAR.Skip(0x8); + } + + // Transform Bits + if (Flag & 0x40) + { + u32 NumTransformBits = rCHAR.ReadLong(); + rCHAR.Skip(NumTransformBits); + } + + u32 NumUnknown = rCHAR.ReadLong(); + rCHAR.Skip(NumUnknown * 4); + + // Skel Joint Sets + u32 NumSkelJointSets = rCHAR.ReadLong(); + + for (u32 SetIdx = 0; SetIdx < NumSkelJointSets; SetIdx++) + { + rCHAR.Skip(4); + u32 NumUnknown2 = rCHAR.ReadLong(); + rCHAR.Skip(0x20 + NumUnknown2); + } + + // Resources + if (Flag & 0x10) + { + // Don't need the extensions + u32 NumExtensions = rCHAR.ReadLong(); + rCHAR.Skip(NumExtensions * 4); + + u32 NumResources = rCHAR.ReadLong(); + + for (u32 ResIdx = 0; ResIdx < NumResources; ResIdx++) + { + CAssetID ResID(rCHAR, eReturns); + rCHAR.Skip(3); + rChar.DKDependencies.push_back(ResID); + } + } + return pSet; } diff --git a/src/Core/Resource/Factory/CResourceFactory.h b/src/Core/Resource/Factory/CResourceFactory.h index 6e9bd1de..23c79573 100644 --- a/src/Core/Resource/Factory/CResourceFactory.h +++ b/src/Core/Resource/Factory/CResourceFactory.h @@ -100,9 +100,11 @@ public: case eWorld: pRes = CWorldLoader::LoadMLVL(rInput, pEntry); break; case eStateMachine: - // AFSM and FSMC currently unsupported + // AFSM currently unsupported if (pEntry->Game() == eCorruptionProto || pEntry->Game() == eCorruption) pRes = CUnsupportedFormatLoader::LoadFSM2(rInput, pEntry); + else if (pEntry->Game() == eReturns) + pRes = CUnsupportedFormatLoader::LoadFSMC(rInput, pEntry); break; case eBurstFireData: @@ -114,6 +116,7 @@ public: case eParticleDecal: case eParticleWeapon: case eParticleCollisionResponse: + case eParticleTransform: case eUserEvaluatorData: pRes = CUnsupportedParticleLoader::LoadParticle(rInput, pEntry); break; diff --git a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp index 4305db2a..6218f15c 100644 --- a/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedFormatLoader.cpp @@ -333,6 +333,22 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadFSM2(IInputStream& rFSM2, CResou return pOut; } +CDependencyGroup* CUnsupportedFormatLoader::LoadFSMC(IInputStream& rFSMC, CResourceEntry *pEntry) +{ + CFourCC Magic = rFSMC.ReadLong(); + ASSERT(Magic == FOURCC('FSMC')); + + CDependencyGroup *pGroup = new CDependencyGroup(pEntry); + + std::list AssetList; + PerformCheating(rFSMC, pEntry->Game(), AssetList); + + for (auto Iter = AssetList.begin(); Iter != AssetList.end(); Iter++) + pGroup->AddDependency(*Iter); + + return pGroup; +} + CDependencyGroup* CUnsupportedFormatLoader::LoadHIER(IInputStream& rHIER, CResourceEntry *pEntry) { CFourCC Magic = rHIER.ReadLong(); diff --git a/src/Core/Resource/Factory/CUnsupportedFormatLoader.h b/src/Core/Resource/Factory/CUnsupportedFormatLoader.h index 63870b4f..8b779896 100644 --- a/src/Core/Resource/Factory/CUnsupportedFormatLoader.h +++ b/src/Core/Resource/Factory/CUnsupportedFormatLoader.h @@ -20,6 +20,7 @@ public: static CDependencyGroup* LoadDUMB(IInputStream& rDUMB, CResourceEntry *pEntry); static CDependencyGroup* LoadFRME(IInputStream& rFRME, CResourceEntry *pEntry); static CDependencyGroup* LoadFSM2(IInputStream& rFSM2, CResourceEntry *pEntry); + static CDependencyGroup* LoadFSMC(IInputStream& rFSMC, CResourceEntry *pEntry); static CDependencyGroup* LoadHIER(IInputStream& rHIER, CResourceEntry *pEntry); static CDependencyGroup* LoadHINT(IInputStream& rHINT, CResourceEntry *pEntry); static CMapArea* LoadMAPA(IInputStream& rMAPA, CResourceEntry *pEntry); diff --git a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp index 94fea0e8..60eaaf97 100644 --- a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp @@ -11,15 +11,24 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) switch (Param.ToLong()) { - // Bool + // Bool Constant case FOURCC('AAPH'): case FOURCC('CIND'): case FOURCC('DBPS'): + case FOURCC('DDIT'): + case FOURCC('DFOG'): + case FOURCC('EMTU'): + case FOURCC('FXBI'): + case FOURCC('FXBT'): case FOURCC('FXLL'): case FOURCC('INDM'): + case FOURCC('INDP'): + case FOURCC('ITPE'): case FOURCC('LINE'): case FOURCC('LIT_'): case FOURCC('MBLR'): + case FOURCC('NTIK'): + case FOURCC('ONET'): case FOURCC('OPTS'): case FOURCC('ORNT'): case FOURCC('ORTC'): @@ -30,6 +39,7 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('PMUS'): case FOURCC('RDOP'): case FOURCC('RSOP'): + case FOURCC('SCNV'): case FOURCC('SORT'): case FOURCC('STOP'): case FOURCC('VGD1'): @@ -42,7 +52,7 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('VMD4'): case FOURCC('VMPC'): case FOURCC('ZBUF'): - ParseBoolFunction(rPART); + ParseBool(rPART); break; // Bitfield @@ -55,22 +65,32 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('AMSC'): case FOURCC('CSSD'): case FOURCC('HJAK'): + case FOURCC('IAV0'): + case FOURCC('IAV1'): + case FOURCC('IAV2'): + case FOURCC('IAV3'): case FOURCC('LFOT'): case FOURCC('LTME'): case FOURCC('LTYP'): case FOURCC('MAXP'): case FOURCC('MBDM'): case FOURCC('MBSP'): + case FOURCC('MSLT'): case FOURCC('NCSY'): case FOURCC('NDSY'): case FOURCC('PBDM'): case FOURCC('PISY'): case FOURCC('PSLT'): case FOURCC('PSWT'): + case FOURCC('PWGT'): + case FOURCC('SCTR'): case FOURCC('SEED'): case FOURCC('SESD'): case FOURCC('SISY'): case FOURCC('SSSD'): + case FOURCC('SSWT'): + case FOURCC('SVI0'): + case FOURCC('SVI1'): case FOURCC('VSPC'): case FOURCC('XJAK'): case FOURCC('XTAD'): @@ -87,6 +107,7 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('ADV7'): case FOURCC('ADV8'): case FOURCC('ADV9'): + case FOURCC('DBIS'): case FOURCC('EADV'): case FOURCC('FXBR'): case FOURCC('GRTE'): @@ -99,11 +120,15 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('ROTA'): case FOURCC('SIZE'): case FOURCC('SVEO'): + case FOURCC('SVR0'): + case FOURCC('SVR1'): + case FOURCC('SVR2'): case FOURCC('WIDT'): ParseFloatFunction(rPART); break; // Vector + case FOURCC('FXBM'): case FOURCC('FXBO'): case FOURCC('ILOC'): case FOURCC('IVEC'): @@ -111,16 +136,21 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('LOFF'): case FOURCC('PMOP'): case FOURCC('PMOV'): + case FOURCC('PMPV'): case FOURCC('PMRT'): case FOURCC('PMSC'): case FOURCC('POFS'): case FOURCC('PSIV'): case FOURCC('PSOV'): + case FOURCC('SAXS'): case FOURCC('SEPO'): case FOURCC('SSPO'): + case FOURCC('SVV0'): + case FOURCC('SVV1'): case FOURCC('VAV1'): case FOURCC('VAV2'): case FOURCC('VAV3'): + case FOURCC('VAV4'): ParseVectorFunction(rPART); break; @@ -134,9 +164,15 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) break; // Color + case FOURCC('CAV0'): + case FOURCC('CAV1'): + case FOURCC('CAV2'): + case FOURCC('CAV3'): case FOURCC('COLR'): case FOURCC('LCLR'): case FOURCC('PMCL'): + case FOURCC('SVC0'): + case FOURCC('SVC1'): ParseColorFunction(rPART); break; @@ -160,6 +196,15 @@ bool CUnsupportedParticleLoader::ParseParticleParameter(IInputStream& rPART) case FOURCC('ICTS'): case FOURCC('IDTS'): case FOURCC('IITS'): + case FOURCC('MDL1'): + case FOURCC('MDL2'): + case FOURCC('MDL3'): + case FOURCC('MDL4'): + case FOURCC('MDL5'): + case FOURCC('MDL6'): + case FOURCC('MDL7'): + case FOURCC('MDL8'): + case FOURCC('MDL9'): case FOURCC('PMDL'): case FOURCC('SELC'): case FOURCC('SSWH'): @@ -184,7 +229,7 @@ bool CUnsupportedParticleLoader::ParseElectricParameter(IInputStream& rELSC) switch (Param.ToLong()) { case FOURCC('ZERY'): - ParseBoolFunction(rELSC); + ParseBool(rELSC); break; case FOURCC('DFLG'): @@ -272,7 +317,7 @@ bool CUnsupportedParticleLoader::ParseSpawnParameter(IInputStream& rSPSC) case FOURCC('IGLT'): case FOURCC('VMD1'): case FOURCC('VMD2'): - ParseBoolFunction(rSPSC); + ParseBool(rSPSC); break; case FOURCC('GIVL'): @@ -331,13 +376,15 @@ bool CUnsupportedParticleLoader::ParseSwooshParameter(IInputStream& rSWHC) case FOURCC('CROS'): case FOURCC('LLRD'): case FOURCC('ORNT'): + case FOURCC('PTMG'): + case FOURCC('SCNV'): case FOURCC('SROT'): case FOURCC('TEXW'): case FOURCC('VLS1'): case FOURCC('VLS2'): case FOURCC('WIRE'): case FOURCC('ZBUF'): - ParseBoolFunction(rSWHC); + ParseBool(rSWHC); break; case FOURCC('DFLG'): @@ -405,7 +452,7 @@ bool CUnsupportedParticleLoader::ParseDecalParameter(IInputStream& rDPSC) case FOURCC('2ADD'): case FOURCC('DMAB'): case FOURCC('DMOO'): - ParseBoolFunction(rDPSC); + ParseBool(rDPSC); break; case FOURCC('1LFT'): @@ -489,7 +536,7 @@ bool CUnsupportedParticleLoader::ParseWeaponParameter(IInputStream& rWPSC) case FOURCC('SWTR'): case FOURCC('TCND'): case FOURCC('VMD2'): - ParseBoolFunction(rWPSC); + ParseBool(rWPSC); break; case FOURCC('PSLT'): @@ -798,8 +845,60 @@ bool CUnsupportedParticleLoader::ParseUserEvaluatorParameter(IInputStream& rUSRC return true; } +bool CUnsupportedParticleLoader::ParseTransformParameter(IInputStream& rXFSC) +{ + u32 ParamOffset = rXFSC.Tell(); + CFourCC Param = rXFSC.ReadLong(); + if (Param == FOURCC('_END')) return false; + + switch (Param.ToLong()) + { + case FOURCC('IAV0'): + case FOURCC('IAV1'): + case FOURCC('IAV2'): + case FOURCC('IAV3'): + ParseIntFunction(rXFSC); + break; + + case FOURCC('ADV1'): + case FOURCC('ADV2'): + case FOURCC('ADV3'): + case FOURCC('ADV4'): + case FOURCC('ADV5'): + case FOURCC('ADV6'): + case FOURCC('ADV7'): + case FOURCC('ADV8'): + case FOURCC('ADV9'): + case FOURCC('EFSC'): + ParseFloatFunction(rXFSC); + break; + + case FOURCC('EOFS'): + case FOURCC('SOFS'): + case FOURCC('VAV1'): + case FOURCC('VAV2'): + case FOURCC('VAV3'): + case FOURCC('VAV4'): + ParseVectorFunction(rXFSC); + break; + + case FOURCC('EROT'): + case FOURCC('ROT0'): + case FOURCC('SROT'): + ParseRotationFunction(rXFSC); + break; + + default: + Log::FileError(rXFSC.GetSourceString(), ParamOffset, "Unknown XFSC parameter: " + Param.ToString()); + DEBUG_BREAK; + return false; + } + + return true; +} + // ************ FUNCTION LOADING ************ -void CUnsupportedParticleLoader::ParseBoolFunction(IInputStream& rFile) +void CUnsupportedParticleLoader::ParseBool(IInputStream& rFile) { u32 FuncOffset = rFile.Tell(); CFourCC Func = rFile.ReadLong(); @@ -813,6 +912,38 @@ void CUnsupportedParticleLoader::ParseBoolFunction(IInputStream& rFile) case FOURCC('NONE'): break; + default: + Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown bool constant function: " + Func.ToString()); + DEBUG_BREAK; + break; + } +} + +void CUnsupportedParticleLoader::ParseBoolFunction(IInputStream& rFile) +{ + u32 FuncOffset = rFile.Tell(); + CFourCC Func = rFile.ReadLong(); + + switch (Func.ToLong()) + { + case FOURCC('CNST'): + rFile.Seek(0x1, SEEK_CUR); + break; + + case FOURCC('MIRR'): + case FOURCC('P50H'): + break; + + case FOURCC('EQUL'): + case FOURCC('LTHN'): + ParseFloatFunction(rFile); + ParseFloatFunction(rFile); + break; + + case FOURCC('NORM'): + ParseVectorFunction(rFile); + break; + default: Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown bool function: " + Func.ToString()); DEBUG_BREAK; @@ -837,6 +968,10 @@ void CUnsupportedParticleLoader::ParseIntFunction(IInputStream& rFile) case FOURCC('GAPC'): case FOURCC('GEMT'): case FOURCC('GTCP'): + case FOURCC('PAP0'): + case FOURCC('PAP1'): + case FOURCC('PAP2'): + case FOURCC('PAP3'): case FOURCC('PCRT'): case FOURCC('PDET'): break; @@ -897,6 +1032,12 @@ void CUnsupportedParticleLoader::ParseIntFunction(IInputStream& rFile) ParseFloatFunction(rFile); break; + case FOURCC('BNID'): + rFile.Seek(0x4, SEEK_CUR); + rFile.ReadString(); + ParseBool(rFile); + break; + default: Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown int function: " + Func.ToString()); DEBUG_BREAK; @@ -924,6 +1065,15 @@ void CUnsupportedParticleLoader::ParseFloatFunction(IInputStream& rFile) case FOURCC('PAP9'): case FOURCC('PEA0'): case FOURCC('PRLW'): + case FOURCC('PSA0'): + case FOURCC('PSA1'): + case FOURCC('PSA2'): + case FOURCC('PSC0'): + case FOURCC('PSC1'): + case FOURCC('PSI0'): + case FOURCC('PSI1'): + case FOURCC('PSV0'): + case FOURCC('PSV1'): case FOURCC('PSLL'): break; @@ -954,7 +1104,6 @@ void CUnsupportedParticleLoader::ParseFloatFunction(IInputStream& rFile) ParseFloatFunction(rFile); break; - case FOURCC('CEXT'): case FOURCC('OCSP'): ParseIntFunction(rFile); break; @@ -1063,10 +1212,21 @@ void CUnsupportedParticleLoader::ParseFloatFunction(IInputStream& rFile) break; case FOURCC('TOCS'): + ParseBool(rFile); + ParseIntFunction(rFile); + ParseIntFunction(rFile); + ParseIntFunction(rFile); + break; + + case FOURCC('CREL'): ParseBoolFunction(rFile); + ParseFloatFunction(rFile); + ParseFloatFunction(rFile); + break; + + case FOURCC('CEXT'): ParseIntFunction(rFile); - ParseIntFunction(rFile); - ParseIntFunction(rFile); + if (mpGroup->Game() >= eReturns) ParseFloatFunction(rFile); break; default: @@ -1146,10 +1306,12 @@ void CUnsupportedParticleLoader::ParseVectorFunction(IInputStream& rFile) ParseVectorFunction(rFile); break; + case FOURCC('CMPS'): case FOURCC('NONE'): case FOURCC('PAP1'): case FOURCC('PAP2'): case FOURCC('PAP3'): + case FOURCC('PAP4'): case FOURCC('PENV'): case FOURCC('PETR'): case FOURCC('PEVL'): @@ -1160,10 +1322,11 @@ void CUnsupportedParticleLoader::ParseVectorFunction(IInputStream& rFile) case FOURCC('PLOC'): case FOURCC('PNCV'): case FOURCC('PSOF'): - case FOURCC('PSOU'): case FOURCC('PSOR'): + case FOURCC('PSOU'): case FOURCC('PSTR'): case FOURCC('PVEL'): + case FOURCC('SLOC'): break; case FOURCC('PULS'): @@ -1178,6 +1341,28 @@ void CUnsupportedParticleLoader::ParseVectorFunction(IInputStream& rFile) ParseFloatFunction(rFile); break; + case FOURCC('BNPS'): + case FOURCC('BNSC'): + ParseIntFunction(rFile); + break; + + case FOURCC('CVEC'): + ParseBoolFunction(rFile); + ParseVectorFunction(rFile); + ParseVectorFunction(rFile); + break; + + case FOURCC('IRTV'): + case FOURCC('ROTV'): + ParseRotationFunction(rFile); + ParseVectorFunction(rFile); + break; + + case FOURCC('VEXT'): + ParseIntFunction(rFile); + ParseVectorFunction(rFile); + break; + default: Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown vector function: " + Func.ToString()); DEBUG_BREAK; @@ -1200,7 +1385,7 @@ void CUnsupportedParticleLoader::ParseModVectorFunction(IInputStream& rFile) ParseVectorFunction(rFile); ParseFloatFunction(rFile); ParseFloatFunction(rFile); - ParseBoolFunction(rFile); + ParseBool(rFile); break; case FOURCC('BOXV'): @@ -1228,7 +1413,7 @@ void CUnsupportedParticleLoader::ParseModVectorFunction(IInputStream& rFile) ParseFloatFunction(rFile); ParseFloatFunction(rFile); ParseFloatFunction(rFile); - ParseBoolFunction(rFile); + ParseBool(rFile); break; case FOURCC('EXPL'): @@ -1330,6 +1515,10 @@ void CUnsupportedParticleLoader::ParseColorFunction(IInputStream& rFile) break; case FOURCC('NONE'): + case FOURCC('PAP0'): + case FOURCC('PAP1'): + case FOURCC('PAP2'): + case FOURCC('PAP3'): case FOURCC('PCOL'): break; @@ -1352,6 +1541,64 @@ void CUnsupportedParticleLoader::ParseColorFunction(IInputStream& rFile) } } +void CUnsupportedParticleLoader::ParseRotationFunction(IInputStream& rFile) +{ + u32 FuncOffset = rFile.Tell(); + CFourCC Func = rFile.ReadLong(); + + switch (Func.ToLong()) + { + case FOURCC('NONE'): + case FOURCC('RLCL'): + case FOURCC('RSYS'): + break; + + case FOURCC('CNST'): + rFile.Seek(0x10, SEEK_CUR); + break; + + case FOURCC('BNRT'): + ParseIntFunction(rFile); + break; + + case FOURCC('CROT'): + ParseBoolFunction(rFile); + ParseRotationFunction(rFile); + ParseRotationFunction(rFile); + break; + + case FOURCC('ISWT'): + case FOURCC('RADD'): + case FOURCC('RADN'): + case FOURCC('RSBN'): + case FOURCC('RSUB'): + ParseRotationFunction(rFile); + ParseRotationFunction(rFile); + break; + + case FOURCC('KPIN'): + ParseRotationFunction(rFile); + break; + + case FOURCC('RAXZ'): + ParseVectorFunction(rFile); + ParseVectorFunction(rFile); + ParseRotationFunction(rFile); + break; + + case FOURCC('REUL'): + ParseFloatFunction(rFile); + ParseFloatFunction(rFile); + ParseFloatFunction(rFile); + break; + + default: + Log::FileError(rFile.GetSourceString(), FuncOffset, "Unknown rotation function: " + Func.ToString()); + DEBUG_BREAK; + break; + } +} + void CUnsupportedParticleLoader::ParseUVFunction(IInputStream& rFile) { u32 FuncOffset = rFile.Tell(); @@ -1373,7 +1620,7 @@ void CUnsupportedParticleLoader::ParseUVFunction(IInputStream& rFile) ParseIntFunction(rFile); ParseIntFunction(rFile); ParseIntFunction(rFile); - ParseBoolFunction(rFile); + ParseBool(rFile); break; case FOURCC('TEXP'): @@ -1415,7 +1662,7 @@ void CUnsupportedParticleLoader::ParseEmitterFunction(IInputStream& rFile) ParseVectorFunction(rFile); ParseVectorFunction(rFile); ParseFloatFunction(rFile); - ParseBoolFunction(rFile); + ParseBool(rFile); break; case FOURCC('PLNE'): @@ -1540,15 +1787,24 @@ void CUnsupportedParticleLoader::ParseKeyframeEmitterData(IInputStream& rFile, c // ************ STATIC ************ CDependencyGroup* CUnsupportedParticleLoader::LoadParticle(IInputStream& rFile, CResourceEntry *pEntry) { - CFourCC Magic = rFile.ReadLong(); - - // Loop through particle functions CUnsupportedParticleLoader Loader; Loader.mpGroup = new CDependencyGroup(pEntry); - if (pEntry->Game() >= eReturns) - return Loader.mpGroup; + // Validate DKCR asset header + if (pEntry->Game() == eReturns) + { + u32 AssetHeader = rFile.ReadLong(); + if (AssetHeader != 0x6E190001) + { + Log::Error("Invalid DKCR particle header: " + TString::HexString(AssetHeader)); + return Loader.mpGroup; + } + } + + CFourCC Magic = rFile.ReadLong(); + + // Loop through particle functions while (true) { bool ShouldContinue = false; @@ -1565,6 +1821,7 @@ CDependencyGroup* CUnsupportedParticleLoader::LoadParticle(IInputStream& rFile, case FOURCC('CRSM'): ShouldContinue = Loader.ParseCollisionResponseParameter(rFile); break; case FOURCC('BFRE'): ShouldContinue = Loader.ParseBurstFireParameter(rFile); break; case FOURCC('USER'): ShouldContinue = Loader.ParseUserEvaluatorParameter(rFile); break; + case FOURCC('XFSM'): ShouldContinue = Loader.ParseTransformParameter(rFile); break; default: Log::Error("Unrecognized particle system magic: " + Magic.ToString()); diff --git a/src/Core/Resource/Factory/CUnsupportedParticleLoader.h b/src/Core/Resource/Factory/CUnsupportedParticleLoader.h index 0a6b3f44..d58d85aa 100644 --- a/src/Core/Resource/Factory/CUnsupportedParticleLoader.h +++ b/src/Core/Resource/Factory/CUnsupportedParticleLoader.h @@ -21,8 +21,10 @@ class CUnsupportedParticleLoader bool ParseCollisionResponseParameter(IInputStream& rCRSC); bool ParseBurstFireParameter(IInputStream& rBFRC); bool ParseUserEvaluatorParameter(IInputStream& rUSRC); + bool ParseTransformParameter(IInputStream& rXFSC); // Function Loading + void ParseBool(IInputStream& rFile); void ParseBoolFunction(IInputStream& rFile); void ParseBitfieldFunction(IInputStream& rFile); void ParseIntFunction(IInputStream& rFile); @@ -30,6 +32,7 @@ class CUnsupportedParticleLoader void ParseVectorFunction(IInputStream& rFile); void ParseModVectorFunction(IInputStream& rFile); void ParseColorFunction(IInputStream& rFile); + void ParseRotationFunction(IInputStream& rFile); void ParseUVFunction(IInputStream& rFile); void ParseEmitterFunction(IInputStream& rFile); void ParseSoundFunction(IInputStream& rFile); diff --git a/templates/Properties.xml b/templates/Properties.xml index cb746c95..bf5db53a 100644 --- a/templates/Properties.xml +++ b/templates/Properties.xml @@ -230,7 +230,7 @@ - +