Added versioning support to the serializer; began restructuring CWorld and getting world cooking/serialization working for other games; gave CAssetID an alternate input stream constructor that takes an EGame instead of an EIDLength

This commit is contained in:
parax0 2016-08-14 04:56:51 -06:00
parent ba438383b4
commit 8f2b39469a
41 changed files with 304 additions and 200 deletions

View File

@ -53,6 +53,11 @@ CAssetID::CAssetID(IInputStream& rInput, EIDLength Length)
else mID = rInput.ReadLongLong(); else mID = rInput.ReadLongLong();
} }
CAssetID::CAssetID(IInputStream& rInput, EGame Game)
{
*this = CAssetID(rInput, (Game <= eEchoes ? e32Bit : e64Bit));
}
TString CAssetID::ToString() const TString CAssetID::ToString() const
{ {
if (mLength == e32Bit) if (mLength == e32Bit)

View File

@ -1,6 +1,7 @@
#ifndef CASSETID_H #ifndef CASSETID_H
#define CASSETID_H #define CASSETID_H
#include "EGame.h"
#include "TString.h" #include "TString.h"
#include "types.h" #include "types.h"
#include <FileIO/FileIO.h> #include <FileIO/FileIO.h>
@ -23,6 +24,7 @@ public:
CAssetID(u64 ID, EIDLength Length); CAssetID(u64 ID, EIDLength Length);
CAssetID(const char* pkID); CAssetID(const char* pkID);
CAssetID(IInputStream& rInput, EIDLength Length); CAssetID(IInputStream& rInput, EIDLength Length);
CAssetID(IInputStream& rInput, EGame Game);
void Write(IOutputStream& rOutput) const; void Write(IOutputStream& rOutput) const;
TString ToString() const; TString ToString() const;
bool IsValid() const; bool IsValid() const;
@ -49,6 +51,9 @@ public:
static CAssetID FromString(const TString& rkString); static CAssetID FromString(const TString& rkString);
static CAssetID RandomID(); static CAssetID RandomID();
inline static CAssetID InvalidID(EIDLength IDLength) { return (IDLength == e32Bit ? skInvalidID32 : skInvalidID64); }
inline static CAssetID InvalidID(EGame Game) { return InvalidID(Game <= eEchoes ? e32Bit : e64Bit); }
static CAssetID skInvalidID32; static CAssetID skInvalidID32;
static CAssetID skInvalidID64; static CAssetID skInvalidID64;
}; };

View File

@ -91,4 +91,5 @@ SOURCES += \
TString.cpp \ TString.cpp \
Log.cpp \ Log.cpp \
FileUtil.cpp \ FileUtil.cpp \
CAssetID.cpp CAssetID.cpp \
EGame.cpp

29
src/Common/EGame.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "EGame.h"
#include "CFourCC.h"
CFourCC GetGameID(EGame Game)
{
switch (Game)
{
case ePrimeDemo: return "MP1D";
case ePrime: return "MP1 ";
case eEchoesDemo: return "MP2D";
case eEchoes: return "MP2E";
case eCorruptionProto: return "MP3P";
case eCorruption: return "MP3C";
case eReturns: return "DKCR";
default: return "UNKN";
}
}
EGame GetGameForID(const CFourCC& rkID)
{
if (rkID == "MP1D") return ePrimeDemo;
if (rkID == "MP1 ") return ePrime;
if (rkID == "MP2D") return eEchoesDemo;
if (rkID == "MP2E") return eEchoes;
if (rkID == "MP3P") return eCorruptionProto;
if (rkID == "MP3C") return eCorruption;
if (rkID == "DKCR") return eReturns;
return eUnknownGame;
}

View File

@ -1,6 +1,11 @@
#ifndef EGAME_H #ifndef EGAME_H
#define EGAME_H #define EGAME_H
#include "TString.h"
#include "types.h"
class CFourCC;
enum EGame enum EGame
{ {
ePrimeDemo, ePrimeDemo,
@ -13,4 +18,7 @@ enum EGame
eUnknownGame = -1 eUnknownGame = -1
}; };
CFourCC GetGameID(EGame Game);
EGame GetGameForID(const CFourCC& rkID);
#endif // EGAME_H #endif // EGAME_H

View File

@ -15,9 +15,15 @@ public:
: IArchive() : IArchive()
, mJustEndedParam(false) , mJustEndedParam(false)
{ {
// Load XML and set current element to the root element // Load XML and set current element to the root element; read version
mDoc.LoadFile(*rkFileName); mDoc.LoadFile(*rkFileName);
mpCurElem = mDoc.FirstChildElement(); mpCurElem = mDoc.FirstChildElement();
ASSERT(mpCurElem != nullptr);
mFileVersion = TString( mpCurElem->Attribute("FileVer") ).ToInt32(10);
mArchiveVersion = TString( mpCurElem->Attribute("ArchiveVer") ).ToInt32(10);
const char *pkGameAttr = mpCurElem->Attribute("Game");
mGame = pkGameAttr ? eUnknownGame : GetGameForID( CFourCC(pkGameAttr) );
} }
protected: protected:

View File

@ -2,6 +2,7 @@
#define CXMLWRITER #define CXMLWRITER
#include "IArchive.h" #include "IArchive.h"
#include "Common/CFourCC.h"
#include <iostream> #include <iostream>
#include <tinyxml2.h> #include <tinyxml2.h>
@ -12,16 +13,24 @@ class CXMLWriter : public IArchive
tinyxml2::XMLElement *mpCurElem; tinyxml2::XMLElement *mpCurElem;
public: public:
CXMLWriter(const TString& rkRootName, const TString& rkFileName) CXMLWriter(const TString& rkFileName, const TString& rkRootName, u32 FileVersion, EGame Game = eUnknownGame)
: IArchive() : IArchive()
, mOutFilename(rkFileName) , mOutFilename(rkFileName)
{ {
mFileVersion = FileVersion;
mGame = Game;
// Create declaration and root node // Create declaration and root node
tinyxml2::XMLDeclaration *pDecl = mDoc.NewDeclaration(); tinyxml2::XMLDeclaration *pDecl = mDoc.NewDeclaration();
mDoc.LinkEndChild(pDecl); mDoc.LinkEndChild(pDecl);
mpCurElem = mDoc.NewElement(*rkRootName); mpCurElem = mDoc.NewElement(*rkRootName);
mDoc.LinkEndChild(mpCurElem); mDoc.LinkEndChild(mpCurElem);
// Write version data
mpCurElem->SetAttribute("FileVer", (int) FileVersion);
mpCurElem->SetAttribute("ArchiveVer", (int) skCurrentArchiveVersion);
if (Game != eUnknownGame) mpCurElem->SetAttribute("Game", *GetGameID(Game).ToString());
} }
~CXMLWriter() ~CXMLWriter()

View File

