Fixed some missed dependencies in a few formats and implemented support for building file lists for paks and MLVLs, and implemented support for package cooking for MP1

This commit is contained in:
parax0
2016-08-12 04:27:19 -06:00
parent 0f2c0d5b39
commit de18044ae0
39 changed files with 1094 additions and 171 deletions

View File

@@ -36,14 +36,11 @@ CDependencyTree* CGameArea::BuildDependencyTree() const
// Base dependencies
CAreaDependencyTree *pTree = new CAreaDependencyTree(ID());
for (u32 iMat = 0; iMat < mpMaterialSet->NumMaterials(); iMat++)
{
CMaterial *pMat = mpMaterialSet->MaterialByIndex(iMat);
pTree->AddDependency(pMat->IndTexture());
std::set<CAssetID> MatTextures;
mpMaterialSet->GetUsedTextureIDs(MatTextures);
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
pTree->AddDependency(pMat->Pass(iPass)->Texture());
}
for (auto Iter = MatTextures.begin(); Iter != MatTextures.end(); Iter++)
pTree->AddDependency(*Iter);
pTree->AddDependency(mPathID);
pTree->AddDependency(mPortalAreaID);

View File

@@ -58,12 +58,23 @@ public:
CDependencyTree* BuildDependencyTree() const
{
CAnimSetDependencyTree *pTree = new CAnimSetDependencyTree(ID());
std::set<CAssetID> BaseUsedSet;
// Base dependencies
for (u32 iAnim = 0; iAnim < mAnims.size(); iAnim++)
pTree->AddDependency(mAnims[iAnim].pAnim);
{
CAnimation *pAnim = mAnims[iAnim].pAnim;
if (pAnim)
{
pTree->AddDependency(mAnims[iAnim].pAnim);
BaseUsedSet.insert(pAnim->ID());
}
}
// Character dependencies
for (u32 iNode = 0; iNode < mCharacters.size(); iNode++)
pTree->AddCharacter(&mCharacters[iNode]);
pTree->AddCharacter(&mCharacters[iNode], BaseUsedSet);
return pTree;
}

View File

@@ -59,6 +59,21 @@ public:
return -1;
}
void GetUsedTextureIDs(std::set<CAssetID>& rOut)
{
for (u32 iMat = 0; iMat < mMaterials.size(); iMat++)
{
CMaterial *pMat = mMaterials[iMat];
if (pMat->IndTexture()) rOut.insert(pMat->IndTexture()->ID());
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
{
CTexture *pTex = pMat->Pass(iPass)->Texture();
if (pTex) rOut.insert(pTex->ID());
}
}
}
};
#endif // CMATERIALSET_H

View File

@@ -24,16 +24,16 @@ public:
private:
EGame mVersion;
TResPtr<CResource> mpFrame;
CAssetID mFrameID;
TResPtr<CStringTable> mpStringTable;
bool mIsSlow;
bool mIsImportant;
ELogbookCategory mCategory;
CAssetID mScanImageTextures[4];
public:
CScan(CResourceEntry *pEntry = 0)
: CResource(pEntry)
, mpFrame(nullptr)
, mpStringTable(nullptr)
, mIsSlow(false)
, mIsImportant(false)
@@ -46,8 +46,12 @@ public:
Log::Warning("CScan::BuildDependencyTree not handling Echoes/Corruption dependencies");
CDependencyTree *pTree = new CDependencyTree(ID());
pTree->AddDependency(mpFrame);
pTree->AddDependency(mFrameID);
pTree->AddDependency(mpStringTable);
for (u32 iImg = 0; iImg < 4; iImg++)
pTree->AddDependency(mScanImageTextures[iImg]);
return pTree;
}

View File

