metaforce/Runtime/CPakFile.cpp

184 lines
5.9 KiB
C++
Raw Permalink Normal View History

#include "Runtime/CPakFile.hpp"
2017-02-07 22:48:43 -08:00
2021-04-10 01:42:06 -07:00
namespace metaforce {
static logvisor::Module Log("metaforce::CPakFile");
2017-02-07 22:48:43 -08:00
2019-11-21 07:37:08 -08:00
CPakFile::CPakFile(std::string_view filename, bool buildDepList, bool worldPak, bool override) : CDvdFile(filename) {
2018-12-07 21:30:43 -08:00
if (!CDvdFile::operator bool())
2020-04-11 15:51:39 -07:00
Log.report(logvisor::Fatal, FMT_STRING("{}: Unable to open"), GetPath());
2018-12-07 21:30:43 -08:00
x28_24_buildDepList = buildDepList;
2021-06-07 12:29:18 -07:00
// x28_24_buildDepList = true; // Always do this so metaforce can rapidly pre-warm shaders
2018-12-07 21:30:43 -08:00
x28_26_worldPak = worldPak;
2019-11-21 07:37:08 -08:00
m_override = override;
2017-02-07 22:48:43 -08:00
}
2018-12-07 21:30:43 -08:00
CPakFile::~CPakFile() {
if (x30_dvdReq)
x30_dvdReq->PostCancelRequest();
2018-05-07 22:10:24 -07:00
}
2018-12-07 21:30:43 -08:00
const SObjectTag* CPakFile::GetResIdByName(std::string_view name) const {
for (const std::pair<std::string, SObjectTag>& p : x54_nameList) {
if (CStringExtras::CompareCaseInsensitive(p.first, name)) {
2018-12-07 21:30:43 -08:00
return &p.second;
}
}
2018-12-07 21:30:43 -08:00
return nullptr;
2017-02-07 22:48:43 -08:00
}
void CPakFile::LoadResourceTable(CInputStream& r) {
2018-12-07 21:30:43 -08:00
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 < x4c_resTableCount; ++i) {
u32 flags = r.ReadLong();
2018-12-07 21:30:43 -08:00
FourCC fcc;
r.ReadBytes(reinterpret_cast<u8*>(&fcc), 4);
CAssetId id = r.Get<CAssetId>();
u32 size = r.ReadLong();
u32 offset = r.ReadLong();
2018-12-07 21:30:43 -08:00
if (fcc == FOURCC('MLVL'))
m_mlvlId = id;
x74_resList.emplace_back(id, fcc, offset, size, flags);
2017-10-25 22:37:46 -07:00
if (x28_24_buildDepList)
2018-12-07 21:30:43 -08:00
x64_depList.push_back(id);
}
std::sort(x74_resList.begin(), x74_resList.end(), [](const auto& a, const auto& b) { return a.x0_id < b.x0_id; });
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
void CPakFile::DataLoad() {
x30_dvdReq.reset();
CMemoryInStream r(x38_headerData.data() + x48_resTableOffset, x38_headerData.size() - x48_resTableOffset,
CMemoryInStream::EOwnerShip::NotOwned);
2018-12-07 21:30:43 -08:00
LoadResourceTable(r);
x2c_asyncLoadPhase = EAsyncPhase::Loaded;
if (x28_26_worldPak) {
// Allocate ARAM space DMA x74_resList to ARAM
}
x38_headerData.clear();
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
void CPakFile::InitialHeaderLoad() {
CMemoryInStream r(x38_headerData.data(), x38_headerData.size(), CMemoryInStream::EOwnerShip::NotOwned);
2018-12-07 21:30:43 -08:00
x30_dvdReq.reset();
u32 version = r.ReadLong();
2022-01-31 16:06:54 -08:00
if (version != 0x00030005) {
2019-07-19 21:27:21 -07:00
Log.report(logvisor::Fatal,
2020-04-11 15:51:39 -07:00
FMT_STRING("{}: Incompatible pak file version -- Current version is {:08X}, you're using {:08X}"),
2022-01-31 16:06:54 -08:00
GetPath(), 0x00030005, version);
2018-12-07 21:30:43 -08:00
return;
}
2017-10-25 22:37:46 -07:00
r.ReadLong();
u32 nameCount = r.ReadLong();
2018-12-07 21:30:43 -08:00
x54_nameList.reserve(nameCount);
for (u32 i = 0; i < nameCount; ++i) {
SObjectTag tag(r);
auto name = CStringExtras::ReadString(r);
2018-12-07 21:30:43 -08:00
x54_nameList.emplace_back(name, tag);
}
2017-10-25 22:37:46 -07:00
x4c_resTableCount = r.ReadLong();
x48_resTableOffset = u32(r.GetReadPosition());
2018-12-07 21:30:43 -08:00
x2c_asyncLoadPhase = EAsyncPhase::DataLoad;
u32 newSize = ROUND_UP_32(x4c_resTableCount * 20 + x48_resTableOffset);
u32 origSize = u32(x38_headerData.size());
if (newSize > origSize) {
x38_headerData.resize(newSize);
x30_dvdReq = AsyncSeekRead(x38_headerData.data() + origSize, u32(x38_headerData.size() - origSize),
ESeekOrigin::Begin, origSize);
} else {
DataLoad();
}
2017-10-25 22:37:46 -07:00
};
2018-12-07 21:30:43 -08:00
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;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
const CPakFile::SResInfo* CPakFile::GetResInfoForLoadPreferForward(CAssetId id) const {
if (x28_27_stashedInARAM)
return nullptr;
auto search =
rstl::binary_find(x74_resList.begin(), x74_resList.end(), id, [](const SResInfo& test) { return test.x0_id; });
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;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
}
x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize();
return bestInfo;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
const CPakFile::SResInfo* CPakFile::GetResInfoForLoadDirectionless(CAssetId id) const {
if (x28_27_stashedInARAM)
return nullptr;
auto search =
rstl::binary_find(x74_resList.begin(), x74_resList.end(), id, [](const SResInfo& test) { return test.x0_id; });
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;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
}
x84_currentSeek = bestInfo->GetOffset() + bestInfo->GetSize();
return bestInfo;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
const CPakFile::SResInfo* CPakFile::GetResInfo(CAssetId id) const {
if (x2c_asyncLoadPhase != EAsyncPhase::Loaded)
return nullptr;
if (x28_27_stashedInARAM)
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;
2017-10-25 22:37:46 -07:00
}
2018-12-07 21:30:43 -08:00
void CPakFile::AsyncIdle() {
if (x2c_asyncLoadPhase == EAsyncPhase::Loaded)
return;
if (x30_dvdReq && !x30_dvdReq->IsComplete())
return;
switch (x2c_asyncLoadPhase) {
case EAsyncPhase::Warmup:
Warmup();
break;
case EAsyncPhase::InitialHeader:
InitialHeaderLoad();
break;
case EAsyncPhase::DataLoad:
DataLoad();
break;
default:
break;
}
2017-02-07 22:48:43 -08:00
}
2021-04-10 01:42:06 -07:00
} // namespace metaforce