#include "CResLoader.hpp" #include "CPakFile.hpp" namespace urde { static logvisor::Module Log("CResLoader"); CResLoader::CResLoader() { x48_curPak = x18_pakLoadedList.end(); } const std::vector* CResLoader::GetTagListForFile(const std::string& name) const { std::string namePak = name + ".upak"; for (const std::unique_ptr& pak : x18_pakLoadedList) if (!CStringExtras::CompareCaseInsensitive(namePak, pak->x18_path)) return &pak->GetDepList(); return nullptr; } void CResLoader::AddPakFileAsync(const std::string& name, bool buildDepList, bool worldPak) { std::string namePak = name + ".upak"; if (CDvdFile::FileExists(namePak.c_str())) { x30_pakLoadingList.emplace_back(new CPakFile(namePak, buildDepList, worldPak)); ++x44_pakLoadingCount; } } void CResLoader::AddPakFile(const std::string& name, bool samusPak, bool worldPak) { AddPakFileAsync(name, samusPak, worldPak); WaitForPakFileLoadingComplete(); } void CResLoader::WaitForPakFileLoadingComplete() { while (x44_pakLoadingCount) AsyncIdlePakLoading(); } std::unique_ptr CResLoader::LoadNewResourcePartSync(const SObjectTag& tag, u32 length, u32 offset, void* extBuf) { void* buf = extBuf; CPakFile* file = FindResourceForLoad(tag); if (!buf) buf = new u8[length]; 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, std::unique_ptr& bufOut, int* sizeOut) { if (CPakFile* file = FindResourceForLoad(tag)) { 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(); } } std::unique_ptr CResLoader::LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf) { FindResourceForLoad(tag); 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 std::unique_ptr(newStrm); } std::unique_ptr CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBuf) { void* buf = extBuf; if (CPakFile* file = FindResourceForLoad(tag)) { size_t resSz = ROUND_UP_32(x50_cachedResInfo->GetSize()); if (!buf) buf = new u8[resSz]; 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 std::unique_ptr(newStrm); } return {}; } std::shared_ptr CResLoader::LoadResourcePartAsync(const SObjectTag& tag, u32 length, u32 offset, void* buf) { return FindResourceForLoad(tag.id)->AsyncSeekRead(buf, length, 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->GetSize()), ESeekOrigin::Begin, x50_cachedResInfo->GetOffset()); } std::unique_ptr CResLoader::LoadResourceSync(const urde::SObjectTag& tag) { CPakFile* file = FindResourceForLoad(tag.id); u32 size = ROUND_UP_32(x50_cachedResInfo->GetSize()); std::unique_ptr ret(new u8[size]); file->SyncSeekRead(ret.get(), size, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset()); return ret; } std::unique_ptr CResLoader::LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off) { CPakFile* file = FindResourceForLoad(tag.id); std::unique_ptr ret(new u8[size]); file->SyncSeekRead(ret.get(), size, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + off); return ret; } void CResLoader::GetTagListForFile(const char* pakName, std::vector& out) const { std::string path = std::string(pakName) + ".upak"; for (const std::unique_ptr& file : x18_pakLoadedList) { if (!CStringExtras::CompareCaseInsensitive(file->GetPath(), path)) { auto& depList = file->GetDepList(); out.reserve(depList.size()); for (const auto& dep : depList) { auto resInfo = file->GetResInfo(dep); out.emplace_back(resInfo->GetType(), dep); } return; } } } bool CResLoader::GetResourceCompression(const SObjectTag& tag) { if (FindResource(tag.id)) return x50_cachedResInfo->IsCompressed(); return false; } u32 CResLoader::ResourceSize(const SObjectTag& tag) { if (FindResource(tag.id)) return x50_cachedResInfo->GetSize(); return 0; } bool CResLoader::ResourceExists(const SObjectTag& tag) { return FindResource(tag.id); } FourCC CResLoader::GetResourceTypeById(CAssetId id) const { if (FindResource(id)) return x50_cachedResInfo->GetType(); return {}; } const SObjectTag* CResLoader::GetResourceIdByName(const char* name) const { for (const std::unique_ptr& file : x18_pakLoadedList) { const SObjectTag* id = file->GetResIdByName(name); if (id) return id; } return nullptr; } bool CResLoader::AreAllPaksLoaded() const { return x44_pakLoadingCount == 0; } void CResLoader::AsyncIdlePakLoading() { for (auto it=x30_pakLoadingList.begin(); it != x30_pakLoadingList.end(); ++it) { (*it)->AsyncIdle(); if ((*it)->x2c_asyncLoadPhase == CPakFile::EAsyncPhase::Loaded) { MoveToCorrectLoadedList(std::move(*it)); it = x30_pakLoadingList.erase(it); --x44_pakLoadingCount; } } } bool CResLoader::FindResource(CAssetId id) const { 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; } Log.report(logvisor::Error, "Unable to find asset %08X", id); return false; } CPakFile* CResLoader::FindResourceForLoad(CAssetId id) { 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; } } Log.report(logvisor::Error, "Unable to find asset %08X", id); return nullptr; } CPakFile* CResLoader::FindResourceForLoad(const SObjectTag& tag) { return FindResourceForLoad(tag.id); } bool CResLoader::CacheFromPakForLoad(CPakFile& file, CAssetId 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; x50_cachedResInfo = info; return true; } return false; } bool CResLoader::CacheFromPak(const CPakFile& file, CAssetId id) const { const CPakFile::SResInfo* info = file.GetResInfo(id); if (info) { x4c_cachedResId = id; x50_cachedResInfo = info; return true; } return false; } void CResLoader::MoveToCorrectLoadedList(std::unique_ptr&& file) { x18_pakLoadedList.push_back(std::move(file)); } std::vector> CResLoader::GetResourceIdToNameList() const { std::vector> ret; for (auto it = x18_pakLoadedList.begin() ; it != x18_pakLoadedList.end() ; ++it) for (const auto& name : (*it)->GetNameList()) ret.push_back(name); return ret; } void CResLoader::EnumerateResources(const std::function& lambda) const { for (auto it = x18_pakLoadedList.begin() ; it != x18_pakLoadedList.end() ; ++it) { for (const CAssetId& id : (*it)->GetDepList()) { SObjectTag fcc(GetResourceTypeById(id), id); if (!lambda(fcc)) return; } } } void CResLoader::EnumerateNamedResources(const std::function& lambda) const { for (auto it = x18_pakLoadedList.begin() ; it != x18_pakLoadedList.end() ; ++it) { for (const auto& name : (*it)->GetNameList()) { if (!lambda(name.first, name.second)) return; } } } }