@@ -44,7 +44,7 @@ public:
CDependencyTree* BuildDependencyTree() const
{
// The only dependencies STRGs have is they can reference FONTs with the &font=; formatting tag
// STRGs can reference FONTs with the &font=; formatting tag and TXTRs with the &image=; tag
CDependencyTree *pTree = new CDependencyTree(ID());
EIDLength IDLength = (Game() <= eEchoes ? e32Bit : e64Bit);
@@ -54,14 +54,69 @@ public:
for (u32 iStr = 0; iStr < rkTable.Strings.size(); iStr++)
{
static const TWideString skTag = L"&font=";
const TWideString& rkStr = rkTable.Strings[iStr];
for (u32 FontIdx = rkStr.IndexOfPhrase(*skTag); FontIdx != -1; FontIdx = rkStr.IndexOfPhrase(*skTag, FontIdx + 1))
for (u32 TagIdx = rkStr.IndexOf(L'&'); TagIdx != -1; TagIdx = rkStr.IndexOf(L'&', TagIdx + 1))
{
u32 IDStart = FontIdx + skTag.Size();
TWideString StrFontID = rkStr.SubString(IDStart, IDLength * 2);
pTree->AddDependency( CAssetID::FromString(StrFontID) );
// Check for double ampersand (escape character in DKCR, not sure about other games)
if (rkStr.At(TagIdx + 1) == L'&')
{
TagIdx++;
continue;
}
// Get tag name and parameters
u32 NameEnd = rkStr.IndexOf(L'=', TagIdx);
u32 TagEnd = rkStr.IndexOf(L';', TagIdx);
if (NameEnd == -1 || TagEnd == -1) continue;
TWideString TagName = rkStr.SubString(TagIdx + 1, NameEnd - TagIdx - 1);
TWideString ParamString = rkStr.SubString(NameEnd + 1, TagEnd - NameEnd - 1);
// Font
if (TagName == L"font")
{
ASSERT(ParamString.Size() == IDLength * 2);
pTree->AddDependency( CAssetID::FromString(ParamString) );
}
// Image
else if (TagName == L"image")
{
// Determine which params are textures based on image type
TWideStringList Params = ParamString.Split(L",");
TWideString ImageType = Params.front();
u32 TexturesStart = -1;
if (ImageType == L"A")
TexturesStart = 2;
else if (ImageType == L"SI")
TexturesStart = 3;
else if (ImageType == L"SA")
TexturesStart = 4;
else
{
Log::Error("Unrecognized image type: " + ImageType.ToUTF8());
DEBUG_BREAK;
continue;
}
// Load texture IDs
TWideStringList::iterator Iter = Params.begin();
for (u32 iParam = 0; iParam < Params.size(); iParam++, Iter++)
{
if (iParam >= TexturesStart)
{
TWideString Param = *Iter;
ASSERT(Param.Size() == IDLength * 2);
pTree->AddDependency( CAssetID::FromString(Param) );
}
}
}
}
}
}

View File

@@ -92,6 +92,7 @@ void Serialize(IArchive& rArc, CWorld::SArea& rArea)
<< SERIAL("BoundingBox", rArea.AetherBox)
<< SERIAL("AreaMREA", rArea.AreaResID)
<< SERIAL_HEX("AreaID", rArea.AreaID)
<< SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates)
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")

View File

@@ -11,6 +11,7 @@ class CWorld : public CResource
{
DECLARE_RESOURCE_TYPE(eWorld)
friend class CWorldLoader;
friend class CWorldCooker;
// Instances of CResource pointers are placeholders for unimplemented resource types (eg CMapWorld)
EGame mWorldVersion;
@@ -48,6 +49,7 @@ class CWorld : public CResource
CAABox AetherBox;
CAssetID AreaResID; // Loading every single area as a CResource would be a very bad idea
u64 AreaID;
bool AllowPakDuplicates;
std::vector<u16> AttachedAreaIDs;
std::vector<CAssetID> Dependencies;
@@ -103,11 +105,14 @@ public:
inline CResource* MapWorld() const { return mpMapWorld; }
inline u32 NumAreas() const { return mAreas.size(); }
inline u64 AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID.ToLongLong(); }
inline CAssetID AreaResourceID(u32 AreaIndex) const { return mAreas[AreaIndex].AreaResID; }
inline u32 AreaAttachedCount(u32 AreaIndex) const { return mAreas[AreaIndex].AttachedAreaIDs.size(); }
inline u32 AreaAttachedID(u32 AreaIndex, u32 AttachedIndex) const { return mAreas[AreaIndex].AttachedAreaIDs[AttachedIndex]; }
inline TString AreaInternalName(u32 AreaIndex) const { return mAreas[AreaIndex].InternalName; }
inline CStringTable* AreaName(u32 AreaIndex) const { return mAreas[AreaIndex].pAreaName; }
inline bool DoesAreaAllowPakDuplicates(u32 AreaIndex) const { return mAreas[AreaIndex].AllowPakDuplicates; }
inline void SetAreaAllowsPakDuplicates(u32 AreaIndex, bool Allow) { mAreas[AreaIndex].AllowPakDuplicates = Allow; }
};
#endif // CWORLD_H

