metaforce/Runtime/CResLoader.cpp

309 lines
10 KiB
C++
Raw Normal View History

#include "Runtime/CResLoader.hpp"
#include "Runtime/CPakFile.hpp"
2015-08-23 23:58:07 +00:00
2021-04-10 08:42:06 +00:00
namespace metaforce {
2017-10-27 10:10:32 +00:00
static logvisor::Module Log("CResLoader");
2015-08-23 23:58:07 +00:00
2018-12-08 05:30:43 +00:00
CResLoader::CResLoader() { x48_curPak = x18_pakLoadedList.end(); }
2017-10-26 05:37:46 +00:00
2018-12-08 05:30:43 +00:00
const std::vector<CAssetId>* CResLoader::GetTagListForFile(std::string_view name) const {
2022-02-01 00:06:54 +00:00
const std::string namePak = std::string(name).append(".pak");
for (const std::unique_ptr<CPakFile>& pak : x18_pakLoadedList) {
if (CStringExtras::CompareCaseInsensitive(namePak, pak->x18_path)) {
2018-12-08 05:30:43 +00:00
return &pak->GetDepList();
}
}
2018-12-08 05:30:43 +00:00
return nullptr;
2015-08-23 23:58:07 +00:00
}
2019-11-21 15:37:08 +00:00
void CResLoader::AddPakFileAsync(std::string_view name, bool buildDepList, bool worldPak, bool override) {
2022-02-01 00:06:54 +00:00
const std::string namePak = std::string(name).append(".pak");
if (CDvdFile::FileExists(namePak)) {
2019-11-21 15:37:08 +00:00
x30_pakLoadingList.emplace_back(std::make_unique<CPakFile>(namePak, buildDepList, worldPak, override));
2018-12-08 05:30:43 +00:00
++x44_pakLoadingCount;
}
2015-08-23 23:58:07 +00:00
}
2019-11-21 15:37:08 +00:00
void CResLoader::AddPakFile(std::string_view name, bool samusPak, bool worldPak, bool override) {
AddPakFileAsync(name, samusPak, worldPak, override);
2018-12-08 05:30:43 +00:00
WaitForPakFileLoadingComplete();
2017-10-27 10:10:32 +00:00
}
2018-12-08 05:30:43 +00:00
void CResLoader::WaitForPakFileLoadingComplete() {
while (x44_pakLoadingCount)
AsyncIdlePakLoading();
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CInputStream> CResLoader::LoadNewResourcePartSync(const SObjectTag& tag, u32 length, u32 offset,
void* extBuf) {
void* buf = extBuf;
if (buf == nullptr) {
2018-12-08 05:30:43 +00:00
buf = new u8[length];
}
CPakFile* const file = FindResourceForLoad(tag);
2018-12-08 05:30:43 +00:00
file->SyncSeekRead(buf, length, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + offset);
return std::make_unique<athena::io::MemoryReader>(buf, length, !extBuf);
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
void CResLoader::LoadMemResourceSync(const SObjectTag& tag, std::unique_ptr<u8[]>& bufOut, int* sizeOut) {
if (CPakFile* file = FindResourceForLoad(tag)) {
bufOut = std::unique_ptr<u8[]>(new u8[x50_cachedResInfo->GetSize()]);
file->SyncSeekRead(bufOut.get(), x50_cachedResInfo->GetSize(), ESeekOrigin::Begin, x50_cachedResInfo->GetOffset());
*sizeOut = x50_cachedResInfo->GetSize();
}
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CInputStream> CResLoader::LoadResourceFromMemorySync(const SObjectTag& tag, const void* buf) {
FindResourceForLoad(tag);
std::unique_ptr<CInputStream> newStrm = std::make_unique<athena::io::MemoryReader>(buf, x50_cachedResInfo->GetSize());
2018-12-08 05:30:43 +00:00
if (x50_cachedResInfo->IsCompressed()) {
newStrm->readUint32Big();
newStrm = std::make_unique<CZipInputStream>(std::move(newStrm));
2018-12-08 05:30:43 +00:00
}
return newStrm;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CInputStream> CResLoader::LoadNewResourceSync(const SObjectTag& tag, void* extBuf) {
if (CPakFile* const file = FindResourceForLoad(tag)) {
const size_t resSz = ROUND_UP_32(x50_cachedResInfo->GetSize());
void* buf = extBuf;
if (buf == nullptr) {
2018-12-08 05:30:43 +00:00
buf = new u8[resSz];
}
2018-12-08 05:30:43 +00:00
file->SyncSeekRead(buf, resSz, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset());
const bool takeOwnership = extBuf == nullptr;
std::unique_ptr<CInputStream> newStrm = std::make_unique<athena::io::MemoryReader>(buf, resSz, takeOwnership);
2018-12-08 05:30:43 +00:00
if (x50_cachedResInfo->IsCompressed()) {
newStrm->readUint32Big();
newStrm = std::make_unique<CZipInputStream>(std::move(newStrm));
2015-08-23 23:58:07 +00:00
}
return newStrm;
2018-12-08 05:30:43 +00:00
}
return nullptr;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::shared_ptr<IDvdRequest> CResLoader::LoadResourcePartAsync(const SObjectTag& tag, u32 off, u32 size, void* buf) {
CPakFile* file = FindResourceForLoad(tag.id);
return file->AsyncSeekRead(buf, size, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + off);
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::shared_ptr<IDvdRequest> CResLoader::LoadResourceAsync(const SObjectTag& tag, void* buf) {
CPakFile* file = FindResourceForLoad(tag.id);
return file->AsyncSeekRead(buf, ROUND_UP_32(x50_cachedResInfo->GetSize()), ESeekOrigin::Begin,
x50_cachedResInfo->GetOffset());
2015-08-23 23:58:07 +00:00
}
2021-04-10 08:42:06 +00:00
std::unique_ptr<u8[]> CResLoader::LoadResourceSync(const metaforce::SObjectTag& tag) {
2018-12-08 05:30:43 +00:00
CPakFile* file = FindResourceForLoad(tag.id);
u32 size = ROUND_UP_32(x50_cachedResInfo->GetSize());
std::unique_ptr<u8[]> ret(new u8[size]);
file->SyncSeekRead(ret.get(), size, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset());
return ret;
}
2021-04-10 08:42:06 +00:00
std::unique_ptr<u8[]> CResLoader::LoadNewResourcePartSync(const metaforce::SObjectTag& tag, u32 off, u32 size) {
2018-12-08 05:30:43 +00:00
CPakFile* file = FindResourceForLoad(tag.id);
std::unique_ptr<u8[]> ret(new u8[size]);
file->SyncSeekRead(ret.get(), size, ESeekOrigin::Begin, x50_cachedResInfo->GetOffset() + off);
return ret;
}
2018-12-08 05:30:43 +00:00
void CResLoader::GetTagListForFile(const char* pakName, std::vector<SObjectTag>& out) const {
2022-02-01 00:06:54 +00:00
std::string path = std::string(pakName) + ".pak";
2019-11-21 15:37:08 +00:00
for (const std::unique_ptr<CPakFile>& file : m_overridePakList) {
if (_GetTagListForFile(out, path, file))
return;
}
2018-12-08 05:30:43 +00:00
for (const std::unique_ptr<CPakFile>& file : x18_pakLoadedList) {
2019-11-21 15:37:08 +00:00
if (_GetTagListForFile(out, path, file))
2018-12-08 05:30:43 +00:00
return;
2019-11-21 15:37:08 +00:00
}
}
bool CResLoader::_GetTagListForFile(std::vector<SObjectTag>& out, const std::string& path,
const std::unique_ptr<CPakFile>& file) const {
if (CStringExtras::CompareCaseInsensitive(file->GetPath(), path)) {
const auto& depList = file->GetDepList();
2019-11-21 15:37:08 +00:00
out.reserve(depList.size());
for (const auto& dep : depList) {
const auto* const resInfo = file->GetResInfo(dep);
2019-11-21 15:37:08 +00:00
out.emplace_back(resInfo->GetType(), dep);
2017-10-28 07:08:48 +00:00
}
2019-11-21 15:37:08 +00:00
return true;
2018-12-08 05:30:43 +00:00
}
2019-11-21 15:37:08 +00:00
return false;
2017-10-28 07:08:48 +00:00
}
bool CResLoader::GetResourceCompression(const SObjectTag& tag) const {
2018-12-08 05:30:43 +00:00
if (FindResource(tag.id))
return x50_cachedResInfo->IsCompressed();
return false;
2015-08-23 23:58:07 +00:00
}
u32 CResLoader::ResourceSize(const SObjectTag& tag) const {
2018-12-08 05:30:43 +00:00
if (FindResource(tag.id))
return x50_cachedResInfo->GetSize();
return 0;
2015-08-23 23:58:07 +00:00
}
bool CResLoader::ResourceExists(const SObjectTag& tag) const { return FindResource(tag.id); }
2015-08-23 23:58:07 +00:00
2018-12-08 05:30:43 +00:00
FourCC CResLoader::GetResourceTypeById(CAssetId id) const {
if (id.IsValid() && FindResource(id))
return x50_cachedResInfo->GetType();
return {};
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
const SObjectTag* CResLoader::GetResourceIdByName(std::string_view name) const {
2019-11-21 15:37:08 +00:00
for (const std::unique_ptr<CPakFile>& file : m_overridePakList)
if (const SObjectTag* id = file->GetResIdByName(name))
return id;
2018-12-08 05:30:43 +00:00
for (const std::unique_ptr<CPakFile>& file : x18_pakLoadedList)
if (const SObjectTag* id = file->GetResIdByName(name))
return id;
return nullptr;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
bool CResLoader::AreAllPaksLoaded() const { return x44_pakLoadingCount == 0; }
2015-08-23 23:58:07 +00:00
2018-12-08 05:30:43 +00:00
void CResLoader::AsyncIdlePakLoading() {
for (auto it = x30_pakLoadingList.begin(); it != x30_pakLoadingList.end();) {
(*it)->AsyncIdle();
if ((*it)->x2c_asyncLoadPhase == CPakFile::EAsyncPhase::Loaded) {
MoveToCorrectLoadedList(std::move(*it));
it = x30_pakLoadingList.erase(it);
--x44_pakLoadingCount;
continue;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
++it;
}
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
bool CResLoader::FindResource(CAssetId id) const {
if (x4c_cachedResId == id)
return true;
2017-10-26 05:37:46 +00:00
2019-11-21 15:37:08 +00:00
for (auto it = m_overridePakList.begin(); it != m_overridePakList.end(); ++it) {
if (CacheFromPak(**it, id)) {
return true;
}
}
2018-12-08 05:30:43 +00:00
if (x48_curPak != x18_pakLoadedList.end())
if (CacheFromPak(**x48_curPak, id))
return true;
2015-08-23 23:58:07 +00:00
2018-12-08 05:30:43 +00:00
for (auto it = x18_pakLoadedList.begin(); it != x18_pakLoadedList.end(); ++it) {
if (it == x48_curPak)
continue;
if (CacheFromPak(**it, id))
return true;
}
2017-10-26 05:37:46 +00:00
2020-04-11 22:51:39 +00:00
Log.report(logvisor::Warning, FMT_STRING("Unable to find asset {}"), id);
2018-12-08 05:30:43 +00:00
return false;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
CPakFile* CResLoader::FindResourceForLoad(CAssetId id) {
2019-11-21 15:37:08 +00:00
for (auto it = m_overridePakList.begin(); it != m_overridePakList.end(); ++it) {
if (CacheFromPakForLoad(**it, id)) {
return &**it;
}
}
2018-12-08 05:30:43 +00:00
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;
}
}
2020-04-11 22:51:39 +00:00
Log.report(logvisor::Error, FMT_STRING("Unable to find asset {}"), id);
2018-12-08 05:30:43 +00:00
return nullptr;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
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;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
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;
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
void CResLoader::MoveToCorrectLoadedList(std::unique_ptr<CPakFile>&& file) {
2019-11-21 15:37:08 +00:00
if (file->IsOverridePak())
m_overridePakList.push_back(std::move(file));
else
x18_pakLoadedList.push_back(std::move(file));
2015-08-23 23:58:07 +00:00
}
2018-12-08 05:30:43 +00:00
std::vector<std::pair<std::string, SObjectTag>> CResLoader::GetResourceIdToNameList() const {
std::vector<std::pair<std::string, SObjectTag>> ret;
for (auto it = x18_pakLoadedList.begin(); it != x18_pakLoadedList.end(); ++it)
for (const auto& name : (*it)->GetNameList())
ret.push_back(name);
return ret;
}
2018-12-08 05:30:43 +00:00
void CResLoader::EnumerateResources(const std::function<bool(const SObjectTag&)>& lambda) const {
2019-11-21 15:37:08 +00:00
for (auto it = m_overridePakList.begin(); it != m_overridePakList.end(); ++it) {
for (const CAssetId& id : (*it)->GetDepList()) {
SObjectTag fcc(GetResourceTypeById(id), id);
if (!lambda(fcc))
return;
}
}
2018-12-08 05:30:43 +00:00
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;
}
2018-12-08 05:30:43 +00:00
}
}
2018-12-08 05:30:43 +00:00
void CResLoader::EnumerateNamedResources(const std::function<bool(std::string_view, const SObjectTag&)>& 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;
}
2021-04-10 08:42:06 +00:00
} // namespace metaforce