CWorldLoader: Make use of unsigned stream helpers

This commit is contained in:
Lioncash 2020-06-20 04:25:43 -04:00
parent cdc3328051
commit c2be854b0f
1 changed files with 84 additions and 82 deletions

View File

@ -3,9 +3,7 @@
#include "Core/GameProject/CResourceStore.h" #include "Core/GameProject/CResourceStore.h"
#include <Common/Log.h> #include <Common/Log.h>
CWorldLoader::CWorldLoader() CWorldLoader::CWorldLoader() = default;
{
}
void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL) void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
{ {
@ -16,41 +14,48 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
// Header // Header
if (mVersion < EGame::CorruptionProto) if (mVersion < EGame::CorruptionProto)
{ {
mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), EResourceType::StringTable); mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadULong(), EResourceType::StringTable);
if (mVersion == EGame::Echoes) mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), EResourceType::StringTable);
if (mVersion >= EGame::Echoes) mpWorld->mTempleKeyWorldIndex = rMLVL.ReadLong(); if (mVersion == EGame::Echoes)
if (mVersion >= EGame::Prime) mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), EResourceType::SaveWorld); mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadULong(), EResourceType::StringTable);
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLong(), EResourceType::Model);
if (mVersion >= EGame::Echoes)
mpWorld->mTempleKeyWorldIndex = rMLVL.ReadULong();
if (mVersion >= EGame::Prime)
mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadULong(), EResourceType::SaveWorld);
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadULong(), EResourceType::Model);
} }
else else
{ {
mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), EResourceType::StringTable); mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadULongLong(), EResourceType::StringTable);
rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value
mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), EResourceType::SaveWorld); mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadULongLong(), EResourceType::SaveWorld);
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), EResourceType::Model); mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadULongLong(), EResourceType::Model);
} }
// Memory relays - only in MP1 // Memory relays - only in MP1
if (mVersion == EGame::Prime) if (mVersion == EGame::Prime)
{ {
uint32 NumMemoryRelays = rMLVL.ReadLong(); const uint32 NumMemoryRelays = rMLVL.ReadULong();
mpWorld->mMemoryRelays.reserve(NumMemoryRelays); mpWorld->mMemoryRelays.reserve(NumMemoryRelays);
for (uint32 iMem = 0; iMem < NumMemoryRelays; iMem++) for (uint32 iMem = 0; iMem < NumMemoryRelays; iMem++)
{ {
CWorld::SMemoryRelay MemRelay; auto& MemRelay = mpWorld->mMemoryRelays.emplace_back();
MemRelay.InstanceID = rMLVL.ReadLong(); MemRelay.InstanceID = rMLVL.ReadULong();
MemRelay.TargetID = rMLVL.ReadLong(); MemRelay.TargetID = rMLVL.ReadULong();
MemRelay.Message = rMLVL.ReadShort(); MemRelay.Message = rMLVL.ReadUShort();
MemRelay.Active = rMLVL.ReadBool(); MemRelay.Active = rMLVL.ReadBool();
mpWorld->mMemoryRelays.push_back(MemRelay);
} }
} }
// Areas - here's the real meat of the file // Areas - here's the real meat of the file
uint32 NumAreas = rMLVL.ReadLong(); const uint32 NumAreas = rMLVL.ReadULong();
if (mVersion == EGame::Prime) rMLVL.Seek(0x4, SEEK_CUR); if (mVersion == EGame::Prime)
rMLVL.Seek(0x4, SEEK_CUR);
mpWorld->mAreas.resize(NumAreas); mpWorld->mAreas.resize(NumAreas);
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (uint32 iArea = 0; iArea < NumAreas; iArea++)
@ -64,65 +69,65 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
pArea->AreaID = CAssetID(rMLVL, mVersion); pArea->AreaID = CAssetID(rMLVL, mVersion);
// Attached areas // Attached areas
uint32 NumAttachedAreas = rMLVL.ReadLong(); const uint32 NumAttachedAreas = rMLVL.ReadULong();
pArea->AttachedAreaIDs.reserve(NumAttachedAreas); pArea->AttachedAreaIDs.reserve(NumAttachedAreas);
for (uint32 iAttached = 0; iAttached < NumAttachedAreas; iAttached++) for (uint32 iAttached = 0; iAttached < NumAttachedAreas; iAttached++)
pArea->AttachedAreaIDs.push_back( rMLVL.ReadShort() ); pArea->AttachedAreaIDs.push_back(rMLVL.ReadUShort());
// Skip dependency list - this is very fast to regenerate so there's no use in caching it // Skip dependency list - this is very fast to regenerate so there's no use in caching it
if (mVersion < EGame::CorruptionProto) if (mVersion < EGame::CorruptionProto)
{ {
rMLVL.Seek(0x4, SEEK_CUR); rMLVL.Seek(0x4, SEEK_CUR);
uint32 NumDependencies = rMLVL.ReadLong(); const uint32 NumDependencies = rMLVL.ReadULong();
rMLVL.Seek(NumDependencies * 8, SEEK_CUR); rMLVL.Seek(NumDependencies * 8, SEEK_CUR);
uint32 NumDependencyOffsets = rMLVL.ReadLong(); const uint32 NumDependencyOffsets = rMLVL.ReadULong();
rMLVL.Seek(NumDependencyOffsets * 4, SEEK_CUR); rMLVL.Seek(NumDependencyOffsets * 4, SEEK_CUR);
} }
// Docks // Docks
uint32 NumDocks = rMLVL.ReadLong(); const uint32 NumDocks = rMLVL.ReadULong();
pArea->Docks.resize(NumDocks); pArea->Docks.resize(NumDocks);
for (uint32 iDock = 0; iDock < NumDocks; iDock++) for (uint32 iDock = 0; iDock < NumDocks; iDock++)
{ {
uint32 NumConnectingDocks = rMLVL.ReadLong(); const uint32 NumConnectingDocks = rMLVL.ReadULong();
CWorld::SArea::SDock* pDock = &pArea->Docks[iDock]; CWorld::SArea::SDock* pDock = &pArea->Docks[iDock];
pDock->ConnectingDocks.reserve(NumConnectingDocks); pDock->ConnectingDocks.reserve(NumConnectingDocks);
for (uint32 iConnect = 0; iConnect < NumConnectingDocks; iConnect++) for (uint32 iConnect = 0; iConnect < NumConnectingDocks; iConnect++)
{ {
CWorld::SArea::SDock::SConnectingDock ConnectingDock; auto& ConnectingDock = pDock->ConnectingDocks.emplace_back();
ConnectingDock.AreaIndex = rMLVL.ReadLong(); ConnectingDock.AreaIndex = rMLVL.ReadULong();
ConnectingDock.DockIndex = rMLVL.ReadLong(); ConnectingDock.DockIndex = rMLVL.ReadULong();
pDock->ConnectingDocks.push_back(ConnectingDock);
} }
uint32 NumCoordinates = rMLVL.ReadLong(); const uint32 NumCoordinates = rMLVL.ReadULong();
ASSERT(NumCoordinates == 4); ASSERT(NumCoordinates == 4);
pDock->DockCoordinates.resize(NumCoordinates); pDock->DockCoordinates.resize(NumCoordinates);
for (uint32 iCoord = 0; iCoord < NumCoordinates; iCoord++) for (auto& coordinate : pDock->DockCoordinates)
pDock->DockCoordinates[iCoord] = CVector3f(rMLVL); coordinate = CVector3f(rMLVL);
} }
// Rels // Rels
if ( (mVersion == EGame::EchoesDemo) || (mVersion == EGame::Echoes) ) if (mVersion == EGame::EchoesDemo || mVersion == EGame::Echoes)
{ {
uint32 NumRels = rMLVL.ReadLong(); const uint32 NumRels = rMLVL.ReadULong();
pArea->RelFilenames.resize(NumRels); pArea->RelFilenames.resize(NumRels);
for (uint32 iRel = 0; iRel < NumRels; iRel++) for (auto& filename : pArea->RelFilenames)
pArea->RelFilenames[iRel] = rMLVL.ReadString(); filename = rMLVL.ReadString();
if (mVersion == EGame::Echoes) if (mVersion == EGame::Echoes)
{ {
uint32 NumRelOffsets = rMLVL.ReadLong(); // Don't know what these offsets correspond to const uint32 NumRelOffsets = rMLVL.ReadULong(); // Don't know what these offsets correspond to
pArea->RelOffsets.resize(NumRelOffsets); pArea->RelOffsets.resize(NumRelOffsets);
for (uint32 iOff = 0; iOff < NumRelOffsets; iOff++) for (auto& offset : pArea->RelOffsets)
pArea->RelOffsets[iOff] = rMLVL.ReadLong(); offset = rMLVL.ReadULong();
} }
} }
@ -132,13 +137,13 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
} }
// MapWorld // MapWorld
mpWorld->mpMapWorld = gpResourceStore->LoadResource( CAssetID(rMLVL, mVersion), EResourceType::MapWorld ); mpWorld->mpMapWorld = gpResourceStore->LoadResource(CAssetID(rMLVL, mVersion), EResourceType::MapWorld);
rMLVL.Seek(0x5, SEEK_CUR); // Unknown values which are always 0 rMLVL.Seek(0x5, SEEK_CUR); // Unknown values which are always 0
// Audio Groups - we don't need this info as we regenerate it on cook // Audio Groups - we don't need this info as we regenerate it on cook
if (mVersion == EGame::Prime) if (mVersion == EGame::Prime)
{ {
uint32 NumAudioGrps = rMLVL.ReadLong(); const uint32 NumAudioGrps = rMLVL.ReadULong();
rMLVL.Seek(0x8 * NumAudioGrps, SEEK_CUR); rMLVL.Seek(0x8 * NumAudioGrps, SEEK_CUR);
rMLVL.Seek(0x1, SEEK_CUR); // Unknown values which are always 0 rMLVL.Seek(0x1, SEEK_CUR); // Unknown values which are always 0
} }
@ -148,22 +153,23 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (uint32 iArea = 0; iArea < NumAreas; iArea++)
{ {
CWorld::SArea* pArea = &mpWorld->mAreas[iArea]; CWorld::SArea* pArea = &mpWorld->mAreas[iArea];
uint32 NumLayers = rMLVL.ReadLong(); const uint32 NumLayers = rMLVL.ReadULong();
if (NumLayers != pArea->Layers.size()) pArea->Layers.resize(NumLayers); if (NumLayers != pArea->Layers.size())
pArea->Layers.resize(NumLayers);
uint64 LayerFlags = rMLVL.ReadLongLong(); const uint64 LayerFlags = rMLVL.ReadULongLong();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1); pArea->Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1);
} }
// Layer names // Layer names
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (size_t iArea = 0; iArea < NumAreas; iArea++)
{ {
CWorld::SArea* pArea = &mpWorld->mAreas[iArea]; CWorld::SArea* pArea = &mpWorld->mAreas[iArea];
uint32 NumLayers = pArea->Layers.size(); const size_t NumLayers = pArea->Layers.size();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (size_t iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].LayerName = rMLVL.ReadString(); pArea->Layers[iLayer].LayerName = rMLVL.ReadString();
} }
@ -171,12 +177,12 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
if (mVersion >= EGame::Corruption) if (mVersion >= EGame::Corruption)
{ {
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (size_t iArea = 0; iArea < NumAreas; iArea++)
{ {
CWorld::SArea *pArea = &mpWorld->mAreas[iArea]; CWorld::SArea *pArea = &mpWorld->mAreas[iArea];
uint32 NumLayers = pArea->Layers.size(); const size_t NumLayers = pArea->Layers.size();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (size_t iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].LayerStateID = CSavedStateID(rMLVL); pArea->Layers[iLayer].LayerStateID = CSavedStateID(rMLVL);
} }
} }
@ -186,7 +192,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL) void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
{ {
mpWorld->mpWorldName = gpResourceStore->LoadResource<CStringTable>(rMLVL.ReadLongLong()); mpWorld->mpWorldName = gpResourceStore->LoadResource<CStringTable>(rMLVL.ReadULongLong());
CWorld::STimeAttackData& rData = mpWorld->mTimeAttackData; CWorld::STimeAttackData& rData = mpWorld->mTimeAttackData;
rData.HasTimeAttack = rMLVL.ReadBool(); rData.HasTimeAttack = rMLVL.ReadBool();
@ -200,62 +206,57 @@ void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
rData.ShinyGoldTime = rMLVL.ReadFloat(); rData.ShinyGoldTime = rMLVL.ReadFloat();
} }
mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), EResourceType::SaveWorld); mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadULongLong(), EResourceType::SaveWorld);
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource<CModel>(rMLVL.ReadLongLong()); mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource<CModel>(rMLVL.ReadULongLong());
// Areas // Areas
uint32 NumAreas = rMLVL.ReadLong(); const uint32 NumAreas = rMLVL.ReadULong();
mpWorld->mAreas.resize(NumAreas); mpWorld->mAreas.resize(NumAreas);
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (auto& area : mpWorld->mAreas)
{ {
// Area header // Area header
CWorld::SArea *pArea = &mpWorld->mAreas[iArea]; area.pAreaName = gpResourceStore->LoadResource<CStringTable>(rMLVL.ReadULongLong());
area.Transform = CTransform4f(rMLVL);
pArea->pAreaName = gpResourceStore->LoadResource<CStringTable>(rMLVL.ReadLongLong()); area.AetherBox = CAABox(rMLVL);
pArea->Transform = CTransform4f(rMLVL); area.AreaResID = rMLVL.ReadULongLong();
pArea->AetherBox = CAABox(rMLVL); area.AreaID = rMLVL.ReadULongLong();
pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong();
rMLVL.Seek(0x4, SEEK_CUR); rMLVL.Seek(0x4, SEEK_CUR);
pArea->InternalName = rMLVL.ReadString(); area.InternalName = rMLVL.ReadString();
} }
// Layer flags // Layer flags
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant area count rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant area count
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (auto& area : mpWorld->mAreas)
{ {
CWorld::SArea* pArea = &mpWorld->mAreas[iArea]; const uint32 NumLayers = rMLVL.ReadULong();
uint32 NumLayers = rMLVL.ReadLong(); area.Layers.resize(NumLayers);
pArea->Layers.resize(NumLayers);
uint64 LayerFlags = rMLVL.ReadLongLong(); const uint64 LayerFlags = rMLVL.ReadULongLong();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1); area.Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1);
} }
// Layer names // Layer names
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (auto& area : mpWorld->mAreas)
{ {
CWorld::SArea* pArea = &mpWorld->mAreas[iArea]; const size_t NumLayers = area.Layers.size();
uint32 NumLayers = pArea->Layers.size();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (size_t iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].LayerName = rMLVL.ReadString(); area.Layers[iLayer].LayerName = rMLVL.ReadString();
} }
// Layer state IDs // Layer state IDs
rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count rMLVL.Seek(0x4, SEEK_CUR); // Skipping redundant layer count
for (uint32 iArea = 0; iArea < NumAreas; iArea++) for (auto& area : mpWorld->mAreas)
{ {
CWorld::SArea *pArea = &mpWorld->mAreas[iArea]; const size_t NumLayers = area.Layers.size();
uint32 NumLayers = pArea->Layers.size();
for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++) for (uint32 iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].LayerStateID = CSavedStateID(rMLVL); area.Layers[iLayer].LayerStateID = CSavedStateID(rMLVL);
} }
// Last part of the file is layer name offsets, but we don't need it // Last part of the file is layer name offsets, but we don't need it
@ -278,17 +279,18 @@ void CWorldLoader::GenerateEditorData()
std::unique_ptr<CWorld> CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry) std::unique_ptr<CWorld> CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
{ {
if (!rMLVL.IsValid()) return nullptr; if (!rMLVL.IsValid())
return nullptr;
uint32 Magic = rMLVL.ReadLong(); const uint32 Magic = rMLVL.ReadULong();
if (Magic != 0xDEAFBABE) if (Magic != 0xDEAFBABE)
{ {
errorf("%s: Invalid MLVL magic: 0x%08X", *rMLVL.GetSourceString(), Magic); errorf("%s: Invalid MLVL magic: 0x%08X", *rMLVL.GetSourceString(), Magic);
return nullptr; return nullptr;
} }
uint32 FileVersion = rMLVL.ReadLong(); const uint32 FileVersion = rMLVL.ReadULong();
EGame Version = GetFormatVersion(FileVersion); const EGame Version = GetFormatVersion(FileVersion);
if (Version == EGame::Invalid) if (Version == EGame::Invalid)
{ {
errorf("%s: Unsupported MLVL version: 0x%X", *rMLVL.GetSourceString(), FileVersion); errorf("%s: Unsupported MLVL version: 0x%X", *rMLVL.GetSourceString(), FileVersion);