View File

@@ -31,6 +31,4 @@ void CPoiToWorldCooker::WriteEGMC(CPoiToWorld *pPoiToWorld, IOutputStream& rOut)
rOut.WriteLong(Mappings[iMap].MeshID);
rOut.WriteLong(Mappings[iMap].PoiID);
}
rOut.WriteToBoundary(32, -1);
}

View File

@@ -1,9 +1,162 @@
#include "CWorldCooker.h"
#include "Core/GameProject/DependencyListBuilders.h"
CWorldCooker::CWorldCooker()
{
}
// ************ STATIC ************
bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
{
ASSERT(rMLVL.IsValid());
// MLVL Header
rMLVL.WriteLong(0xDEAFBABE);
rMLVL.WriteLong( GetMLVLVersion(pWorld->Game()) );
CAssetID WorldNameID = pWorld->mpWorldName ? pWorld->mpWorldName->ID() : CAssetID::skInvalidID32;
CAssetID SaveWorldID = pWorld->mpSaveWorld ? pWorld->mpSaveWorld->ID() : CAssetID::skInvalidID32;
CAssetID DefaultSkyID = pWorld->mpDefaultSkybox ? pWorld->mpDefaultSkybox->ID() : CAssetID::skInvalidID32;
WorldNameID.Write(rMLVL);
SaveWorldID.Write(rMLVL);
DefaultSkyID.Write(rMLVL);
// Memory Relays
rMLVL.WriteLong( pWorld->mMemoryRelays.size() );
for (u32 iMem = 0; iMem < pWorld->mMemoryRelays.size(); iMem++)
{
CWorld::SMemoryRelay& rRelay = pWorld->mMemoryRelays[iMem];
rMLVL.WriteLong(rRelay.InstanceID);
rMLVL.WriteLong(rRelay.TargetID);
rMLVL.WriteShort(rRelay.Message);
rMLVL.WriteByte(rRelay.Unknown);
}
// Areas
rMLVL.WriteLong(pWorld->mAreas.size());
rMLVL.WriteLong(1); // Unknown
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
{
// Area Header
CWorld::SArea& rArea = pWorld->mAreas[iArea];
CResourceEntry *pAreaEntry = gpResourceStore->FindEntry(rArea.AreaResID);
ASSERT(pAreaEntry && pAreaEntry->ResourceType() == eArea);
CAssetID AreaNameID = rArea.pAreaName ? rArea.pAreaName->ID() : CAssetID::skInvalidID32;
AreaNameID.Write(rMLVL);
rArea.Transform.Write(rMLVL);
rArea.AetherBox.Write(rMLVL);
rArea.AreaResID.Write(rMLVL);
rMLVL.WriteLong( (u32) rArea.AreaID );
// Attached Areas
rMLVL.WriteLong( rArea.AttachedAreaIDs.size() );
for (u32 iAttach = 0; iAttach < rArea.AttachedAreaIDs.size(); iAttach++)
rMLVL.WriteShort(rArea.AttachedAreaIDs[iAttach]);
// Dependencies
std::list<CAssetID> Dependencies;
std::list<u32> LayerDependsOffsets;
CAreaDependencyListBuilder Builder(pAreaEntry);
Builder.BuildDependencyList(Dependencies, LayerDependsOffsets);
rMLVL.WriteLong(0);
rMLVL.WriteLong( Dependencies.size() );
for (auto Iter = Dependencies.begin(); Iter != Dependencies.end(); Iter++)
{
CAssetID ID = *Iter;
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
ID.Write(rMLVL);
pEntry->CookedExtension().Write(rMLVL);
}
rMLVL.WriteLong(LayerDependsOffsets.size());
for (auto Iter = LayerDependsOffsets.begin(); Iter != LayerDependsOffsets.end(); Iter++)
rMLVL.WriteLong(*Iter);
// Docks
rMLVL.WriteLong( rArea.Docks.size() );
for (u32 iDock = 0; iDock < rArea.Docks.size(); iDock++)
{
CWorld::SArea::SDock& rDock = rArea.Docks[iDock];
rMLVL.WriteLong( rDock.ConnectingDocks.size() );
for (u32 iCon = 0; iCon < rDock.ConnectingDocks.size(); iCon++)
{
CWorld::SArea::SDock::SConnectingDock& rConDock = rDock.ConnectingDocks[iCon];
rMLVL.WriteLong(rConDock.AreaIndex);
rMLVL.WriteLong(rConDock.DockIndex);
}
rMLVL.WriteLong( rDock.DockCoordinates.size() );
for (u32 iCoord = 0; iCoord < rDock.DockCoordinates.size(); iCoord++)
rDock.DockCoordinates[iCoord].Write(rMLVL);
}
}
CAssetID MapWorldID = pWorld->mpMapWorld ? pWorld->mpMapWorld->ID() : CAssetID::skInvalidID32;
MapWorldID.Write(rMLVL);
rMLVL.WriteByte(0);
rMLVL.WriteLong(0);
// Audio Groups
rMLVL.WriteLong(pWorld->mAudioGrps.size());
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
{
CWorld::SAudioGrp& rAudioGroup = pWorld->mAudioGrps[iGrp];
rMLVL.WriteLong(rAudioGroup.Unknown);
rAudioGroup.ResID.Write(rMLVL);
}
rMLVL.WriteByte(0);
// Layers
rMLVL.WriteLong(pWorld->mAreas.size());
std::vector<TString> LayerNames;
std::vector<u32> LayerNameOffsets;
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
{
CWorld::SArea& rArea = pWorld->mAreas[iArea];
LayerNameOffsets.push_back(LayerNames.size());
rMLVL.WriteLong(rArea.Layers.size());
u64 LayerActiveFlags = -1;
for (u32 iLyr = 0; iLyr < rArea.Layers.size(); iLyr++)
{
CWorld::SArea::SLayer& rLayer = rArea.Layers[iLyr];
if (!rLayer.EnabledByDefault)
LayerActiveFlags &= ~(1 << iLyr);
LayerNames.push_back(rLayer.LayerName);
}
rMLVL.WriteLongLong(LayerActiveFlags);
}
rMLVL.WriteLong(LayerNames.size());
for (u32 iLyr = 0; iLyr < LayerNames.size(); iLyr++)
rMLVL.WriteString(LayerNames[iLyr].ToStdString());
rMLVL.WriteLong(LayerNameOffsets.size());
for (u32 iOff = 0; iOff < LayerNameOffsets.size(); iOff++)
rMLVL.WriteLong(LayerNameOffsets[iOff]);
return true;
}
u32 CWorldCooker::GetMLVLVersion(EGame Version)
{
switch (Version)

View File

@@ -1,6 +1,7 @@
#ifndef CWORLDCOOKER_H
#define CWORLDCOOKER_H
#include "Core/Resource/CWorld.h"
#include "Core/Resource/EGame.h"
#include <Common/types.h>
@@ -8,6 +9,7 @@ class CWorldCooker
{
CWorldCooker();
public:
static bool CookMLVL(CWorld *pWorld, IOutputStream& rOut);
static u32 GetMLVLVersion(EGame Version);
};

View File

@@ -681,6 +681,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
Loader.ReadSCLYPrime();
Loader.ReadCollision();
Loader.ReadLightsPrime();
Loader.ReadPATH();
break;
case eEchoesDemo:
Loader.ReadHeaderEchoes();
@@ -688,6 +689,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
Loader.ReadSCLYPrime();
Loader.ReadCollision();
Loader.ReadLightsPrime();
Loader.ReadPATH();
Loader.ReadPTLA();
Loader.ReadEGMC();
break;
case eEchoes:
@@ -696,6 +699,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
Loader.ReadLightsPrime();
Loader.ReadPATH();
Loader.ReadPTLA();
Loader.ReadEGMC();
break;
case eCorruptionProto:
@@ -704,6 +709,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
Loader.ReadLightsCorruption();
Loader.ReadPATH();
Loader.ReadPTLA();
Loader.ReadEGMC();
break;
case eCorruption:
@@ -715,6 +722,8 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
if (Loader.mVersion == eCorruption)
{
Loader.ReadLightsCorruption();
Loader.ReadPATH();
Loader.ReadPTLA();
Loader.ReadEGMC();
}
break;

View File

@@ -5,8 +5,8 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
{
// Only difference between versions is asset ID length. Just check for EOF with 32-bit ID length.
u32 Start = rDGRP.Tell();
rDGRP.Seek(DepCount * 4, SEEK_CUR);
u32 Remaining = rDGRP.Size() - Start;
rDGRP.Seek(DepCount * 8, SEEK_CUR);
u32 Remaining = rDGRP.Size() - rDGRP.Tell();
EGame Game = ePrimeDemo;
@@ -14,7 +14,9 @@ EGame CDependencyGroupLoader::VersionTest(IInputStream& rDGRP, u32 DepCount)
{
for (u32 iRem = 0; iRem < Remaining; iRem++)
{
if (rDGRP.ReadByte() != 0xFF)
u8 Byte = rDGRP.ReadByte();
if (Byte != 0xFF)
{
Game = eCorruptionProto;
break;

View File

@@ -120,7 +120,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
if (pMat->mOptions & CMaterial::eIndStage)
{
u32 IndTexIndex = mpFile->ReadLong();
pMat->mpIndirectTexture = mTextures[IndTexIndex];
pMat->mpIndirectTexture = mTextures[TextureIndices[IndTexIndex]];
}
// Color channels
@@ -162,7 +162,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
u8 TexSel = mpFile->ReadByte();
if ((TexSel == 0xFF) || (TexSel >= mTextures.size()))
if ((TexSel == 0xFF) || (TexSel >= TextureIndices.size()))
pPass->mpTexture = nullptr;
else
pPass->mpTexture = mTextures[TextureIndices[TexSel]];

View File

@@ -9,11 +9,18 @@ CScanLoader::CScanLoader()
CScan* CScanLoader::LoadScanMP1(IInputStream& rSCAN)
{
// Basic support at the moment - don't read animation/scan image data
rSCAN.Seek(0x4, SEEK_CUR); // Skip FRME ID
mpScan->mFrameID = CAssetID(rSCAN, e32Bit);
mpScan->mpStringTable = gpResourceStore->LoadResource(rSCAN.ReadLong(), "STRG");
mpScan->mIsSlow = (rSCAN.ReadLong() != 0);
mpScan->mCategory = (CScan::ELogbookCategory) rSCAN.ReadLong();
mpScan->mIsImportant = (rSCAN.ReadByte() == 1);
for (u32 iImg = 0; iImg < 4; iImg++)
{
mpScan->mScanImageTextures[iImg] = CAssetID(rSCAN, e32Bit);
rSCAN.Seek(0x18, SEEK_CUR);
}
mpScan->mVersion = ePrime;
return mpScan;
}

View File

@@ -33,24 +33,17 @@ CModel::~CModel()
CDependencyTree* CModel::BuildDependencyTree() const
{
CDependencyTree *pTree = new CDependencyTree(ID());
std::set<CAssetID> TextureIDs;
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
{
CMaterialSet *pSet = mMaterialSets[iSet];
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
{
CMaterial *pMat = pSet->MaterialByIndex(iMat);
pTree->AddDependency(pMat->IndTexture());
for (u32 iPass = 0; iPass < pMat->PassCount(); iPass++)
{
CMaterialPass *pPass = pMat->Pass(iPass);
pTree->AddDependency(pPass->Texture());
}
}
pSet->GetUsedTextureIDs(TextureIDs);
}
for (auto Iter = TextureIDs.begin(); Iter != TextureIDs.end(); Iter++)
pTree->AddDependency(*Iter);
return pTree;
}