@ -3,6 +3,7 @@
#include "Common/AssertMacro.h" #include "Common/AssertMacro.h"
#include "Common/CAssetID.h" #include "Common/CAssetID.h"
#include "Common/EGame.h"
#include "Common/TString.h" #include "Common/TString.h"
#include "Common/types.h" #include "Common/types.h"
@ -164,8 +165,15 @@ public:
// Actual archive class // Actual archive class
class IArchive class IArchive
{ {
protected:
s32 mFileVersion;
s32 mArchiveVersion;
EGame mGame;
public: public:
IArchive() {} static const u32 skCurrentArchiveVersion = 0;
IArchive() : mFileVersion(0), mArchiveVersion(skCurrentArchiveVersion), mGame(eUnknownGame) {}
virtual ~IArchive() {} virtual ~IArchive() {}
#define ENABLE_FOR_SERIAL_TYPE(SType) typename std::enable_if<SerialType<ValType, IArchive>::Type == SerialType<ValType, IArchive>::##SType, int>::type = 0 #define ENABLE_FOR_SERIAL_TYPE(SType) typename std::enable_if<SerialType<ValType, IArchive>::Type == SerialType<ValType, IArchive>::##SType, int>::type = 0
@ -381,6 +389,11 @@ public:
virtual void SerializeHexPrimitive(u32& rValue) = 0; virtual void SerializeHexPrimitive(u32& rValue) = 0;
virtual void SerializeHexPrimitive(s64& rValue) = 0; virtual void SerializeHexPrimitive(s64& rValue) = 0;
virtual void SerializeHexPrimitive(u64& rValue) = 0; virtual void SerializeHexPrimitive(u64& rValue) = 0;
// Accessors
inline u32 FileVersion() const { return mFileVersion; }
inline u32 ArchiveVersion() const { return mArchiveVersion; }
inline EGame Game() const { return mGame; }
}; };
// Container serialize methods // Container serialize methods

View File

@ -244,7 +244,7 @@ bool CResourceEntry::Save()
TString Dir = Path.GetFileDirectory(); TString Dir = Path.GetFileDirectory();
FileUtil::CreateDirectory(Dir.ToUTF16()); FileUtil::CreateDirectory(Dir.ToUTF16());
CXMLWriter Writer(GetResourceSerialName(ResourceType()), Path); CXMLWriter Writer(Path, GetResourceSerialName(ResourceType()), 0, mGame);
mpResource->Serialize(Writer); mpResource->Serialize(Writer);
} }

View File

@ -234,6 +234,8 @@ public:
// For PlayerActor animsets we want to include only the empty suit (char 5) in the dependency list. This is to // For PlayerActor animsets we want to include only the empty suit (char 5) in the dependency list. This is to
// accomodate the dynamic loading the game does for PlayerActors to avoid having assets for suits the player // accomodate the dynamic loading the game does for PlayerActors to avoid having assets for suits the player
// doesn't have in memory. We want common assets (animations, etc) in the list but not per-character assets. // doesn't have in memory. We want common assets (animations, etc) in the list but not per-character assets.
// The reason to include empty suit is to make sure resources that are stored as per-character data but are
// actually common to every character, such as particle effects, are still included in the list.
ASSERT(pEntry->ResourceType() == eAnimSet); ASSERT(pEntry->ResourceType() == eAnimSet);
CAnimSetDependencyTree *pTree = static_cast<CAnimSetDependencyTree*>(pEntry->Dependencies()); CAnimSetDependencyTree *pTree = static_cast<CAnimSetDependencyTree*>(pEntry->Dependencies());
mLayerUsedAssets.insert(pTree->ID()); mLayerUsedAssets.insert(pTree->ID());

View File

@ -24,7 +24,6 @@ class CGameArea : public CResource
friend class CAreaLoader; friend class CAreaLoader;
friend class CAreaCooker; friend class CAreaCooker;
EGame mVersion;
u32 mWorldIndex; u32 mWorldIndex;
u32 mVertexCount; u32 mVertexCount;
u32 mTriangleCount; u32 mTriangleCount;
@ -84,7 +83,6 @@ public:
void DeleteInstance(CScriptObject *pInstance); void DeleteInstance(CScriptObject *pInstance);
// Inline Accessors // Inline Accessors
inline EGame Version() const { return mVersion; }
inline u32 WorldIndex() const { return mWorldIndex; } inline u32 WorldIndex() const { return mWorldIndex; }
inline CTransform4f Transform() const { return mTransform; } inline CTransform4f Transform() const { return mTransform; }
inline u32 NumWorldModels() const { return mWorldModels.size(); } inline u32 NumWorldModels() const { return mWorldModels.size(); }

View File

@ -4,7 +4,6 @@
CWorld::CWorld(CResourceEntry *pEntry /*= 0*/) CWorld::CWorld(CResourceEntry *pEntry /*= 0*/)
: CResource(pEntry) : CResource(pEntry)
, mWorldVersion(eUnknownGame)
, mpWorldName(nullptr) , mpWorldName(nullptr)
, mpDarkWorldName(nullptr) , mpDarkWorldName(nullptr)
, mpSaveWorld(nullptr) , mpSaveWorld(nullptr)
@ -56,24 +55,32 @@ void CWorld::SetAreaLayerInfo(CGameArea *pArea)
SArea::SLayer& rLayerInfo = AreaInfo.Layers[iLyr]; SArea::SLayer& rLayerInfo = AreaInfo.Layers[iLyr];
pLayer->SetName(rLayerInfo.LayerName); pLayer->SetName(rLayerInfo.LayerName);
pLayer->SetActive(rLayerInfo.EnabledByDefault); pLayer->SetActive(rLayerInfo.Active);
} }
} }
// ************ SERIALIZATION ************ // ************ SERIALIZATION ************
void CWorld::Serialize(IArchive& rArc) void CWorld::Serialize(IArchive& rArc)
{ {
rArc << SERIAL("WorldNameSTRG", mpWorldName) rArc << SERIAL("WorldNameSTRG", mpWorldName);
<< SERIAL("DarkWorldNameSTRG", mpDarkWorldName)
<< SERIAL("WorldSaveInfo", mpSaveWorld) if (rArc.Game() == eEchoesDemo || rArc.Game() == eEchoes)
<< SERIAL("DefaultSkyCMDL", mpDefaultSkybox) rArc << SERIAL("DarkWorldNameSTRG", mpDarkWorldName);
<< SERIAL("MapWorld", mpMapWorld)
<< SERIAL("Unknown1", mUnknown1) rArc << SERIAL("WorldSaveInfo", mpSaveWorld)
<< SERIAL("UnknownAreas", mUnknownAreas) << SERIAL("WorldMap", mpMapWorld)
<< SERIAL("UnknownAGSC", mUnknownAGSC) << SERIAL("DefaultSkyCMDL", mpDefaultSkybox);
<< SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay")
<< SERIAL_CONTAINER("Areas", mAreas, "Area") if (rArc.Game() >= eEchoesDemo && rArc.Game() <= eCorruption)
<< SERIAL_CONTAINER("AudioGroups", mAudioGrps, "AudioGroup"); rArc << SERIAL("TempleKeyWorldIndex", mTempleKeyWorldIndex);
if (rArc.Game() == ePrime)
rArc << SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay");
rArc << SERIAL_CONTAINER("Areas", mAreas, "Area");
if (rArc.Game() <= ePrime)
rArc << SERIAL_CONTAINER("AudioGroups", mAudioGrps, "AudioGroup");
} }
void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay) void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay)
@ -81,7 +88,7 @@ void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay)
rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID) rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID)
<< SERIAL_HEX("TargetID", rMemRelay.TargetID) << SERIAL_HEX("TargetID", rMemRelay.TargetID)
<< SERIAL("Message", rMemRelay.Message) << SERIAL("Message", rMemRelay.Message)
<< SERIAL("Unknown", rMemRelay.Unknown); << SERIAL("Active", rMemRelay.Active);
} }
void Serialize(IArchive& rArc, CWorld::SArea& rArea) void Serialize(IArchive& rArc, CWorld::SArea& rArea)
@ -91,13 +98,11 @@ void Serialize(IArchive& rArc, CWorld::SArea& rArea)
<< SERIAL("Transform", rArea.Transform) << SERIAL("Transform", rArea.Transform)
<< SERIAL("BoundingBox", rArea.AetherBox) << SERIAL("BoundingBox", rArea.AetherBox)
<< SERIAL("AreaMREA", rArea.AreaResID) << SERIAL("AreaMREA", rArea.AreaResID)
<< SERIAL_HEX("AreaID", rArea.AreaID) << SERIAL("AreaID", rArea.AreaID)
<< SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates) << SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates)
<< SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex") << SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex")
<< SERIAL_CONTAINER("Dependencies", rArea.Dependencies, "Dependency")
<< SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module") << SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module")
<< SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset") << SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset")
<< SERIAL("CommonDependsStart", rArea.CommonDependenciesStart)
<< SERIAL_CONTAINER("Docks", rArea.Docks, "Dock") << SERIAL_CONTAINER("Docks", rArea.Docks, "Dock")
<< SERIAL_CONTAINER("Layers", rArea.Layers, "Layer"); << SERIAL_CONTAINER("Layers", rArea.Layers, "Layer");
} }
@ -117,12 +122,11 @@ void Serialize(IArchive& rArc, CWorld::SArea::SDock::SConnectingDock& rDock)
void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer) void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer)
{ {
rArc << SERIAL("Name", rLayer.LayerName) rArc << SERIAL("Name", rLayer.LayerName)
<< SERIAL("DefaultEnabled", rLayer.EnabledByDefault) << SERIAL("Active", rLayer.Active);
<< SERIAL("LayerDependsStart", rLayer.LayerDependenciesStart);
} }
void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp) void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp)
{ {
rArc << SERIAL("StudioID", rAudioGrp.Unknown) rArc << SERIAL("GroupID", rAudioGrp.GroupID)
<< SERIAL("AGSC", rAudioGrp.ResID); << SERIAL("AGSC", rAudioGrp.ResID);
} }

View File

@ -14,21 +14,17 @@ class CWorld : public CResource
friend class CWorldCooker; friend class CWorldCooker;
// Instances of CResource pointers are placeholders for unimplemented resource types (eg CMapWorld) // Instances of CResource pointers are placeholders for unimplemented resource types (eg CMapWorld)
EGame mWorldVersion;
TResPtr<CStringTable> mpWorldName; TResPtr<CStringTable> mpWorldName;
TResPtr<CStringTable> mpDarkWorldName; TResPtr<CStringTable> mpDarkWorldName;
TResPtr<CResource> mpSaveWorld; TResPtr<CResource> mpSaveWorld;
TResPtr<CModel> mpDefaultSkybox; TResPtr<CModel> mpDefaultSkybox;
TResPtr<CResource> mpMapWorld; TResPtr<CResource> mpMapWorld;
u32 mTempleKeyWorldIndex;
u32 mUnknown1;
u32 mUnknownAreas;
u32 mUnknownAGSC;
struct SAudioGrp struct SAudioGrp
{ {
CAssetID ResID; CAssetID ResID;
u32 Unknown; u32 GroupID;
}; };
std::vector<SAudioGrp> mAudioGrps; std::vector<SAudioGrp> mAudioGrps;
@ -37,7 +33,7 @@ class CWorld : public CResource
u32 InstanceID; u32 InstanceID;
u32 TargetID; u32 TargetID;
u16 Message; u16 Message;
u8 Unknown; bool Active;
}; };
std::vector<SMemoryRelay> mMemoryRelays; std::vector<SMemoryRelay> mMemoryRelays;
@ -47,15 +43,14 @@ class CWorld : public CResource
TResPtr<CStringTable> pAreaName; TResPtr<CStringTable> pAreaName;
CTransform4f Transform; CTransform4f Transform;
CAABox AetherBox; CAABox AetherBox;
CAssetID AreaResID; // Loading every single area as a CResource would be a very bad idea CAssetID AreaResID; // Area resource ID
u64 AreaID; CAssetID AreaID; // Internal area ID (same length as an asset ID)
bool AllowPakDuplicates; bool AllowPakDuplicates;
std::vector<SMemoryRelay> MemoryRelays; // Only needed for MP1
std::vector<u16> AttachedAreaIDs; std::vector<u16> AttachedAreaIDs;
std::vector<CAssetID> Dependencies; std::vector<TString> RelFilenames; // Needs to be removed & generated at cook; temporarily leaving for debugging
std::vector<TString> RelFilenames;
std::vector<u32> RelOffsets; std::vector<u32> RelOffsets;
u32 CommonDependenciesStart;
struct SDock struct SDock
{ {
@ -72,9 +67,8 @@ class CWorld : public CResource
struct SLayer struct SLayer
{ {
TString LayerName; TString LayerName;
bool EnabledByDefault; bool Active;
u8 LayerID[16]; u8 LayerID[16];
u32 LayerDependenciesStart; // Offset into Dependencies vector
}; };
std::vector<SLayer> Layers; std::vector<SLayer> Layers;
}; };
@ -97,7 +91,6 @@ public:
friend void Serialize(IArchive& rArc, SAudioGrp& rAudioGrp); friend void Serialize(IArchive& rArc, SAudioGrp& rAudioGrp);
// Accessors // Accessors
inline EGame Version() const { return mWorldVersion; }
inline CStringTable* WorldName() const { return mpWorldName; } inline CStringTable* WorldName() const { return mpWorldName; }
inline CStringTable* DarkWorldName() const { return mpDarkWorldName; } inline CStringTable* DarkWorldName() const { return mpDarkWorldName; }
inline CResource* SaveWorld() const { return mpSaveWorld; } inline CResource* SaveWorld() const { return mpSaveWorld; }

View File

@ -310,7 +310,7 @@ void CAreaCooker::WriteCookedArea(CGameArea *pArea, IOutputStream& rOut)
{ {
CAreaCooker Cooker; CAreaCooker Cooker;
Cooker.mpArea = pArea; Cooker.mpArea = pArea;
Cooker.mVersion = pArea->Version(); Cooker.mVersion = pArea->Game();
if (Cooker.mVersion <= eEchoes) if (Cooker.mVersion <= eEchoes)
Cooker.DetermineSectionNumbersPrime(); Cooker.DetermineSectionNumbersPrime();

View File

@ -9,20 +9,31 @@ CWorldCooker::CWorldCooker()
bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL) bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
{ {
ASSERT(rMLVL.IsValid()); ASSERT(rMLVL.IsValid());
EGame Game = pWorld->Game();
// MLVL Header // MLVL Header
rMLVL.WriteLong(0xDEAFBABE); rMLVL.WriteLong(0xDEAFBABE);
rMLVL.WriteLong( GetMLVLVersion(pWorld->Game()) ); rMLVL.WriteLong( GetMLVLVersion(pWorld->Game()) );
CAssetID WorldNameID = pWorld->mpWorldName ? pWorld->mpWorldName->ID() : CAssetID::skInvalidID32; CAssetID WorldNameID = pWorld->mpWorldName ? pWorld->mpWorldName->ID() : CAssetID::InvalidID(Game);
CAssetID SaveWorldID = pWorld->mpSaveWorld ? pWorld->mpSaveWorld->ID() : CAssetID::skInvalidID32; CAssetID DarkWorldNameID = pWorld->mpDarkWorldName ? pWorld->mpDarkWorldName->ID() : CAssetID::InvalidID(Game);
CAssetID DefaultSkyID = pWorld->mpDefaultSkybox ? pWorld->mpDefaultSkybox->ID() : CAssetID::skInvalidID32; CAssetID SaveWorldID = pWorld->mpSaveWorld ? pWorld->mpSaveWorld->ID() : CAssetID::InvalidID(Game);
CAssetID DefaultSkyID = pWorld->mpDefaultSkybox ? pWorld->mpDefaultSkybox->ID() : CAssetID::InvalidID(Game);
WorldNameID.Write(rMLVL); WorldNameID.Write(rMLVL);
if (Game == eEchoesDemo || Game == eEchoes)
{
DarkWorldNameID.Write(rMLVL);
rMLVL.WriteLong(0);
}
SaveWorldID.Write(rMLVL); SaveWorldID.Write(rMLVL);
DefaultSkyID.Write(rMLVL); DefaultSkyID.Write(rMLVL);
// Memory Relays // Memory Relays
if (Game == ePrime)
{
rMLVL.WriteLong( pWorld->mMemoryRelays.size() ); rMLVL.WriteLong( pWorld->mMemoryRelays.size() );
for (u32 iMem = 0; iMem < pWorld->mMemoryRelays.size(); iMem++) for (u32 iMem = 0; iMem < pWorld->mMemoryRelays.size(); iMem++)
@ -31,12 +42,13 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
rMLVL.WriteLong(rRelay.InstanceID); rMLVL.WriteLong(rRelay.InstanceID);
rMLVL.WriteLong(rRelay.TargetID); rMLVL.WriteLong(rRelay.TargetID);
rMLVL.WriteShort(rRelay.Message); rMLVL.WriteShort(rRelay.Message);
rMLVL.WriteByte(rRelay.Unknown); rMLVL.WriteBool(rRelay.Active);
}
} }
// Areas // Areas
rMLVL.WriteLong(pWorld->mAreas.size()); rMLVL.WriteLong(pWorld->mAreas.size());
rMLVL.WriteLong(1); // Unknown if (Game <= ePrime) rMLVL.WriteLong(1); // Unknown
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++) for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
{ {
@ -45,20 +57,25 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
CResourceEntry *pAreaEntry = gpResourceStore->FindEntry(rArea.AreaResID); CResourceEntry *pAreaEntry = gpResourceStore->FindEntry(rArea.AreaResID);
ASSERT(pAreaEntry && pAreaEntry->ResourceType() == eArea); ASSERT(pAreaEntry && pAreaEntry->ResourceType() == eArea);
CAssetID AreaNameID = rArea.pAreaName ? rArea.pAreaName->ID() : CAssetID::skInvalidID32; CAssetID AreaNameID = rArea.pAreaName ? rArea.pAreaName->ID() : CAssetID::InvalidID(Game);
AreaNameID.Write(rMLVL); AreaNameID.Write(rMLVL);
rArea.Transform.Write(rMLVL); rArea.Transform.Write(rMLVL);
rArea.AetherBox.Write(rMLVL); rArea.AetherBox.Write(rMLVL);
rArea.AreaResID.Write(rMLVL); rArea.AreaResID.Write(rMLVL);
rMLVL.WriteLong( (u32) rArea.AreaID ); rArea.AreaID.Write(rMLVL);
// Attached Areas // Attached Areas
if (Game <= eCorruption)
{
rMLVL.WriteLong( rArea.AttachedAreaIDs.size() ); rMLVL.WriteLong( rArea.AttachedAreaIDs.size() );
for (u32 iAttach = 0; iAttach < rArea.AttachedAreaIDs.size(); iAttach++) for (u32 iAttach = 0; iAttach < rArea.AttachedAreaIDs.size(); iAttach++)
rMLVL.WriteShort(rArea.AttachedAreaIDs[iAttach]); rMLVL.WriteShort(rArea.AttachedAreaIDs[iAttach]);
}
// Dependencies // Dependencies
if (Game <= eEchoes)
{
std::list<CAssetID> Dependencies; std::list<CAssetID> Dependencies;
std::list<u32> LayerDependsOffsets; std::list<u32> LayerDependsOffsets;
CAreaDependencyListBuilder Builder(pAreaEntry); CAreaDependencyListBuilder Builder(pAreaEntry);
@ -79,8 +96,11 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
for (auto Iter = LayerDependsOffsets.begin(); Iter != LayerDependsOffsets.end(); Iter++) for (auto Iter = LayerDependsOffsets.begin(); Iter != LayerDependsOffsets.end(); Iter++)
rMLVL.WriteLong(*Iter); rMLVL.WriteLong(*Iter);
}
// Docks // Docks
if (Game <= eCorruption)
{
rMLVL.WriteLong( rArea.Docks.size() ); rMLVL.WriteLong( rArea.Docks.size() );
for (u32 iDock = 0; iDock < rArea.Docks.size(); iDock++) for (u32 iDock = 0; iDock < rArea.Docks.size(); iDock++)
@ -102,28 +122,58 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
} }
} }
// Module Dependencies
if (Game == eEchoesDemo || Game == eEchoes)
{
std::vector<TString> ModuleNames;
std::vector<u32> ModuleLayerOffsets;
CAreaDependencyTree *pAreaDeps = static_cast<CAreaDependencyTree*>(pAreaEntry->Dependencies());
pAreaDeps->GetModuleDependencies(Game, ModuleNames, ModuleLayerOffsets);
rMLVL.WriteLong(ModuleNames.size());
for (u32 iMod = 0; iMod < ModuleNames.size(); iMod++)
rMLVL.WriteString(ModuleNames[iMod].ToStdString());
rMLVL.WriteLong(ModuleLayerOffsets.size());
for (u32 iOff = 0; iOff < ModuleLayerOffsets.size(); iOff++)
rMLVL.WriteLong(ModuleLayerOffsets[iOff]);
}
}
if (Game <= eCorruption)
{
// World Map
CAssetID MapWorldID = pWorld->mpMapWorld ? pWorld->mpMapWorld->ID() : CAssetID::skInvalidID32; CAssetID MapWorldID = pWorld->mpMapWorld ? pWorld->mpMapWorld->ID() : CAssetID::skInvalidID32;
MapWorldID.Write(rMLVL); MapWorldID.Write(rMLVL);
// Script Layer - unused in all retail builds but this will need to be supported eventually to properly support the MP1 demo
rMLVL.WriteByte(0); rMLVL.WriteByte(0);
rMLVL.WriteLong(0); rMLVL.WriteLong(0);
}
// Audio Groups // Audio Groups
if (Game <= ePrime)
{
rMLVL.WriteLong(pWorld->mAudioGrps.size()); rMLVL.WriteLong(pWorld->mAudioGrps.size());
for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++) for (u32 iGrp = 0; iGrp < pWorld->mAudioGrps.size(); iGrp++)
{ {
CWorld::SAudioGrp& rAudioGroup = pWorld->mAudioGrps[iGrp]; CWorld::SAudioGrp& rAudioGroup = pWorld->mAudioGrps[iGrp];
rMLVL.WriteLong(rAudioGroup.Unknown); rMLVL.WriteLong(rAudioGroup.GroupID);
rAudioGroup.ResID.Write(rMLVL); rAudioGroup.ResID.Write(rMLVL);
} }
rMLVL.WriteByte(0); rMLVL.WriteByte(0);
}
// Layers // Layers
rMLVL.WriteLong(pWorld->mAreas.size()); rMLVL.WriteLong(pWorld->mAreas.size());
std::vector<TString> LayerNames; std::vector<TString> LayerNames;
std::vector<u32> LayerNameOffsets; std::vector<u32> LayerNameOffsets;
// Layer Flags
for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++) for (u32 iArea = 0; iArea < pWorld->mAreas.size(); iArea++)
{ {
CWorld::SArea& rArea = pWorld->mAreas[iArea]; CWorld::SArea& rArea = pWorld->mAreas[iArea];
@ -135,7 +185,7 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
for (u32 iLyr = 0; iLyr < rArea.Layers.size(); iLyr++) for (u32 iLyr = 0; iLyr < rArea.Layers.size(); iLyr++)
{ {
CWorld::SArea::SLayer& rLayer = rArea.Layers[iLyr]; CWorld::SArea::SLayer& rLayer = rArea.Layers[iLyr];
if (!rLayer.EnabledByDefault) if (!rLayer.Active)
LayerActiveFlags &= ~(1 << iLyr); LayerActiveFlags &= ~(1 << iLyr);
LayerNames.push_back(rLayer.LayerName); LayerNames.push_back(rLayer.LayerName);
@ -144,11 +194,18 @@ bool CWorldCooker::CookMLVL(CWorld *pWorld, IOutputStream& rMLVL)
rMLVL.WriteLongLong(LayerActiveFlags); rMLVL.WriteLongLong(LayerActiveFlags);
} }
// Layer Names
rMLVL.WriteLong(LayerNames.size()); rMLVL.WriteLong(LayerNames.size());
for (u32 iLyr = 0; iLyr < LayerNames.size(); iLyr++) for (u32 iLyr = 0; iLyr < LayerNames.size(); iLyr++)
rMLVL.WriteString(LayerNames[iLyr].ToStdString()); rMLVL.WriteString(LayerNames[iLyr].ToStdString());
// todo: Layer Saved State IDs go here for MP3/DKCR; need support for saved state IDs to implement
if (Game == eCorruption || Game == eReturns)
{
}
// Layer Name Offsets
rMLVL.WriteLong(LayerNameOffsets.size()); rMLVL.WriteLong(LayerNameOffsets.size());
for (u32 iOff = 0; iOff < LayerNameOffsets.size(); iOff++) for (u32 iOff = 0; iOff < LayerNameOffsets.size(); iOff++)

View File

@ -590,19 +590,19 @@ void CAreaLoader::ReadCollision()
void CAreaLoader::ReadPATH() void CAreaLoader::ReadPATH()
{ {
mpSectionMgr->ToSection(mPathBlockNum); mpSectionMgr->ToSection(mPathBlockNum);
mpArea->mPathID = CAssetID(*mpMREA, (mVersion <= eEchoes ? e32Bit : e64Bit)); mpArea->mPathID = CAssetID(*mpMREA, mVersion);
} }
void CAreaLoader::ReadPTLA() void CAreaLoader::ReadPTLA()
{ {
mpSectionMgr->ToSection(this->mPTLABlockNum); mpSectionMgr->ToSection(this->mPTLABlockNum);
mpArea->mPortalAreaID = CAssetID(*mpMREA, (mVersion <= eEchoes ? e32Bit : e64Bit)); mpArea->mPortalAreaID = CAssetID(*mpMREA, mVersion);
} }
void CAreaLoader::ReadEGMC() void CAreaLoader::ReadEGMC()
{ {
mpSectionMgr->ToSection(mEGMCBlockNum); mpSectionMgr->ToSection(mEGMCBlockNum);
CAssetID EGMC(*mpMREA, (mVersion <= eEchoes ? e32Bit : e64Bit)); CAssetID EGMC(*mpMREA, mVersion);
mpArea->mpPoiToWorldMap = gpResourceStore->LoadResource(EGMC, "EGMC"); mpArea->mpPoiToWorldMap = gpResourceStore->LoadResource(EGMC, "EGMC");
} }
@ -669,7 +669,6 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA, CResourceEntry *pEntry)
u32 Version = MREA.ReadLong(); u32 Version = MREA.ReadLong();
Loader.mVersion = GetFormatVersion(Version); Loader.mVersion = GetFormatVersion(Version);
Loader.mpArea->SetGame(Loader.mVersion); Loader.mpArea->SetGame(Loader.mVersion);
Loader.mpArea->mVersion = Loader.mVersion;
Loader.mpMREA = &MREA; Loader.mpMREA = &MREA;
switch (Loader.mVersion) switch (Loader.mVersion)

View File

@ -34,7 +34,6 @@ CDependencyGroup* CDependencyGroupLoader::LoadDGRP(IInputStream& rDGRP, CResourc
u32 NumDependencies = rDGRP.ReadLong(); u32 NumDependencies = rDGRP.ReadLong();
EGame Game = VersionTest(rDGRP, NumDependencies); EGame Game = VersionTest(rDGRP, NumDependencies);
EIDLength IDLength = (Game < eCorruptionProto ? e32Bit : e64Bit);
CDependencyGroup *pGroup = new CDependencyGroup(pEntry); CDependencyGroup *pGroup = new CDependencyGroup(pEntry);
pGroup->SetGame(Game); pGroup->SetGame(Game);
@ -42,7 +41,7 @@ CDependencyGroup* CDependencyGroupLoader::LoadDGRP(IInputStream& rDGRP, CResourc
for (u32 iDep = 0; iDep < NumDependencies; iDep++) for (u32 iDep = 0; iDep < NumDependencies; iDep++)
{ {
rDGRP.Seek(0x4, SEEK_CUR); // Skip dependency type rDGRP.Seek(0x4, SEEK_CUR); // Skip dependency type
CAssetID AssetID(rDGRP, IDLength); CAssetID AssetID(rDGRP, Game);
pGroup->AddDependency(AssetID); pGroup->AddDependency(AssetID);
} }

View File

@ -110,7 +110,7 @@ void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY
{ {
TFileProperty *pFileCast = static_cast<TFileProperty*>(pProp); TFileProperty *pFileCast = static_cast<TFileProperty*>(pProp);
CAssetID ResID = (mVersion < eCorruptionProto ? rSCLY.ReadLong() : rSCLY.ReadLongLong()); CAssetID ResID(rSCLY, mVersion);
const TStringList& rkExtensions = static_cast<CFileTemplate*>(pTemp)->Extensions(); const TStringList& rkExtensions = static_cast<CFileTemplate*>(pTemp)->Extensions();
CResourceInfo Info(ResID, CFourCC(!rkExtensions.empty() ? rkExtensions.front() : "UNKN")); CResourceInfo Info(ResID, CFourCC(!rkExtensions.empty() ? rkExtensions.front() : "UNKN"));

View File

@ -190,8 +190,6 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResou
return nullptr; return nullptr;
} }
EIDLength IDLength = (Game <= eEchoes ? e32Bit : e64Bit);
// Read main file // Read main file
CDependencyGroup *pGroup = new CDependencyGroup(pEntry); CDependencyGroup *pGroup = new CDependencyGroup(pEntry);
u32 NumHints = rHINT.ReadLong(); u32 NumHints = rHINT.ReadLong();
@ -200,15 +198,15 @@ CDependencyGroup* CUnsupportedFormatLoader::LoadHINT(IInputStream& rHINT, CResou
{ {
rHINT.ReadString(); // Skip hint name rHINT.ReadString(); // Skip hint name
rHINT.Seek(0x8, SEEK_CUR); // Skip unknown + appear time rHINT.Seek(0x8, SEEK_CUR); // Skip unknown + appear time
pGroup->AddDependency( CAssetID(rHINT, IDLength) ); // Pop-up STRG pGroup->AddDependency( CAssetID(rHINT, Game) ); // Pop-up STRG
rHINT.Seek(0x8, SEEK_CUR); // Skip unknowns rHINT.Seek(0x8, SEEK_CUR); // Skip unknowns
if (Game <= eEchoes) if (Game <= eEchoes)
{ {
pGroup->AddDependency( CAssetID(rHINT, IDLength) ); // Target MLVL pGroup->AddDependency( CAssetID(rHINT, Game) ); // Target MLVL
pGroup->AddDependency( CAssetID(rHINT, IDLength) ); // Target MREA pGroup->AddDependency( CAssetID(rHINT, Game) ); // Target MREA
rHINT.Seek(0x4, SEEK_CUR); // Skip target room index rHINT.Seek(0x4, SEEK_CUR); // Skip target room index
pGroup->AddDependency( CAssetID(rHINT, IDLength) ); // Map STRG pGroup->AddDependency( CAssetID(rHINT, Game) ); // Map STRG
} }
} }

View File

@ -997,7 +997,7 @@ void CUnsupportedParticleLoader::ParseAssetFunction(IInputStream& rFile)
break; break;
case kAssetCNST: case kAssetCNST:
mpGroup->AddDependency( CAssetID(rFile, mpGroup->Game() <= eEchoes ? e32Bit : e64Bit) ); mpGroup->AddDependency( CAssetID(rFile, mpGroup->Game()) );
break; break;
default: default:
@ -1015,7 +1015,6 @@ void CUnsupportedParticleLoader::ParseSpawnSystemKeyframeData(IInputStream& rFil
rFile.Seek(0x10, SEEK_CUR); // Skip unneeded values rFile.Seek(0x10, SEEK_CUR); // Skip unneeded values
u32 Count = rFile.ReadLong(); u32 Count = rFile.ReadLong();
EIDLength IDLength = (mpGroup->Game() <= eEchoes ? e32Bit : e64Bit);
for (u32 iKey = 0; iKey < Count; iKey++) for (u32 iKey = 0; iKey < Count; iKey++)
{ {
@ -1024,7 +1023,7 @@ void CUnsupportedParticleLoader::ParseSpawnSystemKeyframeData(IInputStream& rFil
for (u32 iInfo = 0; iInfo < InfoCount; iInfo++) for (u32 iInfo = 0; iInfo < InfoCount; iInfo++)
{ {
mpGroup->AddDependency( CAssetID(rFile, IDLength) ); mpGroup->AddDependency( CAssetID(rFile, mpGroup->Game()) );
rFile.Seek(0xC, SEEK_CUR); // Skip unknown/unneeded values rFile.Seek(0xC, SEEK_CUR); // Skip unknown/unneeded values
} }
} }

View File

@ -17,7 +17,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
{ {
mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), "STRG"); mpWorld->mpWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), "STRG");
if (mVersion == eEchoes) mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), "STRG"); if (mVersion == eEchoes) mpWorld->mpDarkWorldName = gpResourceStore->LoadResource(rMLVL.ReadLong(), "STRG");
if (mVersion >= eEchoes) mpWorld->mUnknown1 = rMLVL.ReadLong(); if (mVersion >= eEchoes) mpWorld->mTempleKeyWorldIndex = rMLVL.ReadLong();
if (mVersion >= ePrime) mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), "SAVW"); if (mVersion >= ePrime) mpWorld->mpSaveWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), "SAVW");
mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLong(), "CMDL"); mpWorld->mpDefaultSkybox = gpResourceStore->LoadResource(rMLVL.ReadLong(), "CMDL");
} }
@ -42,40 +42,25 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
MemRelay.InstanceID = rMLVL.ReadLong(); MemRelay.InstanceID = rMLVL.ReadLong();
MemRelay.TargetID = rMLVL.ReadLong(); MemRelay.TargetID = rMLVL.ReadLong();
MemRelay.Message = rMLVL.ReadShort(); MemRelay.Message = rMLVL.ReadShort();
MemRelay.Unknown = rMLVL.ReadByte(); MemRelay.Active = rMLVL.ReadBool();
mpWorld->mMemoryRelays.push_back(MemRelay); mpWorld->mMemoryRelays.push_back(MemRelay);
} }
} }
// Areas - here's the real meat of the file // Areas - here's the real meat of the file
u32 NumAreas = rMLVL.ReadLong(); u32 NumAreas = rMLVL.ReadLong();
if (mVersion == ePrime) mpWorld->mUnknownAreas = rMLVL.ReadLong(); if (mVersion == ePrime) rMLVL.Seek(0x4, SEEK_CUR);
mpWorld->mAreas.resize(NumAreas); mpWorld->mAreas.resize(NumAreas);
for (u32 iArea = 0; iArea < NumAreas; iArea++) for (u32 iArea = 0; iArea < NumAreas; iArea++)
{ {
// Area header // Area header
CWorld::SArea *pArea = &mpWorld->mAreas[iArea]; CWorld::SArea *pArea = &mpWorld->mAreas[iArea];
pArea->pAreaName = gpResourceStore->LoadResource( CAssetID(rMLVL, mVersion), "STRG" );
if (mVersion < eCorruptionProto)
pArea->pAreaName = gpResourceStore->LoadResource(rMLVL.ReadLong(), "STRG");
else
pArea->pAreaName = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), "STRG");
pArea->Transform = CTransform4f(rMLVL); pArea->Transform = CTransform4f(rMLVL);
pArea->AetherBox = CAABox(rMLVL); pArea->AetherBox = CAABox(rMLVL);
pArea->AreaResID = CAssetID(rMLVL, mVersion);
if (mVersion < eCorruptionProto) pArea->AreaID = CAssetID(rMLVL, mVersion);
{
pArea->AreaResID = rMLVL.ReadLong() & 0xFFFFFFFF;
pArea->AreaID = rMLVL.ReadLong() & 0xFFFFFFFF;
}
else
{
pArea->AreaResID = rMLVL.ReadLongLong();
pArea->AreaID = rMLVL.ReadLongLong();
}
// Attached areas // Attached areas
u32 NumAttachedAreas = rMLVL.ReadLong(); u32 NumAttachedAreas = rMLVL.ReadLong();
@ -83,36 +68,15 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
for (u32 iAttached = 0; iAttached < NumAttachedAreas; iAttached++) for (u32 iAttached = 0; iAttached < NumAttachedAreas; iAttached++)
pArea->AttachedAreaIDs.push_back( rMLVL.ReadShort() ); pArea->AttachedAreaIDs.push_back( rMLVL.ReadShort() );
if (mVersion < eCorruptionProto) // Skip dependency list - this is very fast to regenerate so there's no use in caching it
rMLVL.Seek(0x4, SEEK_CUR); // Skipping unknown value (always 0)
// Dependencies
if (mVersion < eCorruptionProto) if (mVersion < eCorruptionProto)
{ {
u32 NumDependencies = rMLVL.ReadLong();
pArea->Dependencies.reserve(NumDependencies);
for (u32 iDep = 0; iDep < NumDependencies; iDep++)
{
pArea->Dependencies.push_back( CAssetID(rMLVL, e32Bit) );
rMLVL.Seek(0x4, SEEK_CUR); rMLVL.Seek(0x4, SEEK_CUR);
} u32 NumDependencies = rMLVL.ReadLong();
rMLVL.Seek(NumDependencies * 8, SEEK_CUR);
/**
* Dependency offsets - indicates an offset into the dependency list where each layer's dependencies start
* The count is the layer count + 1 because the last offset is for common dependencies, like terrain textures
*/
u32 NumDependencyOffsets = rMLVL.ReadLong(); u32 NumDependencyOffsets = rMLVL.ReadLong();
pArea->Layers.resize(NumDependencyOffsets - 1); rMLVL.Seek(NumDependencyOffsets * 4, SEEK_CUR);
for (u32 iOff = 0; iOff < NumDependencyOffsets; iOff++)
{
u32 *pTarget;
if (iOff == NumDependencyOffsets - 1) pTarget = &pArea->CommonDependenciesStart;
else pTarget = &pArea->Layers[iOff].LayerDependenciesStart;
*pTarget = rMLVL.ReadLong();
}
} }
// Docks // Docks
@ -161,16 +125,15 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
} }
} }
// Footer // Internal name - MP1 doesn't have this so reuse the area's real name
if (mVersion >= eEchoesDemo) if (mVersion >= eEchoesDemo)
pArea->InternalName = rMLVL.ReadString(); pArea->InternalName = rMLVL.ReadString();
else
pArea->InternalName = (pArea->pAreaName ? pArea->pAreaName->String("ENGL", 0).ToUTF8() : "");
} }
// MapWorld // MapWorld
if (mVersion < eCorruptionProto) mpWorld->mpMapWorld = gpResourceStore->LoadResource( CAssetID(rMLVL, mVersion), "MAPW" );
mpWorld->mpMapWorld = gpResourceStore->LoadResource(rMLVL.ReadLong(), "MAPW");
else
mpWorld->mpMapWorld = gpResourceStore->LoadResource(rMLVL.ReadLongLong(), "MAPW");
rMLVL.Seek(0x5, SEEK_CUR); // Unknown values which are always 0 rMLVL.Seek(0x5, SEEK_CUR); // Unknown values which are always 0
// AudioGrps // AudioGrps
@ -182,7 +145,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
for (u32 iGrp = 0; iGrp < NumAudioGrps; iGrp++) for (u32 iGrp = 0; iGrp < NumAudioGrps; iGrp++)
{ {
CWorld::SAudioGrp AudioGrp; CWorld::SAudioGrp AudioGrp;
AudioGrp.Unknown = rMLVL.ReadLong(); AudioGrp.GroupID = rMLVL.ReadLong();
AudioGrp.ResID = rMLVL.ReadLong() & 0xFFFFFFFF; AudioGrp.ResID = rMLVL.ReadLong() & 0xFFFFFFFF;
mpWorld->mAudioGrps.push_back(AudioGrp); mpWorld->mAudioGrps.push_back(AudioGrp);
} }
@ -200,7 +163,7 @@ void CWorldLoader::LoadPrimeMLVL(IInputStream& rMLVL)
u64 LayerFlags = rMLVL.ReadLongLong(); u64 LayerFlags = rMLVL.ReadLongLong();
for (u32 iLayer = 0; iLayer < NumLayers; iLayer++) for (u32 iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].EnabledByDefault = (((LayerFlags >> iLayer) & 0x1) == 1); pArea->Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1);
} }
// Layer names // Layer names
@ -262,7 +225,7 @@ void CWorldLoader::LoadReturnsMLVL(IInputStream& rMLVL)
u64 LayerFlags = rMLVL.ReadLongLong(); u64 LayerFlags = rMLVL.ReadLongLong();
for (u32 iLayer = 0; iLayer < NumLayers; iLayer++) for (u32 iLayer = 0; iLayer < NumLayers; iLayer++)
pArea->Layers[iLayer].EnabledByDefault = (((LayerFlags >> iLayer) & 0x1) == 1); pArea->Layers[iLayer].Active = (((LayerFlags >> iLayer) & 0x1) == 1);
} }
// Layer names // Layer names
@ -303,7 +266,6 @@ CWorld* CWorldLoader::LoadMLVL(IInputStream& rMLVL, CResourceEntry *pEntry)
CWorldLoader Loader; CWorldLoader Loader;
Loader.mpWorld = new CWorld(pEntry); Loader.mpWorld = new CWorld(pEntry);
Loader.mpWorld->SetGame(Version); Loader.mpWorld->SetGame(Version);
Loader.mpWorld->mWorldVersion = Version;
Loader.mVersion = Version; Loader.mVersion = Version;
if (Version != eReturns) if (Version != eReturns)

View File

@ -95,7 +95,7 @@ void CPropertyView::SetInstance(CScriptObject *pObj)
void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent) void CPropertyView::UpdateEditorProperties(const QModelIndex& rkParent)
{ {
// Check what game this is // Check what game this is
EGame Game = mpEditor->ActiveArea()->Version(); EGame Game = mpEditor->CurrentGame();
// Iterate over all properties and update if they're an editor property. // Iterate over all properties and update if they're an editor property.
for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++) for (int iRow = 0; iRow < mpModel->rowCount(rkParent); iRow++)

View File

@ -95,7 +95,7 @@ void CDeleteSelectionCommand::undo()
mpEditor->NotifyNodeAboutToBeSpawned(); mpEditor->NotifyNodeAboutToBeSpawned();
CMemoryInStream Mem(rNode.InstanceData.data(), rNode.InstanceData.size(), IOUtil::eBigEndian); CMemoryInStream Mem(rNode.InstanceData.data(), rNode.InstanceData.size(), IOUtil::eBigEndian);
CScriptObject *pInstance = CScriptLoader::LoadInstance(Mem, rNode.pArea, rNode.pLayer, rNode.pArea->Version(), true); CScriptObject *pInstance = CScriptLoader::LoadInstance(Mem, rNode.pArea, rNode.pLayer, rNode.pArea->Game(), true);
CScriptNode *pNode = mpEditor->Scene()->CreateScriptNode(pInstance, rNode.NodeID); CScriptNode *pNode = mpEditor->Scene()->CreateScriptNode(pInstance, rNode.NodeID);
rNode.pArea->AddInstanceToArea(pInstance); rNode.pArea->AddInstanceToArea(pInstance);
rNode.pLayer->AddInstance(pInstance, rNode.LayerIndex); rNode.pLayer->AddInstance(pInstance, rNode.LayerIndex);

View File

@ -55,7 +55,7 @@ void CPasteNodesCommand::redo()
if (rkNode.Type == eScriptNode) if (rkNode.Type == eScriptNode)
{ {
CMemoryInStream In(rkNode.InstanceData.data(), rkNode.InstanceData.size(), IOUtil::eBigEndian); CMemoryInStream In(rkNode.InstanceData.data(), rkNode.InstanceData.size(), IOUtil::eBigEndian);
CScriptObject *pInstance = CScriptLoader::LoadInstance(In, pArea, mpLayer, pArea->Version(), true); CScriptObject *pInstance = CScriptLoader::LoadInstance(In, pArea, mpLayer, pArea->Game(), true);
pArea->AddInstanceToArea(pInstance); pArea->AddInstanceToArea(pInstance);
mpLayer->AddInstance(pInstance); mpLayer->AddInstance(pInstance);

View File

@ -343,7 +343,7 @@ void CPoiMapEditDialog::StopPicking()
void CPoiMapEditDialog::OnInstanceListButtonClicked() void CPoiMapEditDialog::OnInstanceListButtonClicked()
{ {
EGame Game = mpEditor->ActiveArea()->Version(); EGame Game = mpEditor->CurrentGame();
CScriptTemplate *pPoiTemplate = CMasterTemplate::MasterForGame(Game)->TemplateByID("POIN"); CScriptTemplate *pPoiTemplate = CMasterTemplate::MasterForGame(Game)->TemplateByID("POIN");
CPoiListDialog Dialog(pPoiTemplate, &mSourceModel, mpEditor->Scene(), this); CPoiListDialog Dialog(pPoiTemplate, &mSourceModel, mpEditor->Scene(), this);

View File

@ -212,16 +212,16 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
UpdateCameraOrbit(); UpdateCameraOrbit();
// Default bloom to Fake Bloom for Metroid Prime 3; disable for other games // Default bloom to Fake Bloom for Metroid Prime 3; disable for other games
bool AllowBloom = (mpWorld->Version() == eCorruptionProto || mpWorld->Version() == eCorruption); bool AllowBloom = (mpWorld->Game() == eCorruptionProto || mpWorld->Game() == eCorruption);
AllowBloom ? SetFakeBloom() : SetNoBloom(); AllowBloom ? SetFakeBloom() : SetNoBloom();
ui->menuBloom->setEnabled(AllowBloom); ui->menuBloom->setEnabled(AllowBloom);
// Disable EGMC editing for Prime 1 and DKCR // Disable EGMC editing for Prime 1 and DKCR
bool AllowEGMC = ( (mpWorld->Version() >= eEchoesDemo) && (mpWorld->Version() <= eCorruption) ); bool AllowEGMC = ( (mpWorld->Game() >= eEchoesDemo) && (mpWorld->Game() <= eCorruption) );
ui->ActionEditPoiToWorldMap->setEnabled(AllowEGMC); ui->ActionEditPoiToWorldMap->setEnabled(AllowEGMC);
// Set up sidebar tabs // Set up sidebar tabs
CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(mpArea->Version()); CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(mpArea->Game());
ui->CreateTabContents->SetMaster(pMaster); ui->CreateTabContents->SetMaster(pMaster);
ui->InstancesTabContents->SetMaster(pMaster); ui->InstancesTabContents->SetMaster(pMaster);

View File

@ -59,7 +59,7 @@ public:
bool HasAnyScriptNodesSelected() const; bool HasAnyScriptNodesSelected() const;
inline CGameArea* ActiveArea() const { return mpArea; } inline CGameArea* ActiveArea() const { return mpArea; }
inline EGame CurrentGame() const { return mpArea ? mpArea->Version() : eUnknownGame; } inline EGame CurrentGame() const { return mpArea ? mpArea->Game() : eUnknownGame; }
inline CLinkDialog* LinkDialog() const { return mpLinkDialog; } inline CLinkDialog* LinkDialog() const { return mpLinkDialog; }
CSceneViewport* Viewport() const; CSceneViewport* Viewport() const;

View File

@ -313,7 +313,7 @@ void WInstancesTab::OnHideAllExceptTypeAction()
else else
{ {
EGame Game = mpEditor->ActiveArea()->Version(); EGame Game = mpEditor->CurrentGame();
CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game); CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game);
for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++) for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++)
@ -344,7 +344,7 @@ void WInstancesTab::OnUnhideAllTypes()
else else
{ {
EGame Game = mpEditor->ActiveArea()->Version(); EGame Game = mpEditor->CurrentGame();
CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game); CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game);
for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++) for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++)
@ -378,7 +378,7 @@ void WInstancesTab::OnUnhideAll()
if (TypesRoot.isValid()) if (TypesRoot.isValid())
{ {
EGame Game = mpEditor->ActiveArea()->Version(); EGame Game = mpEditor->CurrentGame();
CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game); CMasterTemplate *pMaster = CMasterTemplate::MasterForGame(Game);
for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++) for (u32 iTemp = 0; iTemp < pMaster->NumScriptTemplates(); iTemp++)

View File

@ -1,9 +1,18 @@
#include "IInputStream.h" #include "IInputStream.h"
#include <assert.h>
IInputStream::~IInputStream() IInputStream::~IInputStream()
{ {
} }
bool IInputStream::ReadBool()
{
char Val;
ReadBytes(&Val, 1);
assert(Val == 0 || Val == 1);
return (Val != 0 ? true : false);
}
char IInputStream::ReadByte() char IInputStream::ReadByte()
{ {
char Val; char Val;

View File

@ -12,6 +12,7 @@ protected:
std::string mDataSource; std::string mDataSource;
public: public:
bool ReadBool();
char ReadByte(); char ReadByte();
short ReadShort(); short ReadShort();
long ReadLong(); long ReadLong();

View File

@ -4,6 +4,12 @@ IOutputStream::~IOutputStream()
{ {
} }
void IOutputStream::WriteBool(bool Val)
{
char ChrVal = (Val ? 1 : 0);
WriteBytes(&ChrVal, 1);
}
void IOutputStream::WriteByte(char Val) void IOutputStream::WriteByte(char Val)
{ {
WriteBytes(&Val, 1); WriteBytes(&Val, 1);

View File

@ -11,6 +11,7 @@ protected:
std::string mDataDest; std::string mDataDest;
public: public:
void WriteBool(bool Val);
void WriteByte(char Val); void WriteByte(char Val);
void WriteShort(short Val); void WriteShort(short Val);
void WriteLong(long Val); void WriteLong(long Val);

View File

@ -38,7 +38,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -267,7 +267,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -99,7 +99,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -209,7 +209,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -91,7 +91,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -145,7 +145,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -446,7 +446,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -193,7 +193,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">

View File

@ -434,7 +434,7 @@
<property ID="0x426F2F60"> <property ID="0x426F2F60">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x771A3176" extensions="CAUD"> <property ID="0x771A3176">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xEFD287D9"> <property ID="0xEFD287D9">
@ -505,10 +505,10 @@
</property> </property>
</properties> </properties>
</struct> </struct>
<property ID="0xE9C8E2BD" extensions="PART"> <property ID="0xE9C8E2BD">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0xA3E8EC4E" extensions="CAUD"> <property ID="0xA3E8EC4E">
<cook_pref>never</cook_pref> <cook_pref>never</cook_pref>
</property> </property>
<property ID="0x053AE4A7"> <property ID="0x053AE4A7">