From 7c3fb4174ff7f6072341fa582c730cd66ace264b Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Wed, 25 Oct 2017 19:37:46 -1000 Subject: [PATCH] Finish CPakFile and CResLoader --- DataSpec/DNAMP1/MLVL.cpp | 4 + DataSpec/SpecBase.cpp | 55 ++++++++-- DataSpec/SpecBase.hpp | 1 + DataSpec/SpecMP1.cpp | 27 +++-- Editor/ProjectResourceFactoryMP1.cpp | 52 +--------- Runtime/CFactoryMgr.cpp | 27 +++++ Runtime/CFactoryMgr.hpp | 15 +++ Runtime/CPakFile.cpp | 149 +++++++++++++++++++++++++++ Runtime/CPakFile.hpp | 42 +++++--- Runtime/CResLoader.cpp | 103 ++++++++++++------ Runtime/CResLoader.hpp | 17 +-- Runtime/IFactory.hpp | 4 + Runtime/MP1/CMakeLists.txt | 1 + Runtime/MP1/CPreFrontEnd.cpp | 5 +- Runtime/MP1/MP1.cpp | 99 ++++++++++++++++++ Runtime/MP1/MP1.hpp | 3 + Runtime/MP1/MP1OriginalIDs.cpp | 51 +++++++++ Runtime/MP1/MP1OriginalIDs.hpp | 27 +++++ hecl | 2 +- visigen/VISIBuilder.cpp | 1 + 20 files changed, 561 insertions(+), 124 deletions(-) create mode 100644 Runtime/MP1/MP1OriginalIDs.cpp create mode 100644 Runtime/MP1/MP1OriginalIDs.hpp diff --git a/DataSpec/DNAMP1/MLVL.cpp b/DataSpec/DNAMP1/MLVL.cpp index 0fb062fe9..03824d9b1 100644 --- a/DataSpec/DNAMP1/MLVL.cpp +++ b/DataSpec/DNAMP1/MLVL.cpp @@ -315,6 +315,10 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat } } + urde::SObjectTag pathTag = g_curSpec->buildTagFromPath(areaPath.ensureAuxInfo(_S("PATH")), btok); + if (pathTag.id.IsValid()) + areaOut.deps.emplace_back(pathTag.id.Value(), pathTag.type); + urde::SObjectTag tag = g_curSpec->buildTagFromPath(areaPath, btok); if (tag.id.IsValid()) areaOut.deps.emplace_back(tag.id.Value(), tag.type); diff --git a/DataSpec/SpecBase.cpp b/DataSpec/SpecBase.cpp index 9d3b20770..017b75150 100644 --- a/DataSpec/SpecBase.cpp +++ b/DataSpec/SpecBase.cpp @@ -365,6 +365,7 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path, } case hecl::BlenderConnection::BlendType::Actor: { + hecl::ProjectPath asGlob = path.getWithExtension(_S(".*"), true); hecl::BlenderConnection::DataStream ds = conn.beginData(); hecl::BlenderConnection::DataStream::Actor actor = ds.compileActorCharacterOnly(); for (auto& sub : actor.subtypes) @@ -374,20 +375,32 @@ void SpecBase::flattenDependencies(const hecl::ProjectPath& path, pathsOut.push_back(sub.mesh); hecl::SystemStringView chSysName(sub.name); - pathsOut.push_back(path.ensureAuxInfo(chSysName.sys_str() + _S(".CSKR"))); + pathsOut.push_back(asGlob.ensureAuxInfo(chSysName.sys_str() + _S(".CSKR"))); const auto& arm = actor.armatures[sub.armature]; hecl::SystemStringView armSysName(arm.name); - pathsOut.push_back(path.ensureAuxInfo(armSysName.sys_str() + _S(".CINF"))); + pathsOut.push_back(asGlob.ensureAuxInfo(armSysName.sys_str() + _S(".CINF"))); for (const auto& overlay : sub.overlayMeshes) { pathsOut.push_back(overlay.second); - pathsOut.push_back(path.ensureAuxInfo(chSysName.sys_str() + _S('.') + - overlay.first + _S(".CSKR"))); + pathsOut.push_back(asGlob.ensureAuxInfo(chSysName.sys_str() + _S('.') + + overlay.first + _S(".CSKR"))); } } } - break; + auto actNames = ds.getActionNames(); + for (const auto& act : actNames) + { + hecl::SystemStringView actSysName(act); + pathsOut.push_back(asGlob.ensureAuxInfo(actSysName.sys_str() + _S(".ANIM"))); + hecl::ProjectPath evntPath = asGlob.getWithExtension( + hecl::SysFormat(_S(".%s.evnt.yaml"), actSysName.c_str()).c_str(), true); + if (evntPath.isFile()) + pathsOut.push_back(evntPath); + } + + pathsOut.push_back(asGlob); + return; } case hecl::BlenderConnection::BlendType::Area: { @@ -439,6 +452,7 @@ bool SpecBase::canPackage(const hecl::ProjectPath& path) } void SpecBase::recursiveBuildResourceList(std::vector& listOut, + std::unordered_set& addedTags, const hecl::ProjectPath& path, hecl::BlenderToken& btok) { @@ -448,9 +462,24 @@ void SpecBase::recursiveBuildResourceList(std::vector& listOut { hecl::ProjectPath childPath(path, ent.m_name); if (ent.m_isDir) - recursiveBuildResourceList(listOut, childPath, btok); - else if (urde::SObjectTag tag = tagFromPath(childPath, btok)) - listOut.push_back(tag); + { + recursiveBuildResourceList(listOut, addedTags, childPath, btok); + } + else + { + std::vector subPaths; + flattenDependencies(childPath, subPaths, btok); + for (const auto& subPath : subPaths) + { + if (urde::SObjectTag tag = tagFromPath(subPath, btok)) + { + if (addedTags.find(tag) != addedTags.end()) + continue; + addedTags.insert(tag); + listOut.push_back(tag); + } + } + } } } @@ -535,7 +564,8 @@ void SpecBase::doPackage(const hecl::ProjectPath& path, const hecl::Database::Da else if (path.getPathType() == hecl::ProjectPath::Type::Directory) /* General PAK */ { /* Build resource list */ - recursiveBuildResourceList(buildList, path, btok); + std::unordered_set addedTags; + recursiveBuildResourceList(buildList, addedTags, path, btok); std::vector> nameList; /* Build name list */ @@ -556,12 +586,19 @@ void SpecBase::doPackage(const hecl::ProjectPath& path, const hecl::Database::Da /* Async cook resource list if using ClientProcess */ if (cp) { + std::unordered_set addedTags; + addedTags.reserve(buildList.size()); + Log.report(logvisor::Info, _S("Validating resources")); size_t loadIdx = 0; for (auto& tag : buildList) { fprintf(stderr, "\r %" PRISize " / %" PRISize " %.4s %08X", ++loadIdx, buildList.size(), tag.type.getChars(), (unsigned int)tag.id.Value()); + if (addedTags.find(tag) != addedTags.end()) + continue; + addedTags.insert(tag); + hecl::ProjectPath depPath = pathFromTag(tag); if (!depPath) { diff --git a/DataSpec/SpecBase.hpp b/DataSpec/SpecBase.hpp index 41801a491..7968012dd 100644 --- a/DataSpec/SpecBase.hpp +++ b/DataSpec/SpecBase.hpp @@ -187,6 +187,7 @@ protected: void backgroundIndexProc(); void recursiveBuildResourceList(std::vector& listOut, + std::unordered_set& addedTags, const hecl::ProjectPath& path, hecl::BlenderToken& btok); void copyBuildListData(std::vector>& fileIndex, diff --git a/DataSpec/SpecMP1.cpp b/DataSpec/SpecMP1.cpp index 78ef02b0f..37a9da450 100644 --- a/DataSpec/SpecMP1.cpp +++ b/DataSpec/SpecMP1.cpp @@ -538,6 +538,15 @@ struct SpecMP1 : SpecBase return {SBIG('AGSC'), glob.hash().val32()}; } } + if (ext[0] == _S('*') || !hecl::StrCmp(ext, _S("mid"))) + { + if (path.getWithExtension(_S(".mid"), true).isFile() && + path.getWithExtension(_S(".yaml"), true).isFile()) + { + hecl::ProjectPath glob = path.getWithExtension(_S(".*"), true); + return {SBIG('CSNG'), glob.hash().val32()}; + } + } } hecl::ProjectPath asBlend; @@ -562,13 +571,13 @@ struct SpecMP1 : SpecBase if (path.getAuxInfo().size()) { if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S(".CINF"))) - return {SBIG('CINF'), path.hash().val32()}; + return {SBIG('CINF'), path.getWithExtension(_S(".*"), true).hash().val32()}; else if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S(".CSKR"))) - return {SBIG('CSKR'), path.hash().val32()}; + return {SBIG('CSKR'), path.getWithExtension(_S(".*"), true).hash().val32()}; else if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S(".ANIM"))) - return {SBIG('ANIM'), path.hash().val32()}; + return {SBIG('ANIM'), path.getWithExtension(_S(".*"), true).hash().val32()}; } - return {SBIG('ANCS'), path.hash().val32()}; + return {SBIG('ANCS'), path.getWithExtension(_S(".*"), true).hash().val32()}; case hecl::BlenderConnection::BlendType::Area: { if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S("PATH"))) @@ -580,11 +589,11 @@ struct SpecMP1 : SpecBase if (path.getAuxInfo().size()) { if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S("MAPW"))) - return {SBIG('MAPW'), path.hash().val32()}; + return {SBIG('MAPW'), path.getWithExtension(_S(".*"), true).hash().val32()}; else if (hecl::StringUtils::EndsWith(path.getAuxInfo(), _S("SAVW"))) - return {SBIG('SAVW'), path.hash().val32()}; + return {SBIG('SAVW'), path.getWithExtension(_S(".*"), true).hash().val32()}; } - return {SBIG('MLVL'), path.hash().val32()}; + return {SBIG('MLVL'), path.getWithExtension(_S(".*"), true).hash().val32()}; } case hecl::BlenderConnection::BlendType::MapArea: return {SBIG('MAPA'), path.hash().val32()}; @@ -1023,7 +1032,7 @@ struct SpecMP1 : SpecBase mSeeds.read(reader); WriteTweak(mSeeds, out); } - else if (!classStr.compare(DNAMP1::MazeSeeds::DNAType())) + else if (!classStr.compare(DNAMP1::SnowForces::DNAType())) { DNAMP1::SnowForces sForces; sForces.read(reader); @@ -1204,6 +1213,7 @@ struct SpecMP1 : SpecBase urde::SObjectTag skyboxTag(FOURCC('CMDL'), mlvl.worldSkyboxId.toUint32()); if (skyboxTag) { + listOut.push_back(skyboxTag); hecl::ProjectPath skyboxPath = pathFromTag(skyboxTag); if (btok.getBlenderConnection().openBlend(skyboxPath)) { @@ -1217,7 +1227,6 @@ struct SpecMP1 : SpecBase listOut.push_back(texTag); } } - listOut.push_back(skyboxTag); } listOut.push_back(worldTag); diff --git a/Editor/ProjectResourceFactoryMP1.cpp b/Editor/ProjectResourceFactoryMP1.cpp index 82976f9df..a3fbfc369 100644 --- a/Editor/ProjectResourceFactoryMP1.cpp +++ b/Editor/ProjectResourceFactoryMP1.cpp @@ -34,6 +34,7 @@ #include "Runtime/CDependencyGroup.hpp" #include "DataSpec/DNACommon/TXTR.hpp" #include "CSimplePool.hpp" +#include "MP1/MP1OriginalIDs.hpp" #include "GameGlobalObjects.hpp" namespace DataSpec @@ -45,57 +46,6 @@ extern hecl::Database::DataSpecEntry SpecEntMP1PC; namespace urde { -class MP1OriginalIDs -{ - std::vector> m_origToNew; - std::vector> m_newToOrig; - -public: - MP1OriginalIDs(CInputStream& in) - { - u32 count = in.readUint32Big(); - m_origToNew.reserve(count); - for (u32 i=0 ; isecond; - } - - CAssetId TranslateNewToOriginal(CAssetId id) const - { - auto search = rstl::binary_find(m_newToOrig.cbegin(), m_newToOrig.cend(), id, - [](const auto& id) { return id.first; }); - if (search == m_newToOrig.cend()) - return -1; - return search->second; - } -}; - -CFactoryFnReturn FMP1OriginalIDsFactory(const SObjectTag& tag, CInputStream& in, - const CVParamTransfer& param, - CObjectReference* selfRef) -{ - return TToken::GetIObjObjectFor(std::make_unique(in)); -} - ProjectResourceFactoryMP1::ProjectResourceFactoryMP1(hecl::ClientProcess& clientProc) : ProjectResourceFactoryBase(clientProc) { diff --git a/Runtime/CFactoryMgr.cpp b/Runtime/CFactoryMgr.cpp index 3c98bf0c9..f16148b63 100644 --- a/Runtime/CFactoryMgr.cpp +++ b/Runtime/CFactoryMgr.cpp @@ -65,4 +65,31 @@ CFactoryFnReturn CFactoryMgr::MakeObjectFromMemory(const SObjectTag& tag, std::u } } +static const FourCC TypeTable[] = +{ + FOURCC('CLSN'), FOURCC('CMDL'), FOURCC('CSKR'), FOURCC('ANIM'), FOURCC('CINF'), FOURCC('TXTR'), + FOURCC('PLTT'), FOURCC('FONT'), FOURCC('ANCS'), FOURCC('EVNT'), FOURCC('MADF'), FOURCC('MLVL'), + FOURCC('MREA'), FOURCC('MAPW'), FOURCC('MAPA'), FOURCC('SAVW'), FOURCC('SAVA'), FOURCC('PART'), + FOURCC('WPSC'), FOURCC('SWHC'), FOURCC('DPSC'), FOURCC('ELSC'), FOURCC('CRSC'), FOURCC('AFSM'), + FOURCC('DCLN'), FOURCC('AGSC'), FOURCC('ATBL'), FOURCC('CSNG'), FOURCC('STRG'), FOURCC('SCAN'), + FOURCC('PATH'), FOURCC('DGRP'), FOURCC('HMAP'), FOURCC('CTWK'), FOURCC('FRME'), FOURCC('HINT'), + FOURCC('MAPU'), FOURCC('DUMB') +}; + +CFactoryMgr::ETypeTable CFactoryMgr::FourCCToTypeIdx(FourCC fcc) +{ + for (int i=0 ; i<4 ; ++i) + fcc.getChars()[i] = char(std::toupper(fcc.getChars()[i])); + auto search = std::find_if(std::begin(TypeTable), std::end(TypeTable), + [fcc](const FourCC& test) { return test == fcc; }); + if (search == std::end(TypeTable)) + return ETypeTable::Invalid; + return ETypeTable(search - std::begin(TypeTable)); +} + +FourCC CFactoryMgr::TypeIdxToFourCC(ETypeTable fcc) +{ + return TypeTable[int(fcc)]; +} + } diff --git a/Runtime/CFactoryMgr.hpp b/Runtime/CFactoryMgr.hpp index 87c32b481..bede6eb87 100644 --- a/Runtime/CFactoryMgr.hpp +++ b/Runtime/CFactoryMgr.hpp @@ -27,6 +27,21 @@ public: CObjectReference* selfRef); void AddFactory(FourCC key, FFactoryFunc func) {m_factories[key] = func;} void AddFactory(FourCC key, FMemFactoryFunc func) {m_memFactories[key] = func;} + + enum class ETypeTable : s8 + { + Invalid = -1, + CLSN, CMDL, CSKR, ANIM, CINF, TXTR, + PLTT, FONT, ANCS, EVNT, MADF, MLVL, + MREA, MAPW, MAPA, SAVW, SAVA, PART, + WPSC, SWHC, DPSC, ELSC, CRSC, AFSM, + DCLN, AGSC, ATBL, CSNG, STRG, SCAN, + PATH, DGRP, HMAP, CTWK, FRME, HINT, + MAPU, DUMB + }; + + static ETypeTable FourCCToTypeIdx(FourCC fcc); + static FourCC TypeIdxToFourCC(ETypeTable fcc); }; } diff --git a/Runtime/CPakFile.cpp b/Runtime/CPakFile.cpp index c2ecf0b02..95316d78e 100644 --- a/Runtime/CPakFile.cpp +++ b/Runtime/CPakFile.cpp @@ -2,6 +2,7 @@ namespace urde { +static logvisor::Module Log("urde::CPakFile"); CPakFile::CPakFile(const std::string& filename, bool buildDepList, bool worldPak) : CDvdFile(filename.c_str()) @@ -18,6 +19,154 @@ const SObjectTag* CPakFile::GetResIdByName(const char* name) const return nullptr; } +void CPakFile::LoadResourceTable(athena::io::MemoryReader& r) +{ + x74_resList.reserve(std::max(size_t(64), size_t(ROUND_UP_32(x4c_resTableCount * sizeof(SResInfo)) + + sizeof(SResInfo) - 1)) / sizeof(SResInfo)); + if (x28_24_buildDepList) + x64_depList.reserve(x4c_resTableCount); + for (u32 i=0 ; i origSize) + { + x38_headerData.resize(newSize); + x30_dvdReq = AsyncSeekRead(x38_headerData.data() + origSize, u32(x38_headerData.size() - origSize), + ESeekOrigin::Begin, origSize); + } + else + { + DataLoad(); + } +}; + +void CPakFile::Warmup() +{ + u32 length = std::min(u32(Length()), u32(8192)); + x38_headerData.resize(length); + x30_dvdReq = AsyncSeekRead(x38_headerData.data(), length, ESeekOrigin::Cur, 0); + x2c_asyncLoadPhase = EAsyncPhase::InitialHeader; +} + +const CPakFile::SResInfo* CPakFile::GetResInfoForLoadPreferForward(CAssetId id) const +{ + if (!x28_27_worldPakInitialized) + return nullptr; + auto search = std::lower_bound(x74_resList.begin(), x74_resList.end(), id, + [](const SResInfo& left, const CAssetId& right) { return left.x0_id < right; }); + if (search == x74_resList.end()) + return nullptr; + const SResInfo* bestInfo = &*search; + s32 bestDelta = x84_currentSeek - bestInfo->GetOffset(); + while (++search != x74_resList.end()) + { + const SResInfo* thisInfo = &*search; + if (thisInfo->x0_id != id) + break; + s32 thisDelta = x84_currentSeek - bestInfo->GetOffset(); + if ((bestDelta < 0 && (thisDelta > 0 || thisDelta > bestDelta)) || + (bestDelta >= 0 && thisDelta > 0 && thisDelta < bestDelta)) + { + bestDelta = thisDelta; + bestInfo = thisInfo; + } + } + x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize(); + return bestInfo; +} + +const CPakFile::SResInfo* CPakFile::GetResInfoForLoadDirectionless(CAssetId id) const +{ + if (!x28_27_worldPakInitialized) + return nullptr; + auto search = std::lower_bound(x74_resList.begin(), x74_resList.end(), id, + [](const SResInfo& left, const CAssetId& right) { return left.x0_id < right; }); + if (search == x74_resList.end()) + return nullptr; + const SResInfo* bestInfo = &*search; + s32 bestDelta = std::abs(s32(x84_currentSeek - bestInfo->GetOffset())); + while (++search != x74_resList.end()) + { + const SResInfo* thisInfo = &*search; + if (thisInfo->x0_id != id) + break; + s32 thisDelta = std::abs(s32(x84_currentSeek - bestInfo->GetOffset())); + if (thisDelta < bestDelta) + { + bestDelta = thisDelta; + bestInfo = thisInfo; + } + } + x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize(); + return bestInfo; +} + +const CPakFile::SResInfo* CPakFile::GetResInfo(CAssetId id) const +{ + if (x2c_asyncLoadPhase != EAsyncPhase::Loaded) + return nullptr; + if (!x28_27_worldPakInitialized) + return nullptr; + auto search = rstl::binary_find(x74_resList.begin(), x74_resList.end(), id, + [](const SResInfo& i) { return i.x0_id; }); + if (search == x74_resList.end()) + return nullptr; + return &*search; +} + void CPakFile::AsyncIdle() { if (x2c_asyncLoadPhase == EAsyncPhase::Loaded) diff --git a/Runtime/CPakFile.hpp b/Runtime/CPakFile.hpp index 52de5032c..6657aaf37 100644 --- a/Runtime/CPakFile.hpp +++ b/Runtime/CPakFile.hpp @@ -6,6 +6,7 @@ #include "CStringExtras.hpp" #include "CDvdFile.hpp" #include "CDvdRequest.hpp" +#include "CFactoryMgr.hpp" namespace urde { @@ -16,10 +17,24 @@ class CPakFile : public CDvdFile public: struct SResInfo { - FourCC x0_type; - u32 x4_offset; - u32 x8_size; - bool xb_compressed; + CAssetId x0_id; + bool x4_compressed : 1; + CFactoryMgr::ETypeTable x4_typeIdx : 7; + u32 x5_offsetDiv32 : 27; + u32 x7_sizeDiv32 : 27; + SResInfo(CAssetId id, FourCC fcc, u32 offset, u32 size, u32 flags) + : x0_id(id) + { + x4_compressed = flags != 0; + x4_typeIdx = CFactoryMgr::FourCCToTypeIdx(fcc); + x5_offsetDiv32 = offset / 32; + x7_sizeDiv32 = size / 32; + } + u32 GetOffset() const { return x5_offsetDiv32 * 32; } + u32 GetSize() const { return x7_sizeDiv32 * 32; } + FourCC GetType() const { return CFactoryMgr::TypeIdxToFourCC(x4_typeIdx); } + bool IsCompressed() const { return x4_compressed; } + CAssetId GetId() const { return x0_id; } }; private: union @@ -39,25 +54,28 @@ private: InitialHeader = 1, DataLoad = 2, Loaded = 3 - } x2c_asyncLoadPhase; + } x2c_asyncLoadPhase = EAsyncPhase::Warmup; std::shared_ptr x30_dvdReq; // Used to be auto_ptr std::vector x38_headerData; u32 x48_resTableOffset = 0; u32 x4c_resTableCount = 0; - int x50_ = -1; + int x50_aramBase = -1; std::vector> x54_nameList; std::vector x64_depList; - std::vector> x74_resList; + std::vector x74_resList; + mutable s32 x84_currentSeek = -1; + void LoadResourceTable(athena::io::MemoryReader& r); + void DataLoad(); + void InitialHeaderLoad(); + void Warmup(); public: CPakFile(const std::string& filename, bool buildDepList, bool worldPak); const std::vector& GetDepList() const { return x64_depList; } const SObjectTag* GetResIdByName(const char* name) const; - const SResInfo* GetResInfoForLoad(CAssetId id) { return nullptr; } - const SResInfo* GetResInfo(CAssetId id) const { return nullptr; } + const SResInfo* GetResInfoForLoadPreferForward(CAssetId id) const; + const SResInfo* GetResInfoForLoadDirectionless(CAssetId id) const; + const SResInfo* GetResInfo(CAssetId id) const; u32 GetFakeStaticSize() const { return 0; } - void DataLoad() {} - void InitialHeaderLoad() {} - void Warmup() {} void AsyncIdle(); }; diff --git a/Runtime/CResLoader.cpp b/Runtime/CResLoader.cpp index 2ca6d4386..2c2505b3e 100644 --- a/Runtime/CResLoader.cpp +++ b/Runtime/CResLoader.cpp @@ -4,6 +4,11 @@ namespace urde { +CResLoader::CResLoader() +{ + x48_curPak = x18_pakLoadedList.end(); +} + const std::vector* CResLoader::GetTagListForFile(const std::string& name) const { std::string namePak = name + ".pak"; @@ -30,79 +35,78 @@ void CResLoader::AddPakFile(const std::string& name, bool samusPak, bool worldPa AsyncIdlePakLoading(); } -CInputStream* CResLoader::LoadNewResourcePartSync(const SObjectTag& tag, int offset, int length, void* extBuf) +std::unique_ptr CResLoader::LoadNewResourcePartSync(const SObjectTag& tag, int offset, int length, void* extBuf) { void* buf = extBuf; CPakFile* file = FindResourceForLoad(tag); if (!buf) buf = new u8[length]; - file->SyncSeekRead(buf, length, ESeekOrigin::Begin, x50_cachedResInfo->x4_offset + offset); - return new CMemoryInStream((atUint8*)buf, length, !extBuf); + file->SyncSeekRead(buf, length, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + offset); + return std::unique_ptr(new athena::io::MemoryReader((atUint8*)buf, length, !extBuf)); } -void CResLoader::LoadMemResourceSync(const SObjectTag& tag, void** bufOut, int* sizeOut) +void CResLoader::LoadMemResourceSync(const SObjectTag& tag, std::unique_ptr& bufOut, int* sizeOut) { CPakFile* file = FindResourceForLoad(tag); - void* buf = new u8[x50_cachedResInfo->x8_size]; - file->SyncSeekRead(buf, x50_cachedResInfo->x8_size, ESeekOrigin::Begin, - x50_cachedResInfo->x4_offset); - *bufOut = buf; - *sizeOut = x50_cachedResInfo->x8_size; + bufOut = std::unique_ptr(new u8[x50_cachedResInfo->GetSize()]); + file->SyncSeekRead(bufOut.get(), x50_cachedResInfo->GetSize(), ESeekOrigin::Begin, + x50_cachedResInfo->GetOffset()); + *sizeOut = x50_cachedResInfo->GetSize(); } -CInputStream* CResLoader::LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf) +std::unique_ptr CResLoader::LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf) { FindResourceForLoad(tag); - CInputStream* newStrm = new CMemoryInStream((atUint8*)buf, x50_cachedResInfo->x8_size); - if (x50_cachedResInfo->xb_compressed) + CInputStream* newStrm = new athena::io::MemoryReader((atUint8*)buf, x50_cachedResInfo->GetSize()); + if (x50_cachedResInfo->IsCompressed()) { newStrm->readUint32Big(); newStrm = new CZipInputStream(std::unique_ptr(newStrm)); } - return newStrm; + return std::unique_ptr(newStrm); } -CInputStream* CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBuf) +std::unique_ptr CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBuf) { void* buf = extBuf; CPakFile* file = FindResourceForLoad(tag); - size_t resSz = ROUND_UP_32(x50_cachedResInfo->x8_size); + size_t resSz = ROUND_UP_32(x50_cachedResInfo->GetSize()); if (!buf) buf = new u8[resSz]; - file->SyncSeekRead(buf, resSz, ESeekOrigin::Begin, x50_cachedResInfo->x4_offset); - CInputStream* newStrm = new CMemoryInStream((atUint8*)buf, resSz, !extBuf); - if (x50_cachedResInfo->xb_compressed) + file->SyncSeekRead(buf, resSz, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset()); + CInputStream* newStrm = new athena::io::MemoryReader((atUint8*)buf, resSz, !extBuf); + if (x50_cachedResInfo->IsCompressed()) { newStrm->readUint32Big(); newStrm = new CZipInputStream(std::unique_ptr(newStrm)); } - return newStrm; + return std::unique_ptr(newStrm); } std::shared_ptr CResLoader::LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf) { return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, length, - ESeekOrigin::Begin, x50_cachedResInfo->x4_offset + offset); + ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + offset); } std::shared_ptr CResLoader::LoadResourceAsync(const SObjectTag& tag, void* buf) { - return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->x8_size), - ESeekOrigin::Begin, x50_cachedResInfo->x4_offset); + return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->GetSize()), + ESeekOrigin::Begin, x50_cachedResInfo->GetOffset()); } bool CResLoader::GetResourceCompression(const SObjectTag& tag) { if (FindResource(tag.id)) - return x50_cachedResInfo->xb_compressed; + return x50_cachedResInfo->IsCompressed(); return false; } u32 CResLoader::ResourceSize(const SObjectTag& tag) { if (FindResource(tag.id)) - return x50_cachedResInfo->x8_size; - return false; + return x50_cachedResInfo->GetSize(); + return 0; } bool CResLoader::ResourceExists(const SObjectTag& tag) @@ -113,7 +117,7 @@ bool CResLoader::ResourceExists(const SObjectTag& tag) FourCC CResLoader::GetResourceTypeById(CAssetId id) const { if (FindResource(id)) - return x50_cachedResInfo->x0_type; + return x50_cachedResInfo->GetType(); return FourCC(); } @@ -151,17 +155,41 @@ void CResLoader::AsyncIdlePakLoading() bool CResLoader::FindResource(CAssetId id) const { - for (const std::unique_ptr& file : x18_pakLoadedList) - if (const_cast(this)->CacheFromPak(*file, id)) + if (x4c_cachedResId == id) + return true; + + if (x48_curPak != x18_pakLoadedList.end()) + if (CacheFromPak(**x48_curPak, id)) return true; + + for (auto it = x18_pakLoadedList.begin() ; it != x18_pakLoadedList.end() ; ++it) + { + if (it == x48_curPak) + continue; + if (CacheFromPak(**it, id)) + return true; + } + return false; } CPakFile* CResLoader::FindResourceForLoad(CAssetId id) { - for (std::unique_ptr& file : x18_pakLoadedList) - if (CacheFromPakForLoad(*file, id)) - return file.get(); + if (x48_curPak != x18_pakLoadedList.end()) + if (CacheFromPakForLoad(**x48_curPak, id)) + return &**x48_curPak; + + for (auto it = x18_pakLoadedList.begin() ; it != x18_pakLoadedList.end() ; ++it) + { + if (it == x48_curPak) + continue; + if (CacheFromPakForLoad(**it, id)) + { + x48_curPak = it; + return &**it; + } + } + return nullptr; } @@ -172,7 +200,16 @@ CPakFile* CResLoader::FindResourceForLoad(const SObjectTag& tag) bool CResLoader::CacheFromPakForLoad(CPakFile& file, CAssetId id) { - const CPakFile::SResInfo* info = file.GetResInfoForLoad(id); + const CPakFile::SResInfo* info; + if (x54_forwardSeek) + { + info = file.GetResInfoForLoadPreferForward(id); + x54_forwardSeek = false; + } + else + { + info = file.GetResInfoForLoadDirectionless(id); + } if (info) { x4c_cachedResId = id; @@ -182,7 +219,7 @@ bool CResLoader::CacheFromPakForLoad(CPakFile& file, CAssetId id) return false; } -bool CResLoader::CacheFromPak(const CPakFile& file, CAssetId id) +bool CResLoader::CacheFromPak(const CPakFile& file, CAssetId id) const { const CPakFile::SResInfo* info = file.GetResInfo(id); if (info) diff --git a/Runtime/CResLoader.hpp b/Runtime/CResLoader.hpp index d7ec499d6..a05057bb1 100644 --- a/Runtime/CResLoader.hpp +++ b/Runtime/CResLoader.hpp @@ -19,16 +19,19 @@ class CResLoader std::list> x18_pakLoadedList; std::list> x30_pakLoadingList; u32 x44_pakLoadingCount = 0; - CAssetId x4c_cachedResId; - const CPakFile::SResInfo* x50_cachedResInfo = nullptr; + std::list>::iterator x48_curPak; + mutable CAssetId x4c_cachedResId; + mutable const CPakFile::SResInfo* x50_cachedResInfo = nullptr; + bool x54_forwardSeek = false; public: + CResLoader(); const std::vector* GetTagListForFile(const std::string& name) const; void AddPakFileAsync(const std::string& name, bool samusPak, bool worldPak); void AddPakFile(const std::string& name, bool samusPak, bool worldPak); - CInputStream* LoadNewResourcePartSync(const SObjectTag& tag, int offset, int length, void* extBuf); - void LoadMemResourceSync(const SObjectTag& tag, void** bufOut, int* sizeOut); - CInputStream* LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf); - CInputStream* LoadNewResourceSync(const SObjectTag& tag, void* extBuf=nullptr); + std::unique_ptr LoadNewResourcePartSync(const SObjectTag& tag, int offset, int length, void* extBuf); + void LoadMemResourceSync(const SObjectTag& tag, std::unique_ptr& bufOut, int* sizeOut); + std::unique_ptr LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf); + std::unique_ptr LoadNewResourceSync(const SObjectTag& tag, void* extBuf=nullptr); std::shared_ptr LoadResourcePartAsync(const SObjectTag& tag, int offset, int length, void* buf); std::shared_ptr LoadResourceAsync(const SObjectTag& tag, void* buf); bool GetResourceCompression(const SObjectTag& tag); @@ -42,7 +45,7 @@ public: CPakFile* FindResourceForLoad(CAssetId id); CPakFile* FindResourceForLoad(const SObjectTag& tag); bool CacheFromPakForLoad(CPakFile& file, CAssetId id); - bool CacheFromPak(const CPakFile& file, CAssetId id); + bool CacheFromPak(const CPakFile& file, CAssetId id) const; void MoveToCorrectLoadedList(std::unique_ptr&& file); }; diff --git a/Runtime/IFactory.hpp b/Runtime/IFactory.hpp index f62be291b..a5722637c 100644 --- a/Runtime/IFactory.hpp +++ b/Runtime/IFactory.hpp @@ -10,6 +10,8 @@ namespace urde class CVParamTransfer; class IObj; class CObjectReference; +class CResLoader; +class CFactoryMgr; using CFactoryFnReturn = std::unique_ptr; using FFactoryFunc = std::function& lambda) const=0; virtual void EnumerateNamedResources(const std::function& lambda) const=0; + virtual CResLoader* GetResLoader() const { return nullptr; } + virtual CFactoryMgr* GetFactoryMgr() const { return nullptr; } /* Non-factory versions, replaces CResLoader */ virtual u32 ResourceSize(const urde::SObjectTag& tag)=0; diff --git a/Runtime/MP1/CMakeLists.txt b/Runtime/MP1/CMakeLists.txt index f5f6adbd1..cc3225257 100644 --- a/Runtime/MP1/CMakeLists.txt +++ b/Runtime/MP1/CMakeLists.txt @@ -42,6 +42,7 @@ set(MP1_SOURCES CSamusDoll.hpp CSamusDoll.cpp CGameCubeDoll.hpp CGameCubeDoll.cpp CArtifactDoll.hpp CArtifactDoll.cpp + MP1OriginalIDs.hpp MP1OriginalIDs.cpp MP1.hpp MP1.cpp ${MP1_PLAT_SOURCES} ${MP1_WORLD_SOURCES}) diff --git a/Runtime/MP1/CPreFrontEnd.cpp b/Runtime/MP1/CPreFrontEnd.cpp index 1f713620a..99bb6c69e 100644 --- a/Runtime/MP1/CPreFrontEnd.cpp +++ b/Runtime/MP1/CPreFrontEnd.cpp @@ -20,8 +20,9 @@ CIOWin::EMessageReturn CPreFrontEnd::OnMessage(const CArchitectureMessage& msg, return EMessageReturn::Normal; CMain* m = static_cast(g_Main); - //if (CResLoader::AreAllPaksLoaded()) - // return EMessageReturn::Exit; + if (CResLoader* loader = g_ResFactory->GetResLoader()) + if (loader->AreAllPaksLoaded()) + return EMessageReturn::Exit; if (!x14_resourceTweaksRegistered) { m->RegisterResourceTweaks(); diff --git a/Runtime/MP1/MP1.cpp b/Runtime/MP1/MP1.cpp index f0c2f0ecf..aa3ff4535 100644 --- a/Runtime/MP1/MP1.cpp +++ b/Runtime/MP1/MP1.cpp @@ -20,7 +20,39 @@ #include "Graphics/Shaders/CParticleSwooshShaders.hpp" #include "Audio/CStreamAudioManager.hpp" #include "CGBASupport.hpp" + +#include "CGameHintInfo.hpp" +#include "Particle/CParticleDataFactory.hpp" +#include "Particle/CGenDescription.hpp" +#include "Particle/CElectricDescription.hpp" +#include "Particle/CSwooshDescription.hpp" +#include "Particle/CParticleElectricDataFactory.hpp" +#include "Particle/CParticleSwooshDataFactory.hpp" +#include "Particle/CWeaponDescription.hpp" +#include "Particle/CProjectileWeaponDataFactory.hpp" +#include "Particle/CDecalDataFactory.hpp" +#include "GuiSys/CGuiFrame.hpp" +#include "GuiSys/CRasterFont.hpp" +#include "GuiSys/CStringTable.hpp" +#include "Graphics/CModel.hpp" +#include "Graphics/CTexture.hpp" +#include "Character/CCharLayoutInfo.hpp" +#include "Character/CSkinRules.hpp" +#include "Character/CAnimCharacterSet.hpp" +#include "Character/CAllFormatsAnimSource.hpp" +#include "Character/CAnimPOIData.hpp" +#include "Collision/CCollidableOBBTreeGroup.hpp" +#include "Collision/CCollisionResponseData.hpp" +#include "CSaveWorld.hpp" +#include "AutoMapper/CMapWorld.hpp" +#include "AutoMapper/CMapArea.hpp" +#include "AutoMapper/CMapUniverse.hpp" +#include "CScannableObjectInfo.hpp" #include "Audio/CAudioGroupSet.hpp" +#include "Audio/CSfxManager.hpp" +#include "Audio/CMidiManager.hpp" +#include "CDependencyGroup.hpp" +#include "MP1OriginalIDs.hpp" namespace urde { @@ -248,6 +280,72 @@ CMain::BooSetter::BooSetter(boo::IGraphicsDataFactory* factory, void CMain::RegisterResourceTweaks() { } + +void CGameGlobalObjects::AddPaksAndFactories() +{ + CGraphics::SetViewPointMatrix(zeus::CTransform::Identity()); + CGraphics::SetModelMatrix(zeus::CTransform::Identity()); + if (CResLoader* loader = g_ResFactory->GetResLoader()) + { + loader->AddPakFileAsync("Tweaks", false, false); + loader->AddPakFileAsync("NoARAM", false, false); + loader->AddPakFileAsync("AudioGrp", false, false); + loader->AddPakFileAsync("MiscData", false, false); + loader->AddPakFileAsync("SamusGun", true, false); + loader->AddPakFileAsync("TestAnim", true, false); + loader->AddPakFileAsync("SamGunFx", true, false); + loader->AddPakFileAsync("MidiData", false, false); + loader->AddPakFileAsync("GGuiSys", false, false); + } + + if (CFactoryMgr* fmgr = g_ResFactory->GetFactoryMgr()) + { + fmgr->AddFactory(FOURCC('TXTR'), FMemFactoryFunc(FTextureFactory)); + fmgr->AddFactory(FOURCC('PART'), FFactoryFunc(FParticleFactory)); + fmgr->AddFactory(FOURCC('FRME'), FFactoryFunc(RGuiFrameFactoryInGame)); + fmgr->AddFactory(FOURCC('FONT'), FFactoryFunc(FRasterFontFactory)); + fmgr->AddFactory(FOURCC('CMDL'), FMemFactoryFunc(FModelFactory)); + fmgr->AddFactory(FOURCC('CINF'), FFactoryFunc(FCharLayoutInfo)); + fmgr->AddFactory(FOURCC('CSKR'), FFactoryFunc(FSkinRulesFactory)); + fmgr->AddFactory(FOURCC('ANCS'), FFactoryFunc(FAnimCharacterSet)); + fmgr->AddFactory(FOURCC('ANIM'), FFactoryFunc(AnimSourceFactory)); + fmgr->AddFactory(FOURCC('EVNT'), FFactoryFunc(AnimPOIDataFactory)); + fmgr->AddFactory(FOURCC('DCLN'), FFactoryFunc(FCollidableOBBTreeGroupFactory)); + fmgr->AddFactory(FOURCC('DGRP'), FFactoryFunc(FDependencyGroupFactory)); + fmgr->AddFactory(FOURCC('AGSC'), FMemFactoryFunc(FAudioGroupSetDataFactory)); + fmgr->AddFactory(FOURCC('CSNG'), FFactoryFunc(FMidiDataFactory)); + fmgr->AddFactory(FOURCC('ATBL'), FFactoryFunc(FAudioTranslationTableFactory)); + fmgr->AddFactory(FOURCC('STRG'), FFactoryFunc(FStringTableFactory)); + fmgr->AddFactory(FOURCC('HINT'), FFactoryFunc(FHintFactory)); + fmgr->AddFactory(FOURCC('SAVW'), FFactoryFunc(FSaveWorldFactory)); + fmgr->AddFactory(FOURCC('MAPW'), FFactoryFunc(FMapWorldFactory)); + fmgr->AddFactory(FOURCC('OIDS'), FFactoryFunc(FMP1OriginalIDsFactory)); + fmgr->AddFactory(FOURCC('SCAN'), FFactoryFunc(FScannableObjectInfoFactory)); + fmgr->AddFactory(FOURCC('CRSC'), FFactoryFunc(FCollisionResponseDataFactory)); + fmgr->AddFactory(FOURCC('SWHC'), FFactoryFunc(FParticleSwooshDataFactory)); + fmgr->AddFactory(FOURCC('ELSC'), FFactoryFunc(FParticleElectricDataFactory)); + fmgr->AddFactory(FOURCC('WPSC'), FFactoryFunc(FProjectileWeaponDataFactory)); + fmgr->AddFactory(FOURCC('DPSC'), FFactoryFunc(FDecalDataFactory)); + fmgr->AddFactory(FOURCC('MAPA'), FFactoryFunc(FMapAreaFactory)); + fmgr->AddFactory(FOURCC('MAPU'), FFactoryFunc(FMapUniverseFactory)); + } +} + +void CMain::AddWorldPaks() +{ + auto& pakPrefix = g_tweakGame->GetWorldPrefix(); + for (int i=0 ; i<9 ; ++i) + { + std::string path = pakPrefix; + if (i != 0) + path += '0' + i; + path += ".upak"; + if (CDvdFile::FileExists(path.c_str())) + if (CResLoader* loader = g_ResFactory->GetResLoader()) + loader->AddPakFileAsync(path, false, true); + } +} + void CMain::ResetGameState() { CPersistentOptions sysOpts = g_GameState->SystemOptions(); @@ -325,6 +423,7 @@ void CMain::Init(const hecl::Runtime::FileStoreManager& storeMgr, x128_globalObjects.PostInitialize(); x70_tweaks.RegisterTweaks(); x70_tweaks.RegisterResourceTweaks(); + AddWorldPaks(); FillInAssetIDs(); x164_archSupport.reset(new CGameArchitectureSupport(*this, voiceEngine, backend)); g_archSupport = x164_archSupport.get(); diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 3ffdd3861..0bd9be496 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -66,6 +66,7 @@ class CGameGlobalObjects x13c_mainStringTable = g_SimplePool->GetObj("STRG_Main"); g_MainStringTable = x13c_mainStringTable.GetObj(); } + void AddPaksAndFactories(); static IRenderer* AllocateRenderer(IObjectStore& store, IFactory& resFactory) { @@ -89,6 +90,7 @@ public: void PostInitialize() { + AddPaksAndFactories(); LoadStringTable(); m_renderer.reset(AllocateRenderer(xcc_simplePool, x4_resFactory)); CScriptMazeNode::LoadMazeSeeds(); @@ -253,6 +255,7 @@ public: boo::IGraphicsCommandQueue* cmdQ, boo::ITextureR* spareTex); void RegisterResourceTweaks(); + void AddWorldPaks(); void ResetGameState(); void StreamNewGameState(CBitStreamReader&, u32 idx); void CheckTweakManagerDebugOptions() {} diff --git a/Runtime/MP1/MP1OriginalIDs.cpp b/Runtime/MP1/MP1OriginalIDs.cpp new file mode 100644 index 000000000..8300af688 --- /dev/null +++ b/Runtime/MP1/MP1OriginalIDs.cpp @@ -0,0 +1,51 @@ +#include "MP1OriginalIDs.hpp" +#include "CToken.hpp" + +namespace urde +{ + +MP1OriginalIDs::MP1OriginalIDs(CInputStream& in) +{ + u32 count = in.readUint32Big(); + m_origToNew.reserve(count); + for (u32 i=0 ; isecond; +} + +CAssetId MP1OriginalIDs::TranslateNewToOriginal(CAssetId id) const +{ + auto search = rstl::binary_find(m_newToOrig.cbegin(), m_newToOrig.cend(), id, + [](const auto& id) { return id.first; }); + if (search == m_newToOrig.cend()) + return -1; + return search->second; +} + +CFactoryFnReturn FMP1OriginalIDsFactory(const SObjectTag& tag, CInputStream& in, + const CVParamTransfer& param, + CObjectReference* selfRef) +{ + return TToken::GetIObjObjectFor(std::make_unique(in)); +} + +} diff --git a/Runtime/MP1/MP1OriginalIDs.hpp b/Runtime/MP1/MP1OriginalIDs.hpp new file mode 100644 index 000000000..305ef2d6b --- /dev/null +++ b/Runtime/MP1/MP1OriginalIDs.hpp @@ -0,0 +1,27 @@ +#ifndef URDE_MP1ORIGINALIDS_HPP +#define URDE_MP1ORIGINALIDS_HPP + +#include "RetroTypes.hpp" +#include "IFactory.hpp" + +namespace urde +{ + +class MP1OriginalIDs +{ + std::vector> m_origToNew; + std::vector> m_newToOrig; + +public: + MP1OriginalIDs(CInputStream& in); + CAssetId TranslateOriginalToNew(CAssetId id) const; + CAssetId TranslateNewToOriginal(CAssetId id) const; +}; + +CFactoryFnReturn FMP1OriginalIDsFactory(const SObjectTag& tag, CInputStream& in, + const CVParamTransfer& param, + CObjectReference* selfRef); + +} + +#endif // URDE_MP1ORIGINALIDS_HPP diff --git a/hecl b/hecl index 70b73855b..038917dc5 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 70b73855bf906c81d18bdf70c9b701bba996314e +Subproject commit 038917dc59aaf50efed8925ff5fd53d62fd8cfe8 diff --git a/visigen/VISIBuilder.cpp b/visigen/VISIBuilder.cpp index ff7c390f6..4e6bf9802 100644 --- a/visigen/VISIBuilder.cpp +++ b/visigen/VISIBuilder.cpp @@ -323,6 +323,7 @@ std::vector VISIBuilder::build(const zeus::CAABox& fullAabb, Progress prog(updatePercent); #ifndef _WIN32 + parentPid = getppid(); auto terminate = [this, parentPid]() { return renderCache.m_renderer.m_terminate || (parentPid ? kill(parentPid, 0) : false);