From 2f2ec13ced763be2019ff35524b120cdce038cd7 Mon Sep 17 00:00:00 2001 From: parax0 Date: Wed, 29 Jun 2016 23:23:49 -0600 Subject: [PATCH] Fixed CHAR files failing to load --- src/Core/GameProject/CResourceEntry.cpp | 42 ++++++++++---------- src/Core/GameProject/CResourceStore.cpp | 35 ++++++++++++---- src/Core/GameProject/CResourceStore.h | 4 +- src/Core/Resource/CResource.cpp | 2 +- src/Core/Resource/CResource.h | 2 +- src/Core/Resource/Factory/CAnimSetLoader.cpp | 14 +++++++ src/Core/Resource/Factory/CAnimSetLoader.h | 1 + 7 files changed, 66 insertions(+), 34 deletions(-) diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index 5acdbdd0..a7a869d4 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -96,7 +96,12 @@ CResource* CResourceEntry::Load() { // todo: load raw if (mpResource) return mpResource; - if (!HasCookedVersion()) return nullptr; + + if (!HasCookedVersion()) + { + Log::Error("Couldn't locate resource: " + CookedAssetPath(true)); + return nullptr; + } CFileInStream File(CookedAssetPath().ToStdString(), IOUtil::eBigEndian); if (!File.IsValid()) @@ -116,27 +121,20 @@ CResource* CResourceEntry::Load(IInputStream& rInput) switch (mType) { - case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break; - case eArea: mpResource = CAreaLoader::LoadMREA(rInput, this); break; - case eDynamicCollision: mpResource = CCollisionLoader::LoadDCLN(rInput, this); break; - case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break; - case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break; - case eScan: mpResource = CScanLoader::LoadSCAN(rInput, this); break; - case eSkeleton: mpResource = CSkeletonLoader::LoadCINF(rInput, this); break; - case eSkin: mpResource = CSkinLoader::LoadCSKR(rInput, this); break; - case eStaticGeometryMap: mpResource = CPoiToWorldLoader::LoadEGMC(rInput, this); break; - case eStringTable: mpResource = CStringLoader::LoadSTRG(rInput, this); break; - case eTexture: mpResource = CTextureDecoder::LoadTXTR(rInput, this); break; - case eWorld: mpResource = CWorldLoader::LoadMLVL(rInput, this); break; - - case eAnimSet: - if (mGame <= eEchoes) - mpResource = CAnimSetLoader::LoadANCS(rInput, this); - else - mpResource = CAnimSetLoader::LoadCHAR(rInput, this); - break; - - default: mpResource = new CResource(this); break; + case eAnimation: mpResource = CAnimationLoader::LoadANIM(rInput, this); break; + case eAnimSet: mpResource = CAnimSetLoader::LoadANCSOrCHAR(rInput, this); break; + case eArea: mpResource = CAreaLoader::LoadMREA(rInput, this); break; + case eDynamicCollision: mpResource = CCollisionLoader::LoadDCLN(rInput, this); break; + case eFont: mpResource = CFontLoader::LoadFONT(rInput, this); break; + case eModel: mpResource = CModelLoader::LoadCMDL(rInput, this); break; + case eScan: mpResource = CScanLoader::LoadSCAN(rInput, this); break; + case eSkeleton: mpResource = CSkeletonLoader::LoadCINF(rInput, this); break; + case eSkin: mpResource = CSkinLoader::LoadCSKR(rInput, this); break; + case eStaticGeometryMap: mpResource = CPoiToWorldLoader::LoadEGMC(rInput, this); break; + case eStringTable: mpResource = CStringLoader::LoadSTRG(rInput, this); break; + case eTexture: mpResource = CTextureDecoder::LoadTXTR(rInput, this); break; + case eWorld: mpResource = CWorldLoader::LoadMLVL(rInput, this); break; + default: mpResource = new CResource(this); break; } return mpResource; diff --git a/src/Core/GameProject/CResourceStore.cpp b/src/Core/GameProject/CResourceStore.cpp index 825e7771..3272ccc6 100644 --- a/src/Core/GameProject/CResourceStore.cpp +++ b/src/Core/GameProject/CResourceStore.cpp @@ -232,14 +232,14 @@ bool CResourceStore::RegisterResource(const CUniqueID& rkID, EResType Type, cons } } -CResourceEntry* CResourceStore::CreateTransientEntry(EResType Type, const TWideString& rkDir /*= L""*/, const TWideString& rkFileName /*= L""*/) +CResourceEntry* CResourceStore::RegisterTransientResource(EResType Type, const TWideString& rkDir /*= L""*/, const TWideString& rkFileName /*= L""*/) { CResourceEntry *pEntry = new CResourceEntry(this, CUniqueID::RandomID(), rkDir, rkFileName, Type, true); mResourceEntries[pEntry->ID()] = pEntry; return pEntry; } -CResourceEntry* CResourceStore::CreateTransientEntry(EResType Type, const CUniqueID& rkID, const TWideString& rkDir /*=L ""*/, const TWideString& rkFileName /*= L""*/) +CResourceEntry* CResourceStore::RegisterTransientResource(EResType Type, const CUniqueID& rkID, const TWideString& rkDir /*=L ""*/, const TWideString& rkFileName /*= L""*/) { CResourceEntry *pEntry = new CResourceEntry(this, rkID, rkDir, rkFileName, Type, true); mResourceEntries[rkID] = pEntry; @@ -264,7 +264,7 @@ CResource* CResourceStore::LoadResource(const CUniqueID& rkID, const CFourCC& rk CMemoryInStream MemStream(DataBuffer.data(), DataBuffer.size(), IOUtil::eBigEndian); EResType Type = CResource::ResTypeForExtension(rkType); - CResourceEntry *pEntry = CreateTransientEntry(Type, rkID); + CResourceEntry *pEntry = RegisterTransientResource(Type, rkID); CResource *pRes = pEntry->Load(MemStream); if (pRes) mLoadedResources[rkID] = pEntry; return pRes; @@ -282,9 +282,15 @@ CResource* CResourceStore::LoadResource(const CUniqueID& rkID, const CFourCC& rk if (Type != eInvalidResType) { - TWideString Name = rkID.ToString().ToUTF16(); - CResourceEntry *pEntry = CreateTransientEntry(Type, mTransientLoadDir, Name); - CResource *pRes = pEntry->Load(); + // Note the entry may not be able to find the resource on its own (due to not knowing what game + // it is) so we will attempt to open the file stream ourselves and pass it to the entry instead. + TString Name = rkID.ToString(); + CResourceEntry *pEntry = RegisterTransientResource(Type, mTransientLoadDir, Name.ToUTF16()); + + TString Path = mTransientLoadDir.ToUTF8() + Name + "." + rkType.ToString(); + CFileInStream File(Path.ToStdString(), IOUtil::eBigEndian); + CResource *pRes = pEntry->Load(File); + if (pRes) mLoadedResources[rkID] = pEntry; return pRes; } @@ -318,10 +324,22 @@ CResource* CResourceStore::LoadResource(const TString& rkPath) return nullptr; } + // Open file + CFileInStream File(rkPath.ToStdString(), IOUtil::eBigEndian); + + if (!File.IsValid()) + { + Log::Error("Unable to load resource; couldn't open file: " + rkPath); + return nullptr; + } + + // Load resource TString OldTransientDir = mTransientLoadDir; mTransientLoadDir = Dir; - CResourceEntry *pEntry = CreateTransientEntry(Type, ID, Dir, Name); - CResource *pRes = pEntry->Load(); + + CResourceEntry *pEntry = RegisterTransientResource(Type, ID, Dir, Name); + CResource *pRes = pEntry->Load(File); + if (pRes) mLoadedResources[ID] = pEntry; mTransientLoadDir = OldTransientDir; @@ -375,6 +393,7 @@ void CResourceStore::DestroyUnreferencedResources() { It = mLoadedResources.erase(It); NumDeleted++; + if (It == mLoadedResources.end()) break; } } } diff --git a/src/Core/GameProject/CResourceStore.h b/src/Core/GameProject/CResourceStore.h index 328346ab..b2519c65 100644 --- a/src/Core/GameProject/CResourceStore.h +++ b/src/Core/GameProject/CResourceStore.h @@ -47,8 +47,8 @@ public: bool RegisterResource(const CUniqueID& rkID, EResType Type, const TWideString& rkDir, const TWideString& rkFileName); CResourceEntry* FindEntry(const CUniqueID& rkID) const; - CResourceEntry* CreateTransientEntry(EResType Type, const TWideString& rkDir = L"", const TWideString& rkFileName = L""); - CResourceEntry* CreateTransientEntry(EResType Type, const CUniqueID& rkID, const TWideString& rkDir = L"", const TWideString& rkFileName = L""); + CResourceEntry* RegisterTransientResource(EResType Type, const TWideString& rkDir = L"", const TWideString& rkFileName = L""); + CResourceEntry* RegisterTransientResource(EResType Type, const CUniqueID& rkID, const TWideString& rkDir = L"", const TWideString& rkFileName = L""); CResource* LoadResource(const CUniqueID& rkID, const CFourCC& rkType); CResource* LoadResource(const TString& rkPath); diff --git a/src/Core/Resource/CResource.cpp b/src/Core/Resource/CResource.cpp index c7278f48..c3090b08 100644 --- a/src/Core/Resource/CResource.cpp +++ b/src/Core/Resource/CResource.cpp @@ -165,7 +165,7 @@ REGISTER_RESOURCE_TYPE(ATBL, eAudioLookupTable, ePrimeDemo, eCorruption) REGISTER_RESOURCE_TYPE(BFRC, eBurstFireData, eCorruptionProto, eCorruption) REGISTER_RESOURCE_TYPE(CAAD, eUnknown_CAAD, eCorruption, eCorruption) REGISTER_RESOURCE_TYPE(CAUD, eAudioMacro, eCorruptionProto, eReturns) -REGISTER_RESOURCE_TYPE(CHAR, eCharacter, eCorruptionProto, eReturns) +REGISTER_RESOURCE_TYPE(CHAR, eAnimSet, eCorruptionProto, eReturns) REGISTER_RESOURCE_TYPE(CINF, eSkeleton, ePrimeDemo, eReturns) REGISTER_RESOURCE_TYPE(CMDL, eModel, ePrimeDemo, eReturns) REGISTER_RESOURCE_TYPE(CRSC, eParticleCollisionResponse, ePrimeDemo, eCorruption) diff --git a/src/Core/Resource/CResource.h b/src/Core/Resource/CResource.h index 722bb146..71a2ee28 100644 --- a/src/Core/Resource/CResource.h +++ b/src/Core/Resource/CResource.h @@ -38,7 +38,7 @@ public: CResource(CResourceEntry *pEntry = 0) : mpEntry(pEntry), mRefCount(0) { - if (!mpEntry) mpEntry = gResourceStore.CreateTransientEntry(Type()); + if (!mpEntry) mpEntry = gResourceStore.RegisterTransientResource(Type()); } virtual ~CResource() {} diff --git a/src/Core/Resource/Factory/CAnimSetLoader.cpp b/src/Core/Resource/Factory/CAnimSetLoader.cpp index 9615f52d..4a5e5a71 100644 --- a/src/Core/Resource/Factory/CAnimSetLoader.cpp +++ b/src/Core/Resource/Factory/CAnimSetLoader.cpp @@ -194,6 +194,20 @@ void CAnimSetLoader::LoadHalfTransition(IInputStream& rANCS) } // ************ STATIC ************ +CAnimSet* CAnimSetLoader::LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry) +{ + if (!rFile.IsValid()) return nullptr; + u8 Test = rFile.PeekByte(); + + if (Test == 0x3 || Test == 0x5 || Test == 0x59) + return LoadCHAR(rFile, pEntry); + else if (Test == 0x0) + return LoadANCS(rFile, pEntry); + + Log::Error("Failed to determine animset format for " + rFile.GetSourceString() + "; first byte is " + TString::HexString(Test, 2)); + return nullptr; +} + CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry) { if (!rANCS.IsValid()) return nullptr; diff --git a/src/Core/Resource/Factory/CAnimSetLoader.h b/src/Core/Resource/Factory/CAnimSetLoader.h index 60a47bd2..c99d4f4a 100644 --- a/src/Core/Resource/Factory/CAnimSetLoader.h +++ b/src/Core/Resource/Factory/CAnimSetLoader.h @@ -42,6 +42,7 @@ class CAnimSetLoader void LoadHalfTransition(IInputStream& rANCS); public: + static CAnimSet* LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry); static CAnimSet* LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry); static CAnimSet* LoadCHAR(IInputStream& rCHAR, CResourceEntry *pEntry); };