From 5182f436b86f69644b6a8e305af957ed1d02d1c3 Mon Sep 17 00:00:00 2001 From: Aruki Date: Tue, 4 Sep 2018 13:27:27 -0600 Subject: [PATCH] Major refactor of serialization system --- src/Common/CColor.cpp | 5 +- src/Common/EGame.cpp | 15 +- src/Common/EGame.h | 1 - src/Common/Flags.h | 2 +- src/Common/Log.cpp | 2 + src/Common/Serialization/CBasicBinaryReader.h | 54 +- src/Common/Serialization/CBasicBinaryWriter.h | 56 +- src/Common/Serialization/CBinaryReader.h | 115 ++- src/Common/Serialization/CBinaryWriter.h | 75 +- src/Common/Serialization/CXMLReader.h | 92 +- src/Common/Serialization/CXMLWriter.h | 100 +- src/Common/Serialization/IArchive.h | 953 +++++++++++------- src/Common/TString.cpp | 2 +- src/Common/TString.h | 11 +- src/Core/GameProject/CAssetNameMap.cpp | 2 +- src/Core/GameProject/CAssetNameMap.h | 6 +- src/Core/GameProject/CDependencyTree.cpp | 44 +- src/Core/GameProject/CDependencyTree.h | 26 +- src/Core/GameProject/CGameInfo.cpp | 4 +- src/Core/GameProject/CGameInfo.h | 4 +- src/Core/GameProject/CGameProject.cpp | 10 +- src/Core/GameProject/CPackage.cpp | 4 +- src/Core/GameProject/CPackage.h | 4 +- src/Core/GameProject/CResourceEntry.cpp | 12 +- src/Core/GameProject/CResourceStore.cpp | 10 +- .../Animation/CAnimationParameters.cpp | 11 +- .../Resource/Animation/CAnimationParameters.h | 25 + src/Core/Resource/CResTypeFilter.h | 2 +- src/Core/Resource/CResTypeInfo.cpp | 4 +- src/Core/Resource/CSavedStateID.h | 16 +- src/Core/Resource/CWorld.cpp | 82 +- src/Core/Resource/Script/IPropertyNew.cpp | 21 +- src/Core/Resource/Script/IPropertyNew.h | 45 +- .../Script/Property/CAnimationProperty.h | 2 +- .../Script/Property/CAnimationSetProperty.h | 10 + .../Resource/Script/Property/CArrayProperty.h | 6 +- .../Resource/Script/Property/CAssetProperty.h | 18 +- .../Resource/Script/Property/CBoolProperty.h | 2 +- .../Resource/Script/Property/CByteProperty.h | 2 +- .../Resource/Script/Property/CEnumProperty.h | 8 +- .../Resource/Script/Property/CFlagsProperty.h | 8 +- .../Resource/Script/Property/CFloatProperty.h | 2 +- .../Resource/Script/Property/CGuidProperty.h | 2 +- .../Resource/Script/Property/CIntProperty.h | 2 +- .../Resource/Script/Property/CShortProperty.h | 2 +- .../Resource/Script/Property/CSoundProperty.h | 2 +- .../Script/Property/CSplineProperty.h | 2 +- .../Script/Property/CStringProperty.h | 2 +- .../Script/Property/CStructProperty.h | 33 +- src/Core/Resource/TResPtr.h | 2 +- src/Math/CAABox.cpp | 4 +- src/Math/CTransform4f.cpp | 6 +- src/Math/CVector3f.cpp | 4 +- templates/Properties.xml | 2 +- 54 files changed, 1105 insertions(+), 831 deletions(-) diff --git a/src/Common/CColor.cpp b/src/Common/CColor.cpp index 62810cd0..ec8c539d 100644 --- a/src/Common/CColor.cpp +++ b/src/Common/CColor.cpp @@ -65,7 +65,10 @@ void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/) const void CColor::Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(R) << SERIAL_AUTO(G) << SERIAL_AUTO(B) << SERIAL_AUTO(A); + rArc << SerialParameter("R", R) + << SerialParameter("G", G) + << SerialParameter("B", B) + << SerialParameter("A", A, SH_Optional, 1.0f); } long CColor::ToLongRGBA() const diff --git a/src/Common/EGame.cpp b/src/Common/EGame.cpp index fedeb96d..f76a36ed 100644 --- a/src/Common/EGame.cpp +++ b/src/Common/EGame.cpp @@ -62,7 +62,7 @@ TString GetGameShortName(EGame Game) void Serialize(IArchive& rArc, EGame& rGame) { CFourCC GameID = GetGameID(rGame); - rArc.SerializePrimitive(GameID); + rArc.SerializePrimitive(GameID, 0); if (rArc.IsReader()) rGame = GetGameForID(GameID); } @@ -83,16 +83,3 @@ ERegion GetRegionForName(const TString& rkName) return eRegion_Unknown; } - -void Serialize(IArchive& rArc, ERegion& rRegion) -{ - TString Name; - - if (rArc.IsWriter()) - Name = GetRegionName(rRegion); - - rArc.SerializePrimitive(Name); - - if (rArc.IsReader()) - rRegion = GetRegionForName(Name); -} diff --git a/src/Common/EGame.h b/src/Common/EGame.h index 1897b5f0..a82c3383 100644 --- a/src/Common/EGame.h +++ b/src/Common/EGame.h @@ -38,6 +38,5 @@ enum ERegion }; TString GetRegionName(ERegion Region); ERegion GetRegionForName(const TString& rkName); -void Serialize(IArchive& rArc, ERegion& rRegion); #endif // EGAME_H diff --git a/src/Common/Flags.h b/src/Common/Flags.h index 698bcd22..2b380512 100644 --- a/src/Common/Flags.h +++ b/src/Common/Flags.h @@ -38,7 +38,7 @@ public: inline void ClearFlag(FlagEnum Flag) { mValue &= ~((u32) Flag); } inline void ClearFlag(TFlags Flags) { mValue &= ~Flags; } - inline void Serialize(IArchive& rArc) { rArc.SerializeHexPrimitive(mValue); } + inline void Serialize(IArchive& rArc) { rArc.SerializePrimitive(mValue, SH_HexDisplay); } }; #define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags FlagTypeName; diff --git a/src/Common/Log.cpp b/src/Common/Log.cpp index 39643149..85df7423 100644 --- a/src/Common/Log.cpp +++ b/src/Common/Log.cpp @@ -53,8 +53,10 @@ bool InitLog(const TString& rkFilename) fprintf(gpLogFile, "Opened log file at %s\n", Buffer); fflush(gpLogFile); +#ifdef APP_FULL_NAME // Print app name and version fprintf(gpLogFile, APP_FULL_NAME"\n"); +#endif // Print any messages that were attempted before we initialized if (!gPreInitLogs.empty()) diff --git a/src/Common/Serialization/CBasicBinaryReader.h b/src/Common/Serialization/CBasicBinaryReader.h index 40cfb471..283ead58 100644 --- a/src/Common/Serialization/CBasicBinaryReader.h +++ b/src/Common/Serialization/CBasicBinaryReader.h @@ -20,13 +20,13 @@ public: : IArchive() , mOwnsStream(true) { + mArchiveFlags = AF_Binary | AF_Reader; mpStream = new CFileInStream(rkFilename, IOUtil::eBigEndian); if (mpStream->IsValid()) { mMagicValid = (mpStream->ReadLong() == Magic); - CSerialVersion Version(*mpStream); - SetVersion(Version); + SerializeVersion(); } } @@ -35,6 +35,8 @@ public: , mMagicValid(true) , mOwnsStream(false) { + mArchiveFlags = AF_Binary | AF_Reader; + ASSERT(pStream->IsValid()); mpStream = pStream; SetVersion(rkVersion); @@ -45,6 +47,7 @@ public: , mMagicValid(true) , mOwnsStream(true) { + mArchiveFlags = AF_Binary | AF_Reader; mpStream = new CMemoryInStream(pData, DataSize, Endian); SetVersion(rkVersion); } @@ -61,34 +64,29 @@ public: virtual bool IsWriter() const { return false; } virtual bool IsTextFormat() const { return false; } - virtual bool ParamBegin(const char*) { return true; } - virtual void ParamEnd() { } + virtual bool ParamBegin(const char*, u32) { return true; } + virtual void ParamEnd() { } - virtual void SerializeContainerSize(u32& rSize, const TString&) { SerializePrimitive(rSize); } - virtual void SerializeAbstractObjectType(u32& rType) { SerializePrimitive(rType); } - virtual void SerializePrimitive(bool& rValue) { rValue = mpStream->ReadBool(); } - virtual void SerializePrimitive(char& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(s8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(u8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(s16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializePrimitive(u16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializePrimitive(s32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializePrimitive(u32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializePrimitive(s64& rValue) { rValue = mpStream->ReadLongLong(); } - virtual void SerializePrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); } - virtual void SerializePrimitive(float& rValue) { rValue = mpStream->ReadFloat(); } - virtual void SerializePrimitive(double& rValue) { rValue = mpStream->ReadDouble(); } - virtual void SerializePrimitive(TString& rValue) { rValue = mpStream->ReadSizedString(); } - virtual void SerializePrimitive(TWideString& rValue) { rValue = mpStream->ReadSizedWString(); } - virtual void SerializePrimitive(CFourCC& rValue) { rValue = CFourCC(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue = CAssetID(*mpStream, mGame); } + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) { return ArchiveVersion() >= eArVer_Refactor ? mpStream->ReadBool() : true; } + virtual void SerializeContainerSize(u32& rSize, const TString&, u32 Flags) { SerializePrimitive(rSize, Flags); } + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { mpStream->ReadBytes(pData, Size); } - virtual void SerializeHexPrimitive(u8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); } - - virtual void BulkSerialize(void* pData, u32 Size) { mpStream->ReadBytes(pData, Size); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { rValue = mpStream->ReadBool(); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { rValue = mpStream->ReadShort(); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { rValue = mpStream->ReadShort(); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { rValue = mpStream->ReadLong(); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { rValue = mpStream->ReadLong(); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { rValue = mpStream->ReadLongLong(); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { rValue = mpStream->ReadLongLong(); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { rValue = mpStream->ReadFloat(); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { rValue = mpStream->ReadDouble(); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { rValue = mpStream->ReadSizedString(); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { rValue = mpStream->ReadSizedWString(); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { rValue = CFourCC(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { rValue = CAssetID(*mpStream, mGame); } }; #endif // CBASICBINARYREADER diff --git a/src/Common/Serialization/CBasicBinaryWriter.h b/src/Common/Serialization/CBasicBinaryWriter.h index 34d9de3a..622b5492 100644 --- a/src/Common/Serialization/CBasicBinaryWriter.h +++ b/src/Common/Serialization/CBasicBinaryWriter.h @@ -20,13 +20,14 @@ public: , mMagic(Magic) , mOwnsStream(true) { + mArchiveFlags = AF_Binary | AF_Writer; mpStream = new CFileOutStream(rkFilename, IOUtil::eBigEndian); if (mpStream->IsValid()) { mpStream->WriteLong(0); // Magic is written after the rest of the file is successfully saved SetVersion(skCurrentArchiveVersion, FileVersion, Game); - GetVersionInfo().Write(*mpStream); + SerializeVersion(); } } @@ -35,6 +36,7 @@ public: , mOwnsStream(false) { ASSERT(pStream->IsValid()); + mArchiveFlags = AF_Binary | AF_Writer; mpStream = pStream; SetVersion(skCurrentArchiveVersion, FileVersion, Game); } @@ -44,6 +46,7 @@ public: , mOwnsStream(false) { ASSERT(pStream->IsValid()); + mArchiveFlags = AF_Binary | AF_Writer; mpStream = pStream; SetVersion(rkVersion); } @@ -66,34 +69,35 @@ public: virtual bool IsWriter() const { return true; } virtual bool IsTextFormat() const { return false; } - virtual bool ParamBegin(const char*) { return true; } - virtual void ParamEnd() { } + virtual bool ParamBegin(const char*, u32) { return true; } + virtual void ParamEnd() { } - virtual void SerializeContainerSize(u32& rSize, const TString&) { mpStream->WriteLong(rSize); } - virtual void SerializeAbstractObjectType(u32& rType) { mpStream->WriteLong(rType); } - virtual void SerializePrimitive(bool& rValue) { mpStream->WriteBool(rValue); } - virtual void SerializePrimitive(char& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(s8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(u8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(s16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializePrimitive(u16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializePrimitive(s32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializePrimitive(u32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializePrimitive(s64& rValue) { mpStream->WriteLongLong(rValue); } - virtual void SerializePrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } - virtual void SerializePrimitive(float& rValue) { mpStream->WriteFloat(rValue); } - virtual void SerializePrimitive(double& rValue) { mpStream->WriteDouble(rValue); } - virtual void SerializePrimitive(TString& rValue) { mpStream->WriteSizedString(rValue); } - virtual void SerializePrimitive(TWideString& rValue) { mpStream->WriteSizedWString(rValue); } - virtual void SerializePrimitive(CFourCC& rValue) { rValue.Write(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) + { + bool ValidPtr = (Pointer != nullptr); + mpStream->WriteBool(ValidPtr); + return ValidPtr; + } - virtual void SerializeHexPrimitive(u8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializeHexPrimitive(u32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializeHexPrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } + virtual void SerializeContainerSize(u32& rSize, const TString&) { mpStream->WriteLong(rSize); } - virtual void BulkSerialize(void* pData, u32 Size) { mpStream->WriteBytes(pData, Size); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { mpStream->WriteBool(rValue); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { mpStream->WriteShort(rValue); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { mpStream->WriteShort(rValue); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { mpStream->WriteLong(rValue); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { mpStream->WriteLong(rValue); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { mpStream->WriteLongLong(rValue); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { mpStream->WriteLongLong(rValue); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { mpStream->WriteFloat(rValue); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { mpStream->WriteDouble(rValue); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { mpStream->WriteSizedString(rValue); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { mpStream->WriteSizedWString(rValue); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { rValue.Write(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { mpStream->WriteBytes(pData, Size); } }; #endif // CBASICBINARYWRITER diff --git a/src/Common/Serialization/CBinaryReader.h b/src/Common/Serialization/CBinaryReader.h index ef6f774b..981d9f9c 100644 --- a/src/Common/Serialization/CBinaryReader.h +++ b/src/Common/Serialization/CBinaryReader.h @@ -7,43 +7,46 @@ class CBinaryReader : public IArchive { - struct SParameter + struct SBinaryParm { u32 Offset; u32 Size; u32 NumChildren; u32 ChildIndex; - bool Abstract; }; - std::vector mParamStack; + std::vector mBinaryParmStack; IInputStream *mpStream; bool mMagicValid; bool mOwnsStream; + bool mInAttribute; public: CBinaryReader(const TString& rkFilename, u32 Magic) : IArchive() , mOwnsStream(true) + , mInAttribute(false) { + mArchiveFlags = AF_Reader | AF_Binary; mpStream = new CFileInStream(rkFilename, IOUtil::eBigEndian); if (mpStream->IsValid()) { mMagicValid = (mpStream->ReadLong() == Magic); - CSerialVersion Version(*mpStream); - SetVersion(Version); } InitParamStack(); + SerializeVersion(); } CBinaryReader(IInputStream *pStream, const CSerialVersion& rkVersion) : IArchive() , mMagicValid(true) , mOwnsStream(false) + , mInAttribute(false) { ASSERT(pStream && pStream->IsValid()); + mArchiveFlags = AF_Reader | AF_Binary; mpStream = pStream; SetVersion(rkVersion); @@ -64,27 +67,23 @@ private: u32 Size = ReadSize(); u32 Offset = mpStream->Tell(); u32 NumChildren = ReadSize(); - mParamStack.push_back( SParameter { Offset, Size, NumChildren, 0, false } ); - mParamStack.reserve(20); + mBinaryParmStack.push_back( SBinaryParm { Offset, Size, NumChildren, 0 } ); + mBinaryParmStack.reserve(20); } public: // Interface - virtual bool IsReader() const { return true; } - virtual bool IsWriter() const { return false; } - virtual bool IsTextFormat() const { return false; } - u32 ReadSize() { return (mArchiveVersion < eArVer_32BitBinarySize ? (u32) mpStream->ReadShort() : mpStream->ReadLong()); } - virtual bool ParamBegin(const char *pkName) + virtual bool ParamBegin(const char *pkName, u32 Flags) { // If this is the parent parameter's first child, then read the child count - if (mParamStack.back().NumChildren == 0xFFFFFFFF) + if (mBinaryParmStack.back().NumChildren == 0xFFFFFFFF) { - mParamStack.back().NumChildren = ReadSize(); + mBinaryParmStack.back().NumChildren = ReadSize(); } // Save current offset @@ -92,26 +91,25 @@ public: u32 ParamID = TString(pkName).Hash32(); // Check the next parameter ID first and check whether it's a match for the current parameter - if (mParamStack.back().ChildIndex < mParamStack.back().NumChildren) + if (mBinaryParmStack.back().ChildIndex < mBinaryParmStack.back().NumChildren) { u32 NextID = mpStream->ReadLong(); u32 NextSize = ReadSize(); // Does the next parameter ID match the current one? - if (NextID == ParamID) + if (NextID == ParamID || (Flags & SH_IgnoreName)) { - mParamStack.push_back( SParameter { mpStream->Tell(), NextSize, 0xFFFFFFFF, 0, false } ); + mBinaryParmStack.push_back( SBinaryParm { mpStream->Tell(), NextSize, 0xFFFFFFFF, 0 } ); return true; } } // It's not a match - return to the parent parameter's first child and check all children to find a match - if (!mParamStack.empty()) + if (!mBinaryParmStack.empty()) { - bool ParentAbstract = mParamStack.back().Abstract; - u32 ParentOffset = mParamStack.back().Offset; - u32 NumChildren = mParamStack.back().NumChildren; - mpStream->GoTo(ParentOffset + (ParentAbstract ? 4 : 0)); + u32 ParentOffset = mBinaryParmStack.back().Offset; + u32 NumChildren = mBinaryParmStack.back().NumChildren; + mpStream->GoTo(ParentOffset); for (u32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++) { @@ -122,8 +120,8 @@ public: mpStream->Skip(ChildSize); else { - mParamStack.back().ChildIndex = ChildIdx; - mParamStack.push_back( SParameter { mpStream->Tell(), ChildSize, 0xFFFFFFFF, 0, false } ); + mBinaryParmStack.back().ChildIndex = ChildIdx; + mBinaryParmStack.push_back( SBinaryParm { mpStream->Tell(), ChildSize, 0xFFFFFFFF, 0 } ); return true; } } @@ -137,14 +135,28 @@ public: virtual void ParamEnd() { // Make sure we're at the end of the parameter - SParameter& rParam = mParamStack.back(); + SBinaryParm& rParam = mBinaryParmStack.back(); u32 EndOffset = rParam.Offset + rParam.Size; mpStream->GoTo(EndOffset); - mParamStack.pop_back(); + mBinaryParmStack.pop_back(); // Increment parent child index - if (!mParamStack.empty()) - mParamStack.back().ChildIndex++; + if (!mBinaryParmStack.empty()) + mBinaryParmStack.back().ChildIndex++; + } + + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) + { + if (ArchiveVersion() >= eArVer_Refactor) + { + bool ValidPtr = (Pointer != nullptr); + *this << SerialParameter("PointerValid", ValidPtr); + return ValidPtr; + } + else + { + return true; + } } virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/) @@ -153,36 +165,23 @@ public: rSize = (mArchiveVersion < eArVer_32BitBinarySize ? (u32) mpStream->PeekShort() : mpStream->PeekLong()); } - virtual void SerializeAbstractObjectType(u32& rType) - { - // Mark current parameter as abstract so we can account for the object type in the filestream - rType = mpStream->ReadLong(); - mParamStack.back().Abstract = true; - } - - virtual void SerializePrimitive(bool& rValue) { rValue = mpStream->ReadBool(); } - virtual void SerializePrimitive(char& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(s8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(u8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializePrimitive(s16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializePrimitive(u16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializePrimitive(s32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializePrimitive(u32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializePrimitive(s64& rValue) { rValue = mpStream->ReadLongLong(); } - virtual void SerializePrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); } - virtual void SerializePrimitive(float& rValue) { rValue = mpStream->ReadFloat(); } - virtual void SerializePrimitive(double& rValue) { rValue = mpStream->ReadDouble(); } - virtual void SerializePrimitive(TString& rValue) { rValue = mpStream->ReadSizedString(); } - virtual void SerializePrimitive(TWideString& rValue) { rValue = mpStream->ReadSizedWString(); } - virtual void SerializePrimitive(CFourCC& rValue) { rValue = CFourCC(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue = CAssetID(*mpStream, Game()); } - - virtual void SerializeHexPrimitive(u8& rValue) { rValue = mpStream->ReadByte(); } - virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); } - virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); } - virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); } - - virtual void BulkSerialize(void* pData, u32 Size) { mpStream->ReadBytes(pData, Size); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { rValue = mpStream->ReadBool(); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { rValue = mpStream->ReadByte(); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { rValue = mpStream->ReadShort(); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { rValue = mpStream->ReadShort(); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { rValue = mpStream->ReadLong(); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { rValue = mpStream->ReadLong(); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { rValue = mpStream->ReadLongLong(); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { rValue = mpStream->ReadLongLong(); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { rValue = mpStream->ReadFloat(); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { rValue = mpStream->ReadDouble(); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { rValue = mpStream->ReadSizedString(); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { rValue = mpStream->ReadSizedWString(); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { rValue = CFourCC(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { rValue = CAssetID(*mpStream, Game()); } + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { mpStream->ReadBytes(pData, Size); } }; #endif // CBINARYREADER diff --git a/src/Common/Serialization/CBinaryWriter.h b/src/Common/Serialization/CBinaryWriter.h index 48d114e1..eee2f10a 100644 --- a/src/Common/Serialization/CBinaryWriter.h +++ b/src/Common/Serialization/CBinaryWriter.h @@ -10,7 +10,6 @@ class CBinaryWriter : public IArchive { u32 Offset; u32 NumSubParams; - bool Abstract; }; std::vector mParamStack; @@ -19,29 +18,31 @@ class CBinaryWriter : public IArchive bool mOwnsStream; public: - CBinaryWriter(const TString& rkFilename, u32 Magic, u16 FileVersion, EGame Game) + CBinaryWriter(const TString& rkFilename, u32 Magic, u16 FileVersion = 0, EGame Game = eUnknownGame) : IArchive() , mMagic(Magic) , mOwnsStream(true) { + mArchiveFlags = AF_Writer | AF_Binary; mpStream = new CFileOutStream(rkFilename, IOUtil::eBigEndian); if (mpStream->IsValid()) { mpStream->WriteLong(0); // Magic is written after the rest of the file has been successfully written SetVersion(skCurrentArchiveVersion, FileVersion, Game); - GetVersionInfo().Write(*mpStream); } InitParamStack(); + SerializeVersion(); } - CBinaryWriter(IOutputStream *pStream, u16 FileVersion, EGame Game) + CBinaryWriter(IOutputStream *pStream, u16 FileVersion = 0, EGame Game = eUnknownGame) : IArchive() , mMagic(0) , mOwnsStream(false) { ASSERT(pStream && pStream->IsValid()); + mArchiveFlags = AF_Writer | AF_Binary; mpStream = pStream; SetVersion(skCurrentArchiveVersion, FileVersion, Game); InitParamStack(); @@ -53,6 +54,7 @@ public: , mOwnsStream(false) { ASSERT(pStream && pStream->IsValid()); + mArchiveFlags = AF_Writer | AF_Binary; mpStream = pStream; SetVersion(rkVersion); InitParamStack(); @@ -83,16 +85,12 @@ private: mParamStack.reserve(20); mpStream->WriteLong(0xFFFFFFFF); mpStream->WriteLong(0); // Size filler - mParamStack.push_back( SParameter { mpStream->Tell(), 0, false } ); + mParamStack.push_back( SParameter { mpStream->Tell(), 0 } ); } public: // Interface - virtual bool IsReader() const { return false; } - virtual bool IsWriter() const { return true; } - virtual bool IsTextFormat() const { return false; } - - virtual bool ParamBegin(const char *pkName) + virtual bool ParamBegin(const char *pkName, u32 Flags) { // Update parent param mParamStack.back().NumSubParams++; @@ -106,7 +104,7 @@ public: mpStream->WriteLong(-1); // Param size filler // Add new param to the stack - mParamStack.push_back( SParameter { mpStream->Tell(), 0, false } ); + mParamStack.push_back( SParameter { mpStream->Tell(), 0 } ); return true; } @@ -125,7 +123,6 @@ public: // Write param child count if (rParam.NumSubParams > 0 || mParamStack.size() == 1) { - if (rParam.Abstract) mpStream->Skip(4); mpStream->WriteLong(rParam.NumSubParams); } @@ -133,6 +130,13 @@ public: mParamStack.pop_back(); } + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) + { + bool ValidPtr = (Pointer != nullptr); + *this << SerialParameter("PointerValid", ValidPtr); + return ValidPtr; + } + virtual void SerializeContainerSize(u32& rSize, const TString& /*rkElemName*/) { // Normally handled by ParamBegin and ParamEnd but we need to do something here to account for zero-sized containers @@ -140,36 +144,23 @@ public: mpStream->WriteLong(0); } - virtual void SerializeAbstractObjectType(u32& rType) - { - // Mark this parameter as abstract so we can account for the object type in the filestream - mpStream->WriteLong(rType); - mParamStack.back().Abstract = true; - } - - virtual void SerializePrimitive(bool& rValue) { mpStream->WriteBool(rValue); } - virtual void SerializePrimitive(char& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(s8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(u8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializePrimitive(s16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializePrimitive(u16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializePrimitive(s32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializePrimitive(u32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializePrimitive(s64& rValue) { mpStream->WriteLongLong(rValue); } - virtual void SerializePrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } - virtual void SerializePrimitive(float& rValue) { mpStream->WriteFloat(rValue); } - virtual void SerializePrimitive(double& rValue) { mpStream->WriteDouble(rValue); } - virtual void SerializePrimitive(TString& rValue) { mpStream->WriteSizedString(rValue); } - virtual void SerializePrimitive(TWideString& rValue) { mpStream->WriteSizedWString(rValue); } - virtual void SerializePrimitive(CFourCC& rValue) { rValue.Write(*mpStream); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } - - virtual void SerializeHexPrimitive(u8& rValue) { mpStream->WriteByte(rValue); } - virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); } - virtual void SerializeHexPrimitive(u32& rValue) { mpStream->WriteLong(rValue); } - virtual void SerializeHexPrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); } - - virtual void BulkSerialize(void* pData, u32 Size) { mpStream->WriteBytes(pData, Size); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { mpStream->WriteBool(rValue); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { mpStream->WriteByte(rValue); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { mpStream->WriteShort(rValue); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { mpStream->WriteShort(rValue); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { mpStream->WriteLong(rValue); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { mpStream->WriteLong(rValue); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { mpStream->WriteLongLong(rValue); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { mpStream->WriteLongLong(rValue); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { mpStream->WriteFloat(rValue); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { mpStream->WriteDouble(rValue); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { mpStream->WriteSizedString(rValue); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { mpStream->WriteSizedWString(rValue); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { rValue.Write(*mpStream); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { rValue.Write(*mpStream, CAssetID::GameIDLength(Game())); } + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { mpStream->WriteBytes(pData, Size); } }; #endif // CBINARYWRITER diff --git a/src/Common/Serialization/CXMLReader.h b/src/Common/Serialization/CXMLReader.h index 09bb414e..59fc9c5e 100644 --- a/src/Common/Serialization/CXMLReader.h +++ b/src/Common/Serialization/CXMLReader.h @@ -8,23 +8,24 @@ class CXMLReader : public IArchive { tinyxml2::XMLDocument mDoc; tinyxml2::XMLElement *mpCurElem; // Points to the next element being read + const char* mpAttribute; // Name of the parameter we are reading from an attribute bool mJustEndedParam; // Indicates we just ended a primitive parameter public: CXMLReader(const TString& rkFileName) : IArchive() + , mpAttribute(nullptr) , mJustEndedParam(false) { + mArchiveFlags = AF_Reader | AF_Text; + // Load XML and set current element to the root element; read version mDoc.LoadFile(*rkFileName); mpCurElem = mDoc.FirstChildElement(); if (mpCurElem != nullptr) { - mArchiveVersion = (u16) TString( mpCurElem->Attribute("ArchiveVer") ).ToInt32(10); - mFileVersion = (u16) TString( mpCurElem->Attribute("FileVer") ).ToInt32(10); - const char *pkGameAttr = mpCurElem->Attribute("Game"); - mGame = pkGameAttr ? GetGameForID( CFourCC(pkGameAttr) ) : eUnknownGame; + SerializeVersion(); } else { @@ -42,9 +43,17 @@ public: virtual bool IsWriter() const { return false; } virtual bool IsTextFormat() const { return true; } - virtual bool ParamBegin(const char *pkName) + virtual bool ParamBegin(const char *pkName, u32 Flags) { ASSERT(IsValid()); + ASSERT(!mpAttribute); // Attributes cannot have sub-children + + // Store as an attribute if requested + if (Flags & SH_Attribute) + { + mpAttribute = mpCurElem->Attribute(pkName); + return mpAttribute != nullptr; + } // Push new parent if needed if (!mJustEndedParam) @@ -55,7 +64,7 @@ public: } // Verify the current element matches the name of the next serialized parameter. - if ( strcmp(mpCurElem->Name(), pkName) == 0) + if ( (Flags & SH_IgnoreName) || strcmp(mpCurElem->Name(), pkName) == 0 ) { mJustEndedParam = false; return true; @@ -88,59 +97,60 @@ public: virtual void ParamEnd() { - if (mJustEndedParam) - mpCurElem = mpCurElem->Parent()->ToElement(); + if (mpAttribute) + mpAttribute = nullptr; - tinyxml2::XMLElement *pElem = mpCurElem->NextSiblingElement(); - if (pElem) - mpCurElem = pElem; + else + { + if (mJustEndedParam) + mpCurElem = mpCurElem->Parent()->ToElement(); - mJustEndedParam = true; + tinyxml2::XMLElement *pElem = mpCurElem->NextSiblingElement(); + if (pElem) + mpCurElem = pElem; + + mJustEndedParam = true; + } } protected: TString ReadParam() { - return TString(mpCurElem->GetText()); + return TString( mpAttribute ? mpAttribute : mpCurElem->GetText() ); } public: - virtual void SerializeContainerSize(u32& rSize, const TString& rkElemName) + virtual void SerializeArraySize(u32& Value) { - rSize = 0; + Value = 0; - for (tinyxml2::XMLElement *pElem = mpCurElem->FirstChildElement(*rkElemName); pElem; pElem = pElem->NextSiblingElement(*rkElemName)) - rSize++; + for (tinyxml2::XMLElement *pElem = mpCurElem->FirstChildElement(); pElem; pElem = pElem->NextSiblingElement()) + Value++; } - virtual void SerializeAbstractObjectType(u32& rType) + virtual bool PreSerializePointer(void*& InPointer, u32 Flags) { - rType = TString(mpCurElem->Attribute("Type")).ToInt32(10); + return mpCurElem->GetText() == nullptr || strcmp(mpCurElem->GetText(), "NULL") != 0; } - virtual void SerializePrimitive(bool& rValue) { rValue = (ReadParam() == "true" ? true : false); } - virtual void SerializePrimitive(char& rValue) { rValue = ReadParam().Front(); } - virtual void SerializePrimitive(s8& rValue) { rValue = (s8) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(u8& rValue) { rValue = (u8) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(s16& rValue) { rValue = (s16) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(s32& rValue) { rValue = (s32) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(u32& rValue) { rValue = (u32) ReadParam().ToInt32(10); } - virtual void SerializePrimitive(s64& rValue) { rValue = (s64) ReadParam().ToInt64(10); } - virtual void SerializePrimitive(u64& rValue) { rValue = (u64) ReadParam().ToInt64(10); } - virtual void SerializePrimitive(float& rValue) { rValue = ReadParam().ToFloat(); } - virtual void SerializePrimitive(double& rValue) { rValue = (double) ReadParam().ToFloat(); } - virtual void SerializePrimitive(TString& rValue) { rValue = ReadParam(); } - virtual void SerializePrimitive(TWideString& rValue) { rValue = ReadParam().ToUTF16(); } - virtual void SerializePrimitive(CFourCC& rValue) { rValue = CFourCC( ReadParam() ); } - virtual void SerializePrimitive(CAssetID& rValue) { rValue = CAssetID::FromString( ReadParam() ); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { rValue = (ReadParam() == "true" ? true : false); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { rValue = ReadParam().Front(); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { rValue = (s8) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { rValue = (u8) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { rValue = (s16) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { rValue = (u16) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { rValue = (s32) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { rValue = (u32) ReadParam().ToInt32( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { rValue = (s64) ReadParam().ToInt64( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { rValue = (u64) ReadParam().ToInt64( (Flags & SH_HexDisplay) ? 16 : 10 ); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { rValue = ReadParam().ToFloat(); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { rValue = (double) ReadParam().ToFloat(); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { rValue = ReadParam(); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { rValue = ReadParam().ToUTF16(); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { rValue = CFourCC( ReadParam() ); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { rValue = CAssetID::FromString( ReadParam() ); } - virtual void SerializeHexPrimitive(u8& rValue) { rValue = (u8) ReadParam().ToInt32(16); } - virtual void SerializeHexPrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(16); } - virtual void SerializeHexPrimitive(u32& rValue) { rValue = (u32) ReadParam().ToInt32(16); } - virtual void SerializeHexPrimitive(u64& rValue) { rValue = (u64) ReadParam().ToInt32(16); } - - virtual void BulkSerialize(void* pData, u32 Size) + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { char* pCharData = (char*) pData; TString StringData = ReadParam(); diff --git a/src/Common/Serialization/CXMLWriter.h b/src/Common/Serialization/CXMLWriter.h index d25cddd2..27c30512 100644 --- a/src/Common/Serialization/CXMLWriter.h +++ b/src/Common/Serialization/CXMLWriter.h @@ -9,16 +9,19 @@ class CXMLWriter : public IArchive { tinyxml2::XMLDocument mDoc; - TString mOutFilename; tinyxml2::XMLElement *mpCurElem; + TString mOutFilename; + const char* mpAttributeName; bool mSaved; public: - CXMLWriter(const TString& rkFileName, const TString& rkRootName, u16 FileVersion, EGame Game = eUnknownGame) + CXMLWriter(const TString& rkFileName, const TString& rkRootName, u16 FileVersion = 0, EGame Game = eUnknownGame) : IArchive() , mOutFilename(rkFileName) + , mpAttributeName(nullptr) , mSaved(false) { + mArchiveFlags = AF_Writer | AF_Text; SetVersion(skCurrentArchiveVersion, FileVersion, Game); // Create declaration and root node @@ -29,9 +32,7 @@ public: mDoc.LinkEndChild(mpCurElem); // Write version data - mpCurElem->SetAttribute("ArchiveVer", (int) skCurrentArchiveVersion); - mpCurElem->SetAttribute("FileVer", (int) FileVersion); - if (Game != eUnknownGame) mpCurElem->SetAttribute("Game", *GetGameID(Game).ToString()); + SerializeVersion(); } ~CXMLWriter() @@ -69,71 +70,86 @@ public: } // Interface - virtual bool IsReader() const { return false; } - virtual bool IsWriter() const { return true; } - virtual bool IsTextFormat() const { return true; } - - virtual bool ParamBegin(const char *pkName) + virtual bool ParamBegin(const char *pkName, u32 Flags) { ASSERT(IsValid()); + ASSERT(!mpAttributeName); // Attributes cannot have sub-children + + // Read as attribute if needed + if (Flags & SH_Attribute) + { + mpAttributeName = pkName; + } + else + { + tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName); + mpCurElem->LinkEndChild(pElem); + mpCurElem = pElem; + } - tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName); - mpCurElem->LinkEndChild(pElem); - mpCurElem = pElem; return true; } virtual void ParamEnd() { - mpCurElem = mpCurElem->Parent()->ToElement(); + if (mpAttributeName) + mpAttributeName = nullptr; + else + mpCurElem = mpCurElem->Parent()->ToElement(); } protected: void WriteParam(const char *pkValue) { - mpCurElem->SetText(pkValue); + if (mpAttributeName) + mpCurElem->SetAttribute(mpAttributeName, pkValue); + else + mpCurElem->SetText(pkValue); } public: - virtual void SerializeContainerSize(u32&, const TString&) + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) { - // Reader obtains container size from number of child elements + if (!Pointer) + { + mpCurElem->SetText("NULL"); + return false; + } + return true; } - virtual void SerializeAbstractObjectType(u32& rType) + virtual void SerializeArraySize(u32& Value) { - mpCurElem->SetAttribute("Type", (unsigned int) rType); + // Do nothing. Reader obtains container size from number of child elements } - virtual void SerializePrimitive(bool& rValue) { WriteParam(rValue ? "true" : "false"); } - virtual void SerializePrimitive(char& rValue) { WriteParam(*TString(rValue)); } - virtual void SerializePrimitive(s8& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(u8& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(s16& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(u16& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(s32& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(u32& rValue) { WriteParam(*TString::FromInt32(rValue, 0, 10)); } - virtual void SerializePrimitive(s64& rValue) { WriteParam(*TString::FromInt64(rValue, 0, 10)); } - virtual void SerializePrimitive(u64& rValue) { WriteParam(*TString::FromInt64(rValue, 0, 10)); } - virtual void SerializePrimitive(float& rValue) { WriteParam(*TString::FromFloat(rValue)); } - virtual void SerializePrimitive(double& rValue) { WriteParam(*TString::FromFloat((float) rValue)); } - virtual void SerializePrimitive(TString& rValue) { WriteParam(*rValue); } - virtual void SerializePrimitive(TWideString& rValue) { WriteParam(*rValue.ToUTF8()); } - virtual void SerializePrimitive(CFourCC& rValue) { WriteParam(*rValue.ToString()); } - virtual void SerializePrimitive(CAssetID& rValue) { WriteParam(*rValue.ToString( CAssetID::GameIDLength(Game()) )); } + virtual void SerializePrimitive(bool& rValue, u32 Flags) { WriteParam(rValue ? "true" : "false"); } + virtual void SerializePrimitive(char& rValue, u32 Flags) { WriteParam(*TString(rValue)); } + virtual void SerializePrimitive(s8& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u8&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(u8& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u8&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(s16& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u16&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(u16& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u16&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(s32& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u32&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(u32& rValue, u32 Flags) { WriteParam( (Flags & SH_HexDisplay) ? *TString::HexString((u32&) rValue, 0) : *TString::FromInt32(rValue, 0, 10) ); } + virtual void SerializePrimitive(s64& rValue, u32 Flags) { WriteParam( *TString::FromInt64(rValue, 0, (Flags & SH_HexDisplay) ? 16 : 10) ); } + virtual void SerializePrimitive(u64& rValue, u32 Flags) { WriteParam( *TString::FromInt64(rValue, 0, (Flags & SH_HexDisplay) ? 16 : 10) ); } + virtual void SerializePrimitive(float& rValue, u32 Flags) { WriteParam( *TString::FromFloat(rValue, 1, true) ); } + virtual void SerializePrimitive(double& rValue, u32 Flags) { WriteParam( *TString::FromFloat((float) rValue, 1, true) ); } + virtual void SerializePrimitive(TString& rValue, u32 Flags) { WriteParam( *rValue ); } + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) { WriteParam( *rValue.ToUTF8() ); } + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) { WriteParam( *rValue.ToString() ); } + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) { WriteParam( *rValue.ToString( CAssetID::GameIDLength(Game()) ) ); } - virtual void SerializeHexPrimitive(u8& rValue) { WriteParam(*TString::HexString(rValue, 2)); } - virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); } - virtual void SerializeHexPrimitive(u32& rValue) { WriteParam(*TString::HexString(rValue, 8)); } - virtual void SerializeHexPrimitive(u64& rValue) { WriteParam(*TString::HexString((u32) rValue, 16)); } - - virtual void BulkSerialize(void* pData, u32 Size) + virtual void SerializeBulkData(void* pData, u32 Size, u32 Flags) { char* pCharData = (char*) pData; TString OutString(Size*2); for (u32 ByteIdx = 0; ByteIdx < Size; ByteIdx++) - itoa(pCharData[ByteIdx], &OutString[ByteIdx*2], 16); + { + //@todo: sloooooow. maybe replace with a LUT? + sprintf(&OutString[ByteIdx*2], "%02X", pCharData[ByteIdx]); + } WriteParam(*OutString); } diff --git a/src/Common/Serialization/IArchive.h b/src/Common/Serialization/IArchive.h index 5bd045fa..0df22e7f 100644 --- a/src/Common/Serialization/IArchive.h +++ b/src/Common/Serialization/IArchive.h @@ -9,6 +9,14 @@ #include "Common/TString.h" #include "Common/types.h" +#include + +#include +#include +#include +#include +#include + /* This is a custom serialization implementation intended for saving game assets out to editor- * friendly formats, such as XML. The main goals of the serialization system is to simplify the * code for reading and writing editor files and to be able to easily update those files without @@ -46,117 +54,127 @@ * variable will be used as the parameter name instead). */ -// TSerialParameter - name/value pair for generic serial parameters +/** ESerialHint - Parameter hint flags */ +enum ESerialHint +{ + SH_HexDisplay = 0x1, // The parameter should be written in hex in text formats + SH_Optional = 0x2, // The parameter should not be written to the file if its value matches the default value + SH_NeverSave = 0x4, // The parameter should not be saved to files + SH_AlwaysSave = 0x8, // The parameter should always be saved regardless of if it matches the default value + SH_Attribute = 0x10, // The parameter is an attribute of another parameter. Attributes cannot have children. + SH_IgnoreName = 0x20, // The parameter name will not be used to validate file data. May yield incorrect results if used improperly! +}; + +/** EArchiveFlags */ +enum EArchiveFlags +{ + AF_Reader = 0x1, // Archive reads data + AF_Writer = 0x2, // Archive writes data + AF_Text = 0x4, // Archive reads/writes to a text format + AF_Binary = 0x8, // Archive reads/writes to a binary format + AF_NoSkipping = 0x10, // Properties are never skipped +}; + +/** Shortcut macro for enable_if */ +#define ENABLE_IF(Conditions, ReturnType) typename std::enable_if< Conditions, ReturnType >::type + +/** Check for whether the equality operator has been implemented for a given type */ +template() == std::declval())> +std::true_type THasEqualToOperator(const ValType&); +std::false_type THasEqualToOperator(...); +template using THasEqualTo = decltype(THasEqualToOperator(std::declval())); + +/** Class that determines if the type is a container */ +template struct TIsContainer : std::false_type {}; +template struct TIsContainer< std::vector > : std::true_type {}; +template struct TIsContainer< std::list > : std::true_type {}; +template struct TIsContainer< std::set > : std::true_type {}; +template struct TIsContainer< std::map > : std::true_type {}; +template struct TIsContainer< std::unordered_map > : std::true_type {}; + +/** Helper macro that tells us whether the parameter supports default property values */ +#define SUPPORTS_DEFAULT_VALUES (!std::is_pointer_v && std::is_copy_assignable_v && THasEqualTo::value && !TIsContainer::value) + +/** TSerialParameter - name/value pair for generic serial parameters */ template struct TSerialParameter { - const char *pkName; - ValType& rValue; + const char* pkName; + ValType& rValue; + u32 HintFlags; + const ValType* pDefaultValue; }; +/** Function that creates a SerialParameter */ +template +ENABLE_IF( SUPPORTS_DEFAULT_VALUES, TSerialParameter ) +inline SerialParameter(const char* pkName, ValType& rValue, u32 HintFlags = 0, const ValType& rkDefaultValue = ValType()) +{ + return TSerialParameter { pkName, rValue, HintFlags, &rkDefaultValue }; +} +template +ENABLE_IF( !SUPPORTS_DEFAULT_VALUES, TSerialParameter ) +inline SerialParameter(const char* pkName, ValType& rValue, u32 HintFlags = 0) +{ + return TSerialParameter { pkName, rValue, HintFlags, nullptr }; +} + +/** Returns whether the parameter value matches its default value */ +template +ENABLE_IF( SUPPORTS_DEFAULT_VALUES, bool ) +inline ParameterMatchesDefault( const TSerialParameter& kParameter ) +{ + return kParameter.pDefaultValue != nullptr && kParameter.rValue == *kParameter.pDefaultValue; +} + template -inline TSerialParameter MakeSerialParameter(const char *pkName, ValType& rValue) +ENABLE_IF( !SUPPORTS_DEFAULT_VALUES, bool ) +inline ParameterMatchesDefault( const TSerialParameter& ) { - return TSerialParameter { pkName, rValue }; + return false; } -#define SERIAL(ParamName, ParamValue) MakeSerialParameter(ParamName, ParamValue) -#define SERIAL_AUTO(ParamValue) MakeSerialParameter(#ParamValue, ParamValue) - -// THexSerialParameter - same as TSerialParameter but serialized in hex for improved readability +/** Initializes the parameter to its default value */ template -struct THexSerialParameter +ENABLE_IF( SUPPORTS_DEFAULT_VALUES, bool ) +inline InitParameterToDefault( TSerialParameter& Param ) { - const char *pkName; - ValType& rValue; -}; - -template::value, int>*/> -inline THexSerialParameter MakeHexSerialParameter(const char *pkName, ValType& rValue) -{ - return THexSerialParameter { pkName, rValue }; + if (Param.pDefaultValue != nullptr) + { + Param.rValue = *Param.pDefaultValue; + return true; + } + else + return false; } -#define SERIAL_HEX(ParamName, ParamValue) MakeHexSerialParameter(ParamName, ParamValue) -#define SERIAL_HEX_AUTO(ParamValue) MakeHexSerialParameter(#ParamValue, ParamValue) - -// TAbstractSerialParameter - name/value pair for polymorphic objects with a pointer to a factory -template -struct TAbstractSerialParameter -{ - const char *pkName; - ValType*& rValue; - FactoryType *pFactory; -}; - -template -inline TAbstractSerialParameter MakeAbstractSerialParameter(const char *pkName, ValType*& rValue, FactoryType *pFactory) -{ - return TAbstractSerialParameter { pkName, rValue, pFactory }; -} - -#define SERIAL_ABSTRACT(ParamName, ParamValue, Factory) MakeAbstractSerialParameter(ParamName, ParamValue, Factory) -#define SERIAL_ABSTRACT_AUTO(ParamValue, Factory) MakeAbstractSerialParameter(#ParamValue, ParamValue, Factory) - -// TContainerSerialParameter - name/value pair for containers with a parameter name string -template -struct TContainerSerialParameter -{ - const char *pkName; - ValType& rContainer; - const char *pkElementName; -}; - template -inline TContainerSerialParameter MakeSerialParameter(const char *pkName, ValType& rContainer, const char *pkElementName) +ENABLE_IF( !SUPPORTS_DEFAULT_VALUES, bool ) +inline InitParameterToDefault( TSerialParameter& ) { - return TContainerSerialParameter { pkName, rContainer, pkElementName }; + return false; } -#define SERIAL_CONTAINER(ParamName, Container, ElementName) MakeSerialParameter(ParamName, Container, ElementName) -#define SERIAL_CONTAINER_AUTO(Container, ElementName) MakeSerialParameter(#Container, Container, ElementName) - -// TAbstractContainerSerialParameter - name/value pair for containers of polymorphic objects with a parameter name string and a pointer to a factory -template -struct TAbstractContainerSerialParameter -{ - const char *pkName; - ValType& rContainer; - const char *pkElementName; - FactoryType *pFactory; -}; - -template -inline TAbstractContainerSerialParameter MakeSerialParameter(const char *pkName, ValType& rContainer, const char *pkElementName, FactoryType *pFactory) -{ - return TAbstractContainerSerialParameter { pkName, rContainer, pkElementName, pFactory }; -} - -#define SERIAL_ABSTRACT_CONTAINER(ParamName, Container, ElementName, Factory) MakeSerialParameter(ParamName, Container, ElementName, Factory) -#define SERIAL_ABSTRACT_CONTAINER_AUTO(Container, ElementName, Factory) MakeSerialParameter(#Container, Container, ElementName, Factory) - -// SFINAE serialize function type check +/** SFINAE serialize function type check */ // https://jguegant.github.io/blogs/tech/sfinae-introduction.html void Serialize(); // This needs to be here or else the global Serialize method handling causes a compiler error. Not sure of a better fix -void SerializeContainer(); +void BulkSerialize(); -template +/** Helper struct to verify that function Func exists and matches the given function signature (FuncType) */ +template struct FunctionExists; + +/** Determine what kind of Serialize function the type has */ +template struct SerialType { -public: enum { Primitive, Member, Global, None }; - // Helper struct to verify that function Func exists and matches the given function signature (FuncType) - template struct FunctionExists; - // Check for ArcType::SerializePrimitive(ValType&) method - template static long long& Check(FunctionExists*); + template static long long& Check(FunctionExists*); // Check for ValType::Serialize(ArcType&) template static long& Check(FunctionExists*); // Check for global Serialize(ArcType&,ValType&) function template static short& Check(FunctionExists*); - // Check for global SerializeContainer(ArcType&,ValType&,const TString&) - template static short& Check(FunctionExists*); // Fallback - no valid Serialize method exists template static char& Check(...); @@ -167,9 +185,44 @@ public: None); }; -#define ENABLE_FOR_SERIAL_TYPE(SType) typename std::enable_if::Type == SerialType::##SType, int>::type = 0 +/** Helper for determining the type used by a given abstract object class (i.e. the type returned by the Type() function) */ +#define ABSTRACT_TYPE decltype( std::declval().Type() ) -// Actual archive class +/** For abstract types, determine what kind of ArchiveConstructor the type has */ +template +struct ArchiveConstructorType +{ + typedef ABSTRACT_TYPE ObjType; + + enum { Basic, Advanced, None }; + + // Check for ValueType::ArchiveConstructor(ObjectType, const IArchive&) + template static long& Check(FunctionExists*); + // Check for ValueType::ArchiveConstructor(ObjectType) + template static short& Check(FunctionExists*); + // Fallback - no valid ArchiveConstructor method exists + template static char& Check(...); + + // Set Type enum to correspond to whichever function exists + static const int Type = (sizeof(Check(0)) == sizeof(long) ? Advanced : + sizeof(Check(0)) == sizeof(short) ? Basic : + None); + + // If you fail here, you are missing an ArchiveConstructor() function, or you do have one but it is malformed. + // Check the comments at the top of this source file for details on serialization requirements for abstract objects. + static_assert(Type != None, "Abstract objects being serialized must have virtual Type() and static ArchiveConstructor() functions."); +}; + +/** Helper that turns functions on or off depending on their serialize type */ +#define IS_SERIAL_TYPE(SType) (SerialType::Type == SerialType::##SType) + +/** Helper that turns functions on or off depending on their StaticConstructor type */ +#define IS_ARCHIVE_CONSTRUCTOR_TYPE(CType) (ArchiveConstructorType::Type == ArchiveConstructorType::##CType) + +/** Helper that turns functions on or off depending on if the parameter type is abstract */ +#define IS_ABSTRACT std::is_abstract::value + +/** IArchive - Main serializer archive interface */ class IArchive { protected: @@ -177,11 +230,25 @@ protected: u16 mFileVersion; EGame mGame; + // Subclasses must fill in flags in their constructors!!! + u32 mArchiveFlags; + + // Info about the stack of parameters being serialized + struct SParmStackEntry + { + size_t TypeID; + size_t TypeSize; + void* pDataPointer; + u32 HintFlags; + }; + std::vector mParmStack; + public: enum EArchiveVersion { eArVer_Initial, eArVer_32BitBinarySize, + eArVer_Refactor, // Insert new versions before this line eArVer_Max }; @@ -191,236 +258,370 @@ public: : mFileVersion(0) , mArchiveVersion(skCurrentArchiveVersion) , mGame(eUnknownGame) - {} + , mArchiveFlags(0) + { + // hack to reduce allocations + mParmStack.reserve(16); + } virtual ~IArchive() {} +protected: + // Serialize archive version. Always call after opening a file. + void SerializeVersion() + { + *this << SerialParameter("ArchiveVer", mArchiveVersion, SH_Attribute) + << SerialParameter("FileVer", mFileVersion, SH_Attribute | SH_Optional, (u16) 0) + << SerialParameter("Game", mGame, SH_Attribute | SH_Optional, eUnknownGame); + } + + // Return whether this parameter should be serialized + template + bool ShouldSerializeParameter(const TSerialParameter& Param) + { + if (mArchiveFlags & AF_NoSkipping) + return true; + + if ( IsWriter() ) + { + if (Param.HintFlags & SH_NeverSave) + return false; + + if ( ( Param.HintFlags & SH_Optional ) && + ( Param.HintFlags & SH_AlwaysSave ) == 0 && + ( ParameterMatchesDefault(Param) ) ) + return false; + } + + return true; + } + + // Instantiate an abstract object from the file + // Only readers are allowed to instantiate objects + template + ENABLE_IF( IS_ARCHIVE_CONSTRUCTOR_TYPE(Basic), ValType* ) + inline InstantiateAbstractObject(const TSerialParameter& Param, ObjType Type) + { + // Variant for basic static constructor + ASSERT( IsReader() ); + return ValType::ArchiveConstructor(Type); + } + + template + ENABLE_IF( IS_ARCHIVE_CONSTRUCTOR_TYPE(Advanced), ValType* ) + InstantiateAbstractObject(const TSerialParameter& Param, ObjType Type) + { + // Variant for advanced static constructor + ASSERT( IsReader() ); + return ValType::ArchiveConstructor(Type, *this); + } + + // Parameter stack handling + template + inline void PushParameter(const TSerialParameter& Param) + { +#if _DEBUG + if (mParmStack.size() > 0) + { + // Attribute properties cannot have children! + ASSERT( (mParmStack.back().HintFlags & SH_Attribute) == 0 ); + } +#endif + + SParmStackEntry Entry; + Entry.TypeID = typeid(ValType).hash_code(); + Entry.TypeSize = sizeof(ValType); + Entry.pDataPointer = &Param.rValue; + Entry.HintFlags = Param.HintFlags; + mParmStack.push_back(Entry); + } + + template + inline void PopParameter(const TSerialParameter& Param) + { +#if _DEBUG + // Make sure the entry matches the param that has been passed in + ASSERT(mParmStack.size() > 0); + const SParmStackEntry& kEntry = mParmStack.back(); + ASSERT(kEntry.TypeID == typeid(ValType).hash_code()); + ASSERT(kEntry.pDataPointer == &Param.rValue); +#endif + mParmStack.pop_back(); + } + +public: // Serialize primitives - template - inline IArchive& operator<<(TSerialParameter rParam) + template + ENABLE_IF( IS_SERIAL_TYPE(Primitive), IArchive& ) + operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) + PushParameter(rParam); + + if (ShouldSerializeParameter(rParam) + && ParamBegin(rParam.pkName, rParam.HintFlags)) { - SerializePrimitive(rParam.rValue); + SerializePrimitive(rParam.rValue, rParam.HintFlags); ParamEnd(); } + else if (IsReader()) + InitParameterToDefault(rParam); + + PopParameter(rParam); return *this; } - // Serialize pointers to primitives - template - inline IArchive& operator<<(TSerialParameter rParam) + template + ENABLE_IF( IS_SERIAL_TYPE(Primitive) && !IS_ABSTRACT, IArchive& ) + operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) - { - if (IsReader() && !rParam.rValue) rParam.rValue = new ValType; - SerializePrimitive(*rParam.rValue); - ParamEnd(); - } - return *this; - } + ASSERT( !(mArchiveFlags & AF_Writer) || rParam.rValue != nullptr ); + PushParameter(rParam); - // Serialize hex primitives - template - inline IArchive& operator<<(THexSerialParameter rParam) - { - if (ParamBegin(rParam.pkName)) + if (ShouldSerializeParameter(rParam) + && ParamBegin(rParam.pkName, rParam.HintFlags)) { - SerializeHexPrimitive(rParam.rValue); - ParamEnd(); - } - return *this; - } + // Support for old versions of archives that serialize types on non-abstract polymorphic pointers + if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v) + { + u32 Type; + *this << SerialParameter("Type", Type, SH_Attribute); + } - // Serialize pointers to hex primitives - template - inline IArchive& operator<<(THexSerialParameter rParam) - { - if (ParamBegin(rParam.pkName)) - { - if (IsReader() && !rParam.rValue) rParam.rValue = new ValType; - SerializeHexPrimitive(*rParam.rValue); - ParamEnd(); - } - return *this; - } + if (PreSerializePointer(rParam.rValue, rParam.HintFlags)) + { + if (rParam.rValue == nullptr && (mArchiveFlags & AF_Reader)) + rParam.rValue = new ValType; - // Serialize objects with member Serialize methods - template - inline IArchive& operator<<(TSerialParameter rParam) - { - if (ParamBegin(rParam.pkName)) - { - rParam.rValue.Serialize(*this); - ParamEnd(); - } - return *this; - } + if (rParam.rValue != nullptr) + SerializePrimitive(*rParam.rValue, rParam.HintFlags); + } + else if (IsReader()) + rParam.rValue = nullptr; - // Serialize pointers to objects with member Serialize methods - template - inline IArchive& operator<<(TSerialParameter rParam) - { - if (ParamBegin(rParam.pkName)) - { - if (IsReader() && !rParam.rValue) rParam.rValue = new ValType; - rParam.rValue->Serialize(*this); ParamEnd(); } + + PopParameter(rParam); return *this; } // Serialize objects with global Serialize functions - template - inline IArchive& operator<<(TSerialParameter rParam) + template + ENABLE_IF( IS_SERIAL_TYPE(Global), IArchive& ) + inline operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) + PushParameter(rParam); + + if (ShouldSerializeParameter(rParam) + && ParamBegin(rParam.pkName, rParam.HintFlags)) { Serialize(*this, rParam.rValue); ParamEnd(); } + else if (IsReader()) + InitParameterToDefault(rParam); + + PopParameter(rParam); return *this; } - // Serialize pointers to objects with global Serialize functions - template - inline IArchive& operator<<(TSerialParameter rParam) + template + ENABLE_IF( IS_SERIAL_TYPE(Global) && !IS_ABSTRACT, IArchive&) + operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) - { - if (IsReader() && !rParam.rValue) rParam.rValue = new ValType; - Serialize(*this, *rParam.rValue); - ParamEnd(); - } - return *this; - } + ASSERT( !IsWriter() || rParam.rValue != nullptr ); + PushParameter(rParam); - // Serialize abstract objects (global methods for abstract objects not supported) - template - inline IArchive& operator<<(TAbstractSerialParameter rParam) - { - if (ParamBegin(rParam.pkName)) + if (ShouldSerializeParameter(rParam) + && ParamBegin(rParam.pkName)) { - // Serialize object type - u32 Type = (IsWriter() ? (u32) rParam.rValue->Type() : 0); - SerializeAbstractObjectType(Type); - - // Reader only - instantiate object - if (IsReader()) + // Support for old versions of archives that serialize types on non-abstract polymorphic pointers + if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v) { - rParam.rValue = static_cast(rParam.pFactory->SpawnObject(Type)); - ASSERT(rParam.rValue != nullptr); + u32 Type; + *this << SerialParameter("Type", Type, SH_Attribute); } - // Finish serialize - rParam.rValue->Serialize(*this); + if (PreSerializePointer(rParam.rValue, rParam.HintFlags, rParam.HintFlags)) + { + if (rParam.rValue == nullptr && IsReader()) + rParam.rValue = new ValType; + + if (rParam.rValue != nullptr) + Serialize(*this, *rParam.rValue); + } + else if (IsReader()) + rParam.rValue = nullptr; + ParamEnd(); } + PopParameter(rParam); return *this; } - // Serialize containers (member methods for containers not supported) - template - inline IArchive& operator<<(TContainerSerialParameter rParam) + // Serialize objects with Serialize methods + template + ENABLE_IF( IS_SERIAL_TYPE(Member), IArchive& ) + operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) + PushParameter(rParam); + + if (ShouldSerializeParameter(rParam) && + ParamBegin(rParam.pkName, rParam.HintFlags)) { - SerializeContainer(*this, rParam.rContainer, rParam.pkElementName); + rParam.rValue.Serialize(*this); ParamEnd(); } + else if (IsReader()) + InitParameterToDefault(rParam); + PopParameter(rParam); return *this; } - // Serialize abstract containers (member methods for containers not supported) - template - inline IArchive& operator<<(TAbstractContainerSerialParameter rParam) + template + ENABLE_IF( IS_SERIAL_TYPE(Member) && !IS_ABSTRACT, IArchive& ) + operator<<(TSerialParameter rParam) { - if (ParamBegin(rParam.pkName)) + PushParameter(rParam); + + if (ShouldSerializeParameter(rParam) && + ParamBegin(rParam.pkName, rParam.HintFlags)) { - SerializeContainer(*this, rParam.rContainer, rParam.pkElementName, rParam.pFactory); + // Support for old versions of archives that serialize types on non-abstract polymorphic pointers + if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v) + { + u32 Type; + *this << SerialParameter("Type", Type, SH_Attribute); + } + + if (PreSerializePointer((void*&) rParam.rValue, rParam.HintFlags)) + { + if (rParam.rValue == nullptr && IsReader()) + rParam.rValue = new ValType; + + if (rParam.rValue != nullptr) + rParam.rValue->Serialize(*this); + } + else if (IsReader()) + rParam.rValue = nullptr; + ParamEnd(); } + PopParameter(rParam); return *this; } + // Serialize polymorphic objects + template().Type() )> + ENABLE_IF( IS_SERIAL_TYPE(Member) && IS_ABSTRACT, IArchive&) + operator<<(TSerialParameter rParam) + { + PushParameter(rParam); + + if (ShouldSerializeParameter(rParam) && + ParamBegin(rParam.pkName, rParam.HintFlags)) + { + if (PreSerializePointer( (void*&) rParam.rValue, rParam.HintFlags )) + { + // Non-reader archives cannot instantiate the class. It must exist already. + if (IsWriter()) + { + ObjectType Type = rParam.rValue->Type(); + *this << SerialParameter("Type", Type, SH_Attribute); + } + else + { + // NOTE: If you crash here, it likely means that the pointer was initialized to a garbage value. + // It is legal to serialize a pointer that already exists, so you still need to initialize it. + ObjectType Type = (rParam.rValue ? rParam.rValue->Type() : ObjectType()); + ObjectType TypeCopy = Type; + *this << SerialParameter("Type", Type, SH_Attribute); + + if (IsReader() && rParam.rValue == nullptr) + { + rParam.rValue = InstantiateAbstractObject(rParam, Type); + } + else if (rParam.rValue != nullptr) + { + // Make sure the type is what we are expecting + ASSERT(Type == TypeCopy); + } + } + + // At this point, the object should exist and is ready for serializing. + if (rParam.rValue) + { + rParam.rValue->Serialize(*this); + } + } + else if (IsReader()) + rParam.rValue = nullptr; + + ParamEnd(); + } + else + { + // Polymorphic types don't support default values + } + + PopParameter(rParam); + return *this; + } + + // Error + template + ENABLE_IF( IS_SERIAL_TYPE(Global) && IS_ABSTRACT, IArchive& ) + operator<<(TSerialParameter) + { + static_assert(false, "Global Serialize method for polymorphic type pointers is not supported."); + } + // Generate compiler errors for classes with no valid Serialize function defined - template - inline IArchive& operator<<(TSerialParameter) + template + ENABLE_IF( IS_SERIAL_TYPE(None), IArchive& ) + operator<<(TSerialParameter) { static_assert(false, "Object being serialized has no valid Serialize method defined."); } - template - inline IArchive& operator<<(TAbstractSerialParameter) - { - static_assert(false, "Abstract object being serialized must have a virtual Serialize method defined."); - } - - template - inline IArchive& operator<<(TContainerSerialParameter) - { - static_assert(false, "Container being serialized has no valid Serialize method defined."); - } - - template - inline IArchive& operator<<(TAbstractContainerSerialParameter) - { - static_assert(false, "Container being serialized has no valid Serialize method defined."); - } - // Interface - virtual bool ParamBegin(const char *pkName) = 0; + virtual bool ParamBegin(const char *pkName, u32 Flags) = 0; virtual void ParamEnd() = 0; - virtual void SerializeContainerSize(u32& rSize, const TString& rkElemName) = 0; - virtual void SerializeAbstractObjectType(u32& rType) = 0; + virtual bool PreSerializePointer(void*& Pointer, u32 Flags) = 0; + virtual void SerializePrimitive(bool& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(char& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(s8& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(u8& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(s16& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(u16& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(s32& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(u32& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(s64& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(u64& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(float& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(double& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(TString& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(TWideString& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(CFourCC& rValue, u32 Flags) = 0; + virtual void SerializePrimitive(CAssetID& rValue, u32 Flags) = 0; + virtual void SerializeBulkData(void* pData, u32 DataSize, u32 Flags) = 0; - virtual void SerializePrimitive(bool& rValue) = 0; - virtual void SerializePrimitive(char& rValue) = 0; - virtual void SerializePrimitive(s8& rValue) = 0; - virtual void SerializePrimitive(u8& rValue) = 0; - virtual void SerializePrimitive(s16& rValue) = 0; - virtual void SerializePrimitive(u16& rValue) = 0; - virtual void SerializePrimitive(s32& rValue) = 0; - virtual void SerializePrimitive(u32& rValue) = 0; - virtual void SerializePrimitive(s64& rValue) = 0; - virtual void SerializePrimitive(u64& rValue) = 0; - virtual void SerializePrimitive(float& rValue) = 0; - virtual void SerializePrimitive(double& rValue) = 0; - virtual void SerializePrimitive(TString& rValue) = 0; - virtual void SerializePrimitive(TWideString& rValue) = 0; - virtual void SerializePrimitive(CFourCC& rValue) = 0; - virtual void SerializePrimitive(CAssetID& rValue) = 0; - - virtual void SerializeHexPrimitive(u8& rValue) = 0; - virtual void SerializeHexPrimitive(u16& rValue) = 0; - virtual void SerializeHexPrimitive(u32& rValue) = 0; - virtual void SerializeHexPrimitive(u64& rValue) = 0; - - virtual void BulkSerialize(void* pData, u32 DataSize) = 0; - - void SerializeBulkData(std::vector& InArray) + // Optional - serialize in an array size. By default, just stores size as an attribute property. + virtual void SerializeArraySize(u32& Value) { - u32 Size = InArray.size(); - SerializeContainerSize(Size, "Size"); - - if (IsReader()) - { - InArray.resize(Size); - } - - BulkSerialize(InArray.data(), Size); + *this << SerialParameter("Size", Value, SH_Attribute); } - // Meta - virtual bool IsReader() const = 0; - virtual bool IsWriter() const = 0; - virtual bool IsTextFormat() const = 0; - // Accessors + inline bool IsReader() const { return (mArchiveFlags & AF_Reader) != 0; } + inline bool IsWriter() const { return (mArchiveFlags & AF_Writer) != 0; } + inline bool IsTextFormat() const { return (mArchiveFlags & AF_Text) != 0; } + inline bool IsBinaryFormat() const { return (mArchiveFlags & AF_Binary) != 0; } + inline u16 ArchiveVersion() const { return mArchiveVersion; } inline u16 FileVersion() const { return mFileVersion; } inline EGame Game() const { return mGame; } @@ -443,8 +644,27 @@ public: { return CSerialVersion(mArchiveVersion, mFileVersion, mGame); } + + /** Returns the last object of a requested type in the parameter stack. Returns nullptr if the wasn't one. + * This function will not return the current object being serialized. */ + template + ValType* FindParentObject() const + { + for (int ParmIdx = mParmStack.size() - 2; ParmIdx >= 0; ParmIdx--) + { + const SParmStackEntry& kEntry = mParmStack[ParmIdx]; + + if (kEntry.TypeID == typeid(ValType).hash_code()) + { + return static_cast(kEntry.pDataPointer); + } + } + + return nullptr; + } }; +#if WITH_CODEGEN // Default enum serializer; can be overridden #include @@ -456,212 +676,179 @@ inline void Serialize(IArchive& Arc, T& Val) if (Arc.IsReader()) { TString ValueName; - Arc.SerializePrimitive(ValueName); + Arc.SerializePrimitive(ValueName, 0); Val = TEnumReflection::ConvertStringToValue( *ValueName ); } else { TString ValueName = TEnumReflection::ConvertValueToString(Val); - Arc.SerializePrimitive(ValueName); + Arc.SerializePrimitive(ValueName, 0); } } else { - Arc.SerializePrimitive((u32&) Val); + Arc.SerializePrimitive((u32&) Val, 0); + } +} +#endif + +// Container serialize methods + +// std::vector +template +inline void Serialize(IArchive& Arc, std::vector& Vector) +{ + u32 Size = Vector.size(); + Arc.SerializeArraySize(Size); + + if (Arc.IsReader()) + { + Vector.resize(Size); + } + + for (u32 i = 0; i < Size; i++) + { + // SH_IgnoreName to preserve compatibility with older files that may have differently-named items + Arc << SerialParameter("Item", Vector[i], SH_IgnoreName); } } -// Container serialize methods -#include -#include -#include -#include - -template -inline void SerializeContainerSize(IArchive& rArc, Container& rContainer, const TString& rkElemName) +// overload for std::vector that serializes in bulk +template<> +inline void Serialize(IArchive& Arc, std::vector& Vector) { - u32 Size = rContainer.size(); - rArc.SerializeContainerSize(Size, rkElemName); - if (rArc.IsReader()) rContainer.resize(Size); -} + // Don't use SerializeArraySize, bulk data is a special case that overloads may not handle correctly + u32 Size = Vector.size(); + Arc << SerialParameter("Size", Size, SH_Attribute); -// std::vector -template -inline void SerializeContainer(IArchive& rArc, std::vector& rVec, const TString& rkElemName = "Item") -{ - SerializeContainerSize(rArc, rVec, rkElemName); + if (Arc.IsReader()) + { + Vector.resize(Size); + } - for (u32 iElem = 0; iElem < rVec.size(); iElem++) - rArc << SERIAL(*rkElemName, rVec[iElem]); -} - -template -inline void SerializeContainer(IArchive& rArc, std::vector& rVec, const TString& rkElemName, FactoryType *pFactory) -{ - SerializeContainerSize(rArc, rVec, rkElemName); - - for (u32 iElem = 0; iElem < rVec.size(); iElem++) - rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory); + Arc.SerializeBulkData(Vector.data(), Vector.size(), 0); } // std::list -template -inline void SerializeContainer(IArchive& rArc, std::list& rList, const TString& rkElemName) +template +inline void Serialize(IArchive& Arc, std::list& List) { - SerializeContainerSize(rArc, rList, rkElemName); + u32 Size = List.size(); + Arc.SerializeArraySize(Size); - for (auto Iter = rList.begin(); Iter != rList.end(); Iter++) - rArc << SERIAL(*rkElemName, *Iter); -} + if (Arc.IsReader()) + { + List.resize(Size); + } -template -inline void SerializeContainer(IArchive& rArc, std::list& rList, const TString& rkElemName, FactoryType *pFactory) -{ - SerializeContainerSize(rArc, rList, rkElemName); - - for (auto Iter = rList.begin(); Iter != rList.end(); Iter++) - rArc << SERIAL_ABSTRACT(*rkElemName, rVec[iElem], pFactory); + for (auto Iter = List.begin(); Iter != List.end(); Iter++) + Arc << SerialParameter("Item", *Iter, SH_IgnoreName); } // Overload for TStringList and TWideStringList so they can use the TString/TWideString serialize functions -inline void SerializeContainer(IArchive& rArc, TStringList& rList, const TString& rkElemName) +inline void Serialize(IArchive& Arc, TStringList& List) { - typedef std::list ListType; - ListType& rGenericList = *reinterpret_cast(&rList); - SerializeContainer(rArc, rGenericList, rkElemName); + std::list& GenericList = *reinterpret_cast< std::list* >(&List); + Serialize(Arc, GenericList); } -inline void SerializeContainer(IArchive& rArc, TWideStringList& rList, const TString& rkElemName) +inline void Serialize(IArchive& Arc, TWideStringList& List) { - typedef std::list ListType; - ListType& rGenericList = *reinterpret_cast(&rList); - SerializeContainer(rArc, rGenericList, rkElemName); + std::list& GenericList = *reinterpret_cast< std::list* >(&List); + Serialize(Arc, GenericList); } // std::set -template -inline void SerializeContainer(IArchive& rArc, std::set& rSet, const TString& rkElemName) +template +inline void Serialize(IArchive& Arc, std::set& Set) { - u32 Size = rSet.size(); - rArc.SerializeContainerSize(Size, rkElemName); + u32 Size = Set.size(); + Arc.SerializeArraySize(Size); - if (rArc.IsReader()) + if (Arc.IsReader()) { - for (u32 iElem = 0; iElem < Size; iElem++) + for (u32 i = 0; i < Size; i++) { - ValType Val; - rArc << SERIAL(*rkElemName, Val); - rSet.insert(Val); + T Val; + Arc << SerialParameter("Item", Val, SH_IgnoreName); + Set.insert(Val); } } else { - for (auto Iter = rSet.begin(); Iter != rSet.end(); Iter++) + for (auto Iter = Set.begin(); Iter != Set.end(); Iter++) { - ValType Val = *Iter; - rArc << SERIAL(*rkElemName, Val); + T Val = *Iter; + Arc << SerialParameter("Item", Val, SH_IgnoreName); } } } -template -inline void SerializeContainer(IArchive& rArc, std::set& rSet, const TString& rkElemName, FactoryType *pFactory) +// std::map and std::unordered_map +template +inline void SerializeMap_Internal(IArchive& Arc, MapType& Map) { - u32 Size = rSet.size(); - rArc.SerializeContainerSize(Size, rkElemName); + u32 Size = Map.size(); + Arc.SerializeArraySize(Size); - if (rArc.IsReader()) + if (Arc.IsReader()) { - for (u32 iElem = 0; iElem < Size; iElem++) + for (u32 i = 0; i < Size; i++) { + KeyType Key; ValType Val; - rArc << SERIAL_ABSTRACT(*rkElemName, Val, pFactory); - rSet.insert(Val); + + if (Arc.ParamBegin("Item", SH_IgnoreName)) + { + Arc << SerialParameter("Key", Key, SH_IgnoreName) + << SerialParameter("Value", Val, SH_IgnoreName); + + ASSERT(Map.find(Key) == Map.end()); + Map[Key] = Val; + Arc.ParamEnd(); + } } } else { - for (auto Iter = rSet.begin(); Iter != rSet.end(); Iter++) + for (auto Iter = Map.begin(); Iter != Map.end(); Iter++) { - ValType Val = *Iter; - rArc << SERIAL_ABSTRACT(*rkElemName, Val, pFactory); + // Creating copies is not ideal, but necessary because parameters cannot be const. + // Maybe this can be avoided somehow? + KeyType Key = Iter->first; + ValType Val = Iter->second; + + if (Arc.ParamBegin("Item", SH_IgnoreName)) + { + Arc << SerialParameter("Key", Key, SH_IgnoreName) + << SerialParameter("Value", Val, SH_IgnoreName); + + Arc.ParamEnd(); + } } } } -// std::map template -inline void SerializeContainer(IArchive& rArc, std::map& rMap, const TString& rkElemName) +inline void Serialize(IArchive& Arc, std::map& Map) { - u32 Size = rMap.size(); - rArc.SerializeContainerSize(Size, rkElemName); - - if (rArc.IsReader()) - { - for (u32 iElem = 0; iElem < Size; iElem++) - { - KeyType Key; - ValType Val; - - rArc.ParamBegin(*rkElemName); - rArc << SERIAL("Key", Key) << SERIAL("Value", Val); - rArc.ParamEnd(); - - ASSERT(rMap.find(Key) == rMap.end()); - rMap[Key] = Val; - } - } - - else - { - for (auto Iter = rMap.begin(); Iter != rMap.end(); Iter++) - { - KeyType Key = Iter->first; - ValType Val = Iter->second; - - rArc.ParamBegin(*rkElemName); - rArc << SERIAL("Key", Key) << SERIAL("Value", Val); - rArc.ParamEnd(); - } - } + SerializeMap_Internal >(Arc, Map); } -template -inline void SerializeContainer(IArchive& rArc, std::map& rMap, const TString& rkElemName, FactoryType *pFactory) +template +inline void Serialize(IArchive& Arc, std::unordered_map& Map) { - u32 Size = rMap.size(); - rArc.SerializeContainerSize(Size, rkElemName); - - if (rArc.IsReader()) - { - for (u32 iElem = 0; iElem < Size; iElem++) - { - KeyType Key; - ValType Val; - - rArc.ParamBegin(*rkElemName); - rArc << SERIAL_ABSTRACT("Key", Key, pFactory) << SERIAL("Value", Val); - rArc.ParamEnd(); - - ASSERT(rMap.find(Key) == rMap.end()); - rMap[Key] = Val; - } - } - - else - { - for (auto Iter = rMap.begin(); Iter != rMap.end(); Iter++) - { - KeyType Key = Iter->first; - ValType Val = Iter->second; - - rArc.ParamBegin(*rkElemName); - rArc << SERIAL("Key", Key) << SERIAL("Value", Val); - rArc.ParamEnd(); - } - } + SerializeMap_Internal >(Arc, Map); } +// Remove header-only macros +#undef ENABLE_IF +#undef SUPPORTS_DEFAULT_VALUES +#undef IS_ABSTRACT +#undef IS_SERIAL_TYPE +#undef IS_ARCHIVE_CONSTRUCTOR_TYPE +#undef ABSTRACT_TYPE + #endif // IARCHIVE diff --git a/src/Common/TString.cpp b/src/Common/TString.cpp index 490954f7..6fc2f9f5 100644 --- a/src/Common/TString.cpp +++ b/src/Common/TString.cpp @@ -1,7 +1,7 @@ #include "TString.h" #include "Hash/CCRC32.h" #include "Hash/CFNV1A.h" -#include +#include "FileIO/IOUtil.h" #include #include diff --git a/src/Common/TString.h b/src/Common/TString.h index cb8b5bbb..cc08fc50 100644 --- a/src/Common/TString.h +++ b/src/Common/TString.h @@ -930,14 +930,9 @@ public: return SStream.str(); } - static _TString FromFloat(float Value, int MinDecimals = 1) + static _TString FromFloat(float Value, int MinDecimals = 1, bool Scientific = false) { - // Initial float -> string conversion - std::basic_stringstream SStream; - if (MinDecimals > 0) SStream.setf(std::ios_base::showpoint); - SStream.setf(std::ios_base::fixed, std::ios_base::floatfield); - SStream << Value; - _TString Out = SStream.str(); + _TString Out = _TString::Format(Scientific ? "%.8g" : "%f", Value); // Make sure we have the right number of decimals int DecIdx = Out.IndexOf(CHAR_LITERAL('.')); @@ -954,7 +949,7 @@ public: if (NumZeroes < MinDecimals) { for (int iDec = 0; iDec < (MinDecimals - NumZeroes); iDec++) - Out.Append(CHAR_LITERAL('.')); + Out.Append(CHAR_LITERAL('0')); } // Remove unnecessary trailing zeroes from the end of the string diff --git a/src/Core/GameProject/CAssetNameMap.cpp b/src/Core/GameProject/CAssetNameMap.cpp index 8ba78322..26aa5fd3 100644 --- a/src/Core/GameProject/CAssetNameMap.cpp +++ b/src/Core/GameProject/CAssetNameMap.cpp @@ -133,7 +133,7 @@ void CAssetNameMap::CopyFromStore(CResourceStore *pStore /*= gpResourceStore*/) // ************ PRIVATE ************ void CAssetNameMap::Serialize(IArchive& rArc) { - rArc << SERIAL_CONTAINER("AssetNameMap", mMap, "Asset"); + rArc << SerialParameter("AssetNameMap", mMap); if (rArc.IsReader()) PostLoadValidate(); diff --git a/src/Core/GameProject/CAssetNameMap.h b/src/Core/GameProject/CAssetNameMap.h index 6257e8f4..b516226b 100644 --- a/src/Core/GameProject/CAssetNameMap.h +++ b/src/Core/GameProject/CAssetNameMap.h @@ -28,7 +28,11 @@ class CAssetNameMap void Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(Name) << SERIAL_AUTO(Directory) << SERIAL_AUTO(Type) << SERIAL_AUTO(AutoGenName) << SERIAL_AUTO(AutoGenDir); + rArc << SerialParameter("Name", Name) + << SerialParameter("Directory", Directory) + << SerialParameter("Type", Type) + << SerialParameter("AutoGenName", AutoGenName) + << SerialParameter("AutoGenDir", AutoGenDir); } bool operator<(const SAssetNameInfo& rkOther) const diff --git a/src/Core/GameProject/CDependencyTree.cpp b/src/Core/GameProject/CDependencyTree.cpp index 69aed359..48098183 100644 --- a/src/Core/GameProject/CDependencyTree.cpp +++ b/src/Core/GameProject/CDependencyTree.cpp @@ -5,8 +5,6 @@ #include "Core/Resource/Script/CScriptLayer.h" #include "Core/Resource/Script/CScriptObject.h" -CDependencyNodeFactory gDependencyNodeFactory; - // ************ IDependencyNode ************ IDependencyNode::~IDependencyNode() { @@ -31,6 +29,24 @@ void IDependencyNode::GetAllResourceReferences(std::set& rOutSet) cons mChildren[iChild]->GetAllResourceReferences(rOutSet); } +// Serialization constructor +IDependencyNode* IDependencyNode::ArchiveConstructor(EDependencyNodeType Type) +{ + switch (Type) + { + case eDNT_DependencyTree: return new CDependencyTree; + case eDNT_ResourceDependency: return new CResourceDependency; + case eDNT_ScriptInstance: return new CScriptInstanceDependency; + case eDNT_ScriptProperty: return new CPropertyDependency; + case eDNT_CharacterProperty: return new CCharPropertyDependency; + case eDNT_SetCharacter: return new CSetCharacterDependency; + case eDNT_SetAnimation: return new CSetAnimationDependency; + case eDNT_AnimEvent: return new CAnimEventDependency; + case eDNT_Area: return new CAreaDependencyTree; + default: ASSERT(false); return nullptr; + } +} + // ************ CDependencyTree ************ EDependencyNodeType CDependencyTree::Type() const { @@ -39,7 +55,7 @@ EDependencyNodeType CDependencyTree::Type() const void CDependencyTree::Serialize(IArchive& rArc) { - rArc << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory); + rArc << SerialParameter("Children", mChildren); } void CDependencyTree::AddChild(IDependencyNode *pNode) @@ -78,7 +94,7 @@ EDependencyNodeType CResourceDependency::Type() const void CResourceDependency::Serialize(IArchive& rArc) { - rArc << SERIAL("ID", mID); + rArc << SerialParameter("ID", mID); } void CResourceDependency::GetAllResourceReferences(std::set& rOutSet) const @@ -99,7 +115,7 @@ EDependencyNodeType CPropertyDependency::Type() const void CPropertyDependency::Serialize(IArchive& rArc) { - rArc << SERIAL("PropertyID", mIDString); + rArc << SerialParameter("PropertyID", mIDString); CResourceDependency::Serialize(rArc); } @@ -112,7 +128,7 @@ EDependencyNodeType CCharPropertyDependency::Type() const void CCharPropertyDependency::Serialize(IArchive& rArc) { CPropertyDependency::Serialize(rArc); - rArc << SERIAL("CharIndex", mUsedChar); + rArc << SerialParameter("CharIndex", mUsedChar); } // ************ CScriptInstanceDependency ************ @@ -123,8 +139,8 @@ EDependencyNodeType CScriptInstanceDependency::Type() const void CScriptInstanceDependency::Serialize(IArchive& rArc) { - rArc << SERIAL("ObjectType", mObjectType) - << SERIAL_ABSTRACT_CONTAINER("Properties", mChildren, "Property", &gDependencyNodeFactory); + rArc << SerialParameter("ObjectType", mObjectType) + << SerialParameter("Properties", mChildren); } // Static @@ -210,8 +226,8 @@ EDependencyNodeType CSetCharacterDependency::Type() const void CSetCharacterDependency::Serialize(IArchive& rArc) { - rArc << SERIAL("CharSetIndex", mCharSetIndex) - << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory); + rArc << SerialParameter("CharSetIndex", mCharSetIndex) + << SerialParameter("Children", mChildren); } CSetCharacterDependency* CSetCharacterDependency::BuildTree(const SSetCharacter& rkChar) @@ -255,8 +271,8 @@ EDependencyNodeType CSetAnimationDependency::Type() const void CSetAnimationDependency::Serialize(IArchive& rArc) { - rArc << SERIAL_CONTAINER("CharacterIndices", mCharacterIndices, "Index") - << SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory); + rArc << SerialParameter("CharacterIndices", mCharacterIndices) + << SerialParameter("Children", mChildren); } CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 AnimIndex) @@ -302,7 +318,7 @@ EDependencyNodeType CAnimEventDependency::Type() const void CAnimEventDependency::Serialize(IArchive& rArc) { CResourceDependency::Serialize(rArc); - rArc << SERIAL("CharacterIndex", mCharIndex); + rArc << SerialParameter("CharacterIndex", mCharIndex); } // ************ CAreaDependencyTree ************ @@ -314,7 +330,7 @@ EDependencyNodeType CAreaDependencyTree::Type() const void CAreaDependencyTree::Serialize(IArchive& rArc) { CDependencyTree::Serialize(rArc); - rArc << SERIAL_CONTAINER("LayerOffsets", mLayerOffsets, "Offset"); + rArc << SerialParameter("LayerOffsets", mLayerOffsets); } void CAreaDependencyTree::AddScriptLayer(CScriptLayer *pLayer, const std::vector& rkExtraDeps) diff --git a/src/Core/GameProject/CDependencyTree.h b/src/Core/GameProject/CDependencyTree.h index ade2088c..1d688121 100644 --- a/src/Core/GameProject/CDependencyTree.h +++ b/src/Core/GameProject/CDependencyTree.h @@ -40,6 +40,9 @@ public: virtual void GetAllResourceReferences(std::set& rOutSet) const; virtual bool HasDependency(const CAssetID& rkID) const; + // Serialization constructor + static IDependencyNode* ArchiveConstructor(EDependencyNodeType Type); + // Accessors inline u32 NumChildren() const { return mChildren.size(); } inline IDependencyNode* ChildByIndex(u32 Index) const { return mChildren[Index]; } @@ -223,28 +226,5 @@ public: inline u32 ScriptLayerOffset(u32 LayerIdx) const { return mLayerOffsets[LayerIdx]; } }; -// Dependency node factory for serialization -class CDependencyNodeFactory -{ -public: - IDependencyNode* SpawnObject(u32 NodeID) - { - switch (NodeID) - { - case eDNT_DependencyTree: return new CDependencyTree; - case eDNT_ResourceDependency: return new CResourceDependency; - case eDNT_ScriptInstance: return new CScriptInstanceDependency; - case eDNT_ScriptProperty: return new CPropertyDependency; - case eDNT_CharacterProperty: return new CCharPropertyDependency; - case eDNT_SetCharacter: return new CSetCharacterDependency; - case eDNT_SetAnimation: return new CSetAnimationDependency; - case eDNT_AnimEvent: return new CAnimEventDependency; - case eDNT_Area: return new CAreaDependencyTree; - default: ASSERT(false); return nullptr; - } - } -}; -extern CDependencyNodeFactory gDependencyNodeFactory; - #endif // CDEPENDENCYTREE diff --git a/src/Core/GameProject/CGameInfo.cpp b/src/Core/GameProject/CGameInfo.cpp index 8a80b3e2..2aa069d0 100644 --- a/src/Core/GameProject/CGameInfo.cpp +++ b/src/Core/GameProject/CGameInfo.cpp @@ -41,10 +41,10 @@ void CGameInfo::Serialize(IArchive& rArc) } // Serialize data - rArc << SERIAL_CONTAINER("GameBuilds", mBuilds, "Build"); + rArc << SerialParameter("GameBuilds", mBuilds); if (mGame <= ePrime) - rArc << SERIAL_CONTAINER("AreaNameMap", mAreaNameMap, "AreaName"); + rArc << SerialParameter("AreaNameMap", mAreaNameMap); } TString CGameInfo::GetBuildName(float BuildVer, ERegion Region) const diff --git a/src/Core/GameProject/CGameInfo.h b/src/Core/GameProject/CGameInfo.h index 16cab5bc..91290fc6 100644 --- a/src/Core/GameProject/CGameInfo.h +++ b/src/Core/GameProject/CGameInfo.h @@ -24,7 +24,9 @@ class CGameInfo void Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(Version) << SERIAL_AUTO(Region) << SERIAL_AUTO(Name); + rArc << SerialParameter("Version", Version) + << SerialParameter("Region", Region) + << SerialParameter("Name", Name); } }; std::vector mBuilds; diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index cb08bbda..66114a91 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -36,10 +36,10 @@ bool CGameProject::Save() bool CGameProject::Serialize(IArchive& rArc) { - rArc << SERIAL("Name", mProjectName) - << SERIAL("Region", mRegion) - << SERIAL("GameID", mGameID) - << SERIAL("BuildVersion", mBuildVersion); + rArc << SerialParameter("Name", mProjectName) + << SerialParameter("Region", mRegion) + << SerialParameter("GameID", mGameID) + << SerialParameter("BuildVersion", mBuildVersion); // Serialize package list std::vector PackageList; @@ -50,7 +50,7 @@ bool CGameProject::Serialize(IArchive& rArc) PackageList.push_back( mPackages[iPkg]->DefinitionPath(true) ); } - rArc << SERIAL_CONTAINER("Packages", PackageList, "Package"); + rArc << SerialParameter("Packages", PackageList); // Load packages if (rArc.IsReader()) diff --git a/src/Core/GameProject/CPackage.cpp b/src/Core/GameProject/CPackage.cpp index 56e08013..11beca0c 100644 --- a/src/Core/GameProject/CPackage.cpp +++ b/src/Core/GameProject/CPackage.cpp @@ -36,8 +36,8 @@ bool CPackage::Save() void CPackage::Serialize(IArchive& rArc) { - rArc << SERIAL("NeedsRecook", mNeedsRecook) - << SERIAL_CONTAINER("NamedResources", mResources, "Resource"); + rArc << SerialParameter("NeedsRecook", mNeedsRecook) + << SerialParameter("NamedResources", mResources); } void CPackage::AddResource(const TString& rkName, const CAssetID& rkID, const CFourCC& rkType) diff --git a/src/Core/GameProject/CPackage.h b/src/Core/GameProject/CPackage.h index 5884e144..20458f7a 100644 --- a/src/Core/GameProject/CPackage.h +++ b/src/Core/GameProject/CPackage.h @@ -17,7 +17,9 @@ struct SNamedResource void Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(Name) << SERIAL_AUTO(ID) << SERIAL_AUTO(Type); + rArc << SerialParameter("Name", Name) + << SerialParameter("ID", ID) + << SerialParameter("Type", Type); } }; diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index 2008515c..31d0ec44 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -127,9 +127,9 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly) { CAssetID ID = mID; - rArc << SERIAL("AssetID", ID) - << SERIAL("Type", mpTypeInfo) - << SERIAL("Flags", mFlags); + rArc << SerialParameter("AssetID", ID) + << SerialParameter("Type", mpTypeInfo) + << SerialParameter("Flags", mFlags); // Don't allow the file to override our asset ID if we already have a valid one. if (rArc.IsReader() && !mID.IsValid()) @@ -140,9 +140,9 @@ void CResourceEntry::SerializeEntryInfo(IArchive& rArc, bool MetadataOnly) { TString Dir = (mpDirectory ? mpDirectory->FullPath() : ""); - rArc << SERIAL("Name", mName) - << SERIAL("Directory", Dir) - << SERIAL_ABSTRACT("Dependencies", mpDependencies, &gDependencyNodeFactory); + rArc << SerialParameter("Name", mName) + << SerialParameter("Directory", Dir) + << SerialParameter("Dependencies", mpDependencies); if (rArc.IsReader()) { diff --git a/src/Core/GameProject/CResourceStore.cpp b/src/Core/GameProject/CResourceStore.cpp index f30f34cc..0541b3d6 100644 --- a/src/Core/GameProject/CResourceStore.cpp +++ b/src/Core/GameProject/CResourceStore.cpp @@ -62,17 +62,17 @@ void RecursiveGetListOfEmptyDirectories(CVirtualDirectory *pDir, TStringList& rO bool CResourceStore::SerializeDatabaseCache(IArchive& rArc) { // Serialize resources - if (rArc.ParamBegin("Resources")) + if (rArc.ParamBegin("Resources", 0)) { // Serialize resources u32 ResourceCount = mResourceEntries.size(); - rArc << SERIAL_AUTO(ResourceCount); + rArc << SerialParameter("ResourceCount", ResourceCount); if (rArc.IsReader()) { for (u32 ResIdx = 0; ResIdx < ResourceCount; ResIdx++) { - if (rArc.ParamBegin("Resource")) + if (rArc.ParamBegin("Resource", 0)) { CResourceEntry *pEntry = CResourceEntry::BuildFromArchive(this, rArc); ASSERT( FindEntry(pEntry->ID()) == nullptr ); @@ -85,7 +85,7 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc) { for (CResourceIterator It(this); It; ++It) { - if (rArc.ParamBegin("Resource")) + if (rArc.ParamBegin("Resource", 0)) { It->SerializeEntryInfo(rArc, false); rArc.ParamEnd(); @@ -101,7 +101,7 @@ bool CResourceStore::SerializeDatabaseCache(IArchive& rArc) if (!rArc.IsReader()) RecursiveGetListOfEmptyDirectories(mpDatabaseRoot, EmptyDirectories); - rArc << SERIAL_CONTAINER_AUTO(EmptyDirectories, "Directory"); + rArc << SerialParameter("EmptyDirectories", EmptyDirectories); if (rArc.IsReader()) { diff --git a/src/Core/Resource/Animation/CAnimationParameters.cpp b/src/Core/Resource/Animation/CAnimationParameters.cpp index 7a61ffab..e42da96f 100644 --- a/src/Core/Resource/Animation/CAnimationParameters.cpp +++ b/src/Core/Resource/Animation/CAnimationParameters.cpp @@ -15,6 +15,7 @@ CAnimationParameters::CAnimationParameters() CAnimationParameters::CAnimationParameters(EGame Game) : mGame(Game) + , mCharacterID( CAssetID::InvalidID(Game) ) , mCharIndex(0) , mAnimIndex(0) , mUnknown2(0) @@ -141,17 +142,17 @@ void CAnimationParameters::Serialize(IArchive& rArc) if (rArc.IsReader()) mGame = rArc.Game(); - rArc << SERIAL("AnimationSetAsset", mCharacterID); + rArc << SerialParameter("AnimationSetAsset", mCharacterID); if (mGame <= eEchoes) - rArc << SERIAL("CharacterID", mCharIndex); + rArc << SerialParameter("CharacterID", mCharIndex); - rArc << SERIAL("AnimationID", mAnimIndex); + rArc << SerialParameter("AnimationID", mAnimIndex); if (mGame >= eReturns) { - rArc << SERIAL("Unknown0", mUnknown2) - << SERIAL("Unknown1", mUnknown3); + rArc << SerialParameter("Unknown0", mUnknown2) + << SerialParameter("Unknown1", mUnknown3); } } diff --git a/src/Core/Resource/Animation/CAnimationParameters.h b/src/Core/Resource/Animation/CAnimationParameters.h index 71e1086d..f4687f5b 100644 --- a/src/Core/Resource/Animation/CAnimationParameters.h +++ b/src/Core/Resource/Animation/CAnimationParameters.h @@ -35,11 +35,36 @@ public: inline void SetCharIndex(u32 Index) { mCharIndex = Index; } inline void SetAnimIndex(u32 Index) { mAnimIndex = Index; } + inline void SetGame(EGame Game) + { + mGame = Game; + + if (!mCharacterID.IsValid()) + { + mCharacterID = CAssetID::InvalidID(mGame); + } + else + { + ASSERT( mCharacterID.Length() == CAssetID::GameIDLength(mGame) ); + } + } + u32 Unknown(u32 Index); void SetResource(const CAssetID& rkID); void SetUnknown(u32 Index, u32 Value); // Operators + inline CAnimationParameters& operator=(const CAnimationParameters& rkOther) + { + mGame = rkOther.mGame; + mCharacterID = rkOther.mCharacterID; + mCharIndex = rkOther.mCharIndex; + mAnimIndex = rkOther.mAnimIndex; + mUnknown2 = rkOther.mUnknown2; + mUnknown3 = rkOther.mUnknown3; + return *this; + } + inline bool operator==(const CAnimationParameters& rkOther) const { return ( (mGame == rkOther.mGame) && diff --git a/src/Core/Resource/CResTypeFilter.h b/src/Core/Resource/CResTypeFilter.h index 52ae96b2..2f259ac4 100644 --- a/src/Core/Resource/CResTypeFilter.h +++ b/src/Core/Resource/CResTypeFilter.h @@ -50,7 +50,7 @@ public: void Serialize(IArchive& rArc) { if (rArc.IsReader()) mGame = rArc.Game(); - rArc << SERIAL_CONTAINER("AcceptedTypes", mAcceptedTypes, "Type"); + rArc << SerialParameter("AcceptedTypes", mAcceptedTypes); } inline bool Accepts(EResType Type) const diff --git a/src/Core/Resource/CResTypeInfo.cpp b/src/Core/Resource/CResTypeInfo.cpp index 60c4c0be..bf28fa32 100644 --- a/src/Core/Resource/CResTypeInfo.cpp +++ b/src/Core/Resource/CResTypeInfo.cpp @@ -114,7 +114,7 @@ void Serialize(IArchive& rArc, CResTypeInfo*& rpType) Ext = rpType->CookedExtension(rArc.Game()); } - rArc.SerializePrimitive(Ext); + rArc.SerializePrimitive(Ext, 0); if (rArc.IsReader()) { @@ -134,7 +134,7 @@ void Serialize(IArchive& rArc, EResType& rType) Extension = pTypeInfo->CookedExtension(rArc.Game()); } - rArc.SerializePrimitive(Extension); + rArc.SerializePrimitive(Extension, 0); if (rArc.IsReader()) { diff --git a/src/Core/Resource/CSavedStateID.h b/src/Core/Resource/CSavedStateID.h index e18ad976..5cfed855 100644 --- a/src/Core/Resource/CSavedStateID.h +++ b/src/Core/Resource/CSavedStateID.h @@ -46,10 +46,18 @@ public: void Serialize(IArchive& rArc) { - TString Str; - if (rArc.IsWriter()) Str = ToString(); - rArc.SerializePrimitive(Str); - if (rArc.IsReader()) *this = FromString(Str); + if (rArc.IsBinaryFormat()) + { + rArc.SerializePrimitive(m[0], 0); + rArc.SerializePrimitive(m[1], 0); + } + else + { + TString Str; + if (rArc.IsWriter()) Str = ToString(); + rArc.SerializePrimitive(Str, 0); + if (rArc.IsReader()) *this = FromString(Str); + } } // Operators diff --git a/src/Core/Resource/CWorld.cpp b/src/Core/Resource/CWorld.cpp index ac411549..e77afd8d 100644 --- a/src/Core/Resource/CWorld.cpp +++ b/src/Core/Resource/CWorld.cpp @@ -92,87 +92,87 @@ u32 CWorld::AreaIndex(CAssetID AreaID) const // ************ SERIALIZATION ************ void CWorld::Serialize(IArchive& rArc) { - rArc << SERIAL("Name", mName) - << SERIAL("NameString", mpWorldName); + rArc << SerialParameter("Name", mName) + << SerialParameter("NameString", mpWorldName); if (rArc.Game() == eEchoesDemo || rArc.Game() == eEchoes) - rArc << SERIAL("DarkNameString", mpDarkWorldName); + rArc << SerialParameter("DarkNameString", mpDarkWorldName); - rArc << SERIAL("WorldSaveInfo", mpSaveWorld) - << SERIAL("WorldMap", mpMapWorld) - << SERIAL("DefaultSkyModel", mpDefaultSkybox); + rArc << SerialParameter("WorldSaveInfo", mpSaveWorld) + << SerialParameter("WorldMap", mpMapWorld) + << SerialParameter("DefaultSkyModel", mpDefaultSkybox); if (rArc.Game() >= eEchoesDemo && rArc.Game() <= eCorruption) - rArc << SERIAL("TempleKeyWorldIndex", mTempleKeyWorldIndex); + rArc << SerialParameter("TempleKeyWorldIndex", mTempleKeyWorldIndex); if (rArc.Game() == eReturns) - rArc << SERIAL("TimeAttackData", mTimeAttackData); + rArc << SerialParameter("TimeAttackData", mTimeAttackData); if (rArc.Game() == ePrime) - rArc << SERIAL_CONTAINER("MemoryRelays", mMemoryRelays, "MemoryRelay"); + rArc << SerialParameter("MemoryRelays", mMemoryRelays); - rArc << SERIAL_CONTAINER("Areas", mAreas, "Area"); + rArc << SerialParameter("Areas", mAreas); } void Serialize(IArchive& rArc, CWorld::STimeAttackData& rData) { - rArc << SERIAL("HasTimeAttack", rData.HasTimeAttack) - << SERIAL("ActNumber", rData.ActNumber) - << SERIAL("BronzeTime", rData.BronzeTime) - << SERIAL("SilverTime", rData.SilverTime) - << SERIAL("GoldTime", rData.GoldTime) - << SERIAL("ShinyGoldTime", rData.ShinyGoldTime); + rArc << SerialParameter("HasTimeAttack", rData.HasTimeAttack) + << SerialParameter("ActNumber", rData.ActNumber) + << SerialParameter("BronzeTime", rData.BronzeTime) + << SerialParameter("SilverTime", rData.SilverTime) + << SerialParameter("GoldTime", rData.GoldTime) + << SerialParameter("ShinyGoldTime", rData.ShinyGoldTime); } void Serialize(IArchive& rArc, CWorld::SMemoryRelay& rMemRelay) { - rArc << SERIAL_HEX("MemoryRelayID", rMemRelay.InstanceID) - << SERIAL_HEX("TargetID", rMemRelay.TargetID) - << SERIAL("Message", rMemRelay.Message) - << SERIAL("Active", rMemRelay.Active); + rArc << SerialParameter("MemoryRelayID", rMemRelay.InstanceID, SH_HexDisplay) + << SerialParameter("TargetID", rMemRelay.TargetID, SH_HexDisplay) + << SerialParameter("Message", rMemRelay.Message) + << SerialParameter("Active", rMemRelay.Active); } void Serialize(IArchive& rArc, CWorld::SArea& rArea) { - rArc << SERIAL("Name", rArea.InternalName) - << SERIAL("NameString", rArea.pAreaName) - << SERIAL("MREA", rArea.AreaResID) - << SERIAL("ID", rArea.AreaID) - << SERIAL("Transform", rArea.Transform) - << SERIAL("BoundingBox", rArea.AetherBox) - << SERIAL("AllowPakDuplicates", rArea.AllowPakDuplicates) - << SERIAL_CONTAINER("AttachedAreas", rArea.AttachedAreaIDs, "AreaIndex") - << SERIAL_CONTAINER("RelModules", rArea.RelFilenames, "Module") - << SERIAL_CONTAINER("RelOffsets", rArea.RelOffsets, "Offset") - << SERIAL_CONTAINER("Docks", rArea.Docks, "Dock") - << SERIAL_CONTAINER("Layers", rArea.Layers, "Layer"); + rArc << SerialParameter("Name", rArea.InternalName) + << SerialParameter("NameString", rArea.pAreaName) + << SerialParameter("MREA", rArea.AreaResID) + << SerialParameter("ID", rArea.AreaID) + << SerialParameter("Transform", rArea.Transform) + << SerialParameter("BoundingBox", rArea.AetherBox) + << SerialParameter("AllowPakDuplicates", rArea.AllowPakDuplicates) + << SerialParameter("AttachedAreas", rArea.AttachedAreaIDs) + << SerialParameter("RelModules", rArea.RelFilenames) + << SerialParameter("RelOffsets", rArea.RelOffsets) + << SerialParameter("Docks", rArea.Docks) + << SerialParameter("Layers", rArea.Layers); } void Serialize(IArchive& rArc, CWorld::SArea::SDock& rDock) { - rArc << SERIAL_CONTAINER("ConnectingDocks", rDock.ConnectingDocks, "ConnectingDock") - << SERIAL_CONTAINER("DockCoords", rDock.DockCoordinates, "Coord"); + rArc << SerialParameter("ConnectingDocks", rDock.ConnectingDocks) + << SerialParameter("DockCoords", rDock.DockCoordinates); } void Serialize(IArchive& rArc, CWorld::SArea::SDock::SConnectingDock& rDock) { - rArc << SERIAL("AreaIndex", rDock.AreaIndex) - << SERIAL("DockIndex", rDock.DockIndex); + rArc << SerialParameter("AreaIndex", rDock.AreaIndex) + << SerialParameter("DockIndex", rDock.DockIndex); } void Serialize(IArchive& rArc, CWorld::SArea::SLayer& rLayer) { - rArc << SERIAL("Name", rLayer.LayerName) - << SERIAL("Active", rLayer.Active); + rArc << SerialParameter("Name", rLayer.LayerName) + << SerialParameter("Active", rLayer.Active); if (rArc.Game() >= eCorruption) { - rArc << SERIAL("StateID", rLayer.LayerStateID); + rArc << SerialParameter("StateID", rLayer.LayerStateID); } } void Serialize(IArchive& rArc, CWorld::SAudioGrp& rAudioGrp) { - rArc << SERIAL("GroupID", rAudioGrp.GroupID) - << SERIAL("AGSC", rAudioGrp.ResID); + rArc << SerialParameter("GroupID", rAudioGrp.GroupID) + << SerialParameter("AGSC", rAudioGrp.ResID); } diff --git a/src/Core/Resource/Script/IPropertyNew.cpp b/src/Core/Resource/Script/IPropertyNew.cpp index 6c3f6f3f..b7f62567 100644 --- a/src/Core/Resource/Script/IPropertyNew.cpp +++ b/src/Core/Resource/Script/IPropertyNew.cpp @@ -95,14 +95,14 @@ void IPropertyNew::Serialize(IArchive& rArc) { if (rArc.Game() <= ePrime) { - rArc << SERIAL("Name", mName); + rArc << SerialParameter("Name", mName); } - rArc << SERIAL_HEX("ID", mID) - << SERIAL("Description", mDescription) - << SERIAL("CookPref", mCookPreference) - << SERIAL("MinVersion", mMinVersion) - << SERIAL("MaxVersion", mMaxVersion); + rArc << SerialParameter("ID", mID, SH_HexDisplay | SH_Optional, (u32) 0xFFFFFFFF) + << SerialParameter("Description", mDescription, SH_Optional) + << SerialParameter("CookPref", mCookPreference, SH_Optional, ECookPreferenceNew::Default) + << SerialParameter("MinVersion", mMinVersion, SH_Optional, 0.f) + << SerialParameter("MaxVersion", mMaxVersion, SH_Optional, FLT_MAX); // Children don't get serialized for most property types } @@ -359,3 +359,12 @@ IPropertyNew* IPropertyNew::CreateIntrinsic(EPropertyTypeNew Type, pOut->PostInitialize(); return pOut; } + +IPropertyNew* IPropertyNew::ArchiveConstructor(EPropertyTypeNew Type, + const IArchive& Arc) +{ + IPropertyNew* pParent = Arc.FindParentObject(); + CScriptTemplate* pTemplate = (pParent ? pParent->ScriptTemplate() : Arc.FindParentObject()); + EGame Game = Arc.Game(); + return Create(Type, pParent, Game, pTemplate); +} diff --git a/src/Core/Resource/Script/IPropertyNew.h b/src/Core/Resource/Script/IPropertyNew.h index d1823e1e..c6cc6367 100644 --- a/src/Core/Resource/Script/IPropertyNew.h +++ b/src/Core/Resource/Script/IPropertyNew.h @@ -230,6 +230,9 @@ public: IPropertyNew* pParent, u32 Offset, const TString& rkName); + + static IPropertyNew* ArchiveConstructor(EPropertyTypeNew Type, + const IArchive& Arc); }; inline ECookPreferenceNew IPropertyNew::CookPreference() const @@ -374,7 +377,43 @@ public: virtual void Serialize(IArchive& rArc) { IPropertyNew::Serialize(rArc); - rArc << SERIAL("DefaultValue", mDefaultValue); + + // Determine if default value should be serialized as optional. + // All MP1 properties should be optional. For MP2 and on, we set optional + // on property types that don't have default values in the game executable. + bool MakeOptional = false; + + if (Game() <= ePrime) + { + MakeOptional = true; + } + else + { + switch (Type()) + { + case EPropertyTypeNew::String: + case EPropertyTypeNew::Asset: + case EPropertyTypeNew::Animation: + case EPropertyTypeNew::AnimationSet: + case EPropertyTypeNew::Sequence: + case EPropertyTypeNew::Spline: + case EPropertyTypeNew::Guid: + MakeOptional = true; + break; + } + } + + // Branch here to avoid constructing a default value if we don't need to. + if (MakeOptional) + rArc << SerialParameter("DefaultValue", mDefaultValue, SH_Optional, GetSerializationDefaultValue()); + else + rArc << SerialParameter("DefaultValue", mDefaultValue); + } + + /** Return default value for serialization - can be customized per type */ + virtual PropType GetSerializationDefaultValue() + { + return PropType(); } }; @@ -398,8 +437,8 @@ public: virtual void Serialize(IArchive& rArc) { TTypedPropertyNew::Serialize(rArc); - rArc << SERIAL("Min", mMinValue) - << SERIAL("Max", mMaxValue); + rArc << SerialParameter("Min", mMinValue, SH_Optional, (PropType) -1) + << SerialParameter("Max", mMaxValue, SH_Optional, (PropType) -1); } virtual void InitFromArchetype(IPropertyNew* pOther) diff --git a/src/Core/Resource/Script/Property/CAnimationProperty.h b/src/Core/Resource/Script/Property/CAnimationProperty.h index 2acf9d29..410fc6a2 100644 --- a/src/Core/Resource/Script/Property/CAnimationProperty.h +++ b/src/Core/Resource/Script/Property/CAnimationProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& rArc) const { - rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) ); + rArc.SerializePrimitive( (u32&) ValueRef(pData), SH_HexDisplay ); } virtual TString ValueAsString(void* pData) const diff --git a/src/Core/Resource/Script/Property/CAnimationSetProperty.h b/src/Core/Resource/Script/Property/CAnimationSetProperty.h index 5d9c0589..1cc025fe 100644 --- a/src/Core/Resource/Script/Property/CAnimationSetProperty.h +++ b/src/Core/Resource/Script/Property/CAnimationSetProperty.h @@ -13,6 +13,11 @@ protected: {} public: + virtual void PostInitialize() + { + mDefaultValue.SetGame(Game()); + } + virtual void SerializeValue(void* pData, IArchive& Arc) const { Value(pData).Serialize(Arc); @@ -22,6 +27,11 @@ public: { return (Game() <= eEchoes ? "AnimationSet" : "CharacterAnimationSet"); } + + virtual CAnimationParameters GetSerializationDefaultValue() + { + return CAnimationParameters( Game() ); + } }; #endif // CANIMATIONSETPROPERTY_H diff --git a/src/Core/Resource/Script/Property/CArrayProperty.h b/src/Core/Resource/Script/Property/CArrayProperty.h index 6928dfed..e4f3a0cb 100644 --- a/src/Core/Resource/Script/Property/CArrayProperty.h +++ b/src/Core/Resource/Script/Property/CArrayProperty.h @@ -108,20 +108,20 @@ public: virtual void Serialize(IArchive& rArc) { TTypedPropertyNew::Serialize(rArc); - //rArc << SERIAL("ItemArchetype", mpItemArchetype); + rArc << SerialParameter("ItemArchetype", mpItemArchetype); } virtual void SerializeValue(void* pData, IArchive& Arc) const { u32 Count = ArrayCount(pData); - Arc.SerializeContainerSize(Count, "ArrayElement"); + Arc.SerializeArraySize(Count); if (Arc.IsReader()) Resize(pData, Count); for (u32 ItemIdx = 0; ItemIdx < Count; ItemIdx++) { - if (Arc.ParamBegin("ArrayElement")) + if (Arc.ParamBegin("ArrayElement", 0)) { void* pItemData = ItemPointer(pData, ItemIdx); mpItemArchetype->SerializeValue(pItemData, Arc); diff --git a/src/Core/Resource/Script/Property/CAssetProperty.h b/src/Core/Resource/Script/Property/CAssetProperty.h index ed60de45..37eea4a2 100644 --- a/src/Core/Resource/Script/Property/CAssetProperty.h +++ b/src/Core/Resource/Script/Property/CAssetProperty.h @@ -10,10 +10,19 @@ class CAssetProperty : public TSerializeableTypedProperty void Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(Name) - << SERIAL_HEX_AUTO(ID); + rArc << SerialParameter("Name", Name) + << SerialParameter("ID", ID, SH_HexDisplay); } }; std::vector mValues; @@ -55,12 +55,12 @@ public: virtual void Serialize(IArchive& rArc) { TSerializeableTypedProperty::Serialize(rArc); - rArc << SERIAL_CONTAINER("Values", mValues, "Values"); + rArc << SerialParameter("Values", mValues); } virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( (u32&) ValueRef(pData) ); + Arc.SerializePrimitive( (u32&) ValueRef(pData), 0 ); } virtual void InitFromArchetype(IPropertyNew* pOther) diff --git a/src/Core/Resource/Script/Property/CFlagsProperty.h b/src/Core/Resource/Script/Property/CFlagsProperty.h index 4abf3449..9f09353a 100644 --- a/src/Core/Resource/Script/Property/CFlagsProperty.h +++ b/src/Core/Resource/Script/Property/CFlagsProperty.h @@ -28,8 +28,8 @@ class CFlagsProperty : public TSerializeableTypedProperty mBitFlags; @@ -64,7 +64,7 @@ public: virtual void Serialize(IArchive& rArc) { TSerializeableTypedProperty::Serialize(rArc); - rArc << SERIAL_CONTAINER("Flags", mBitFlags, "Flag"); + rArc << SerialParameter("Flags", mBitFlags); } virtual void PostInitialize() @@ -80,7 +80,7 @@ public: virtual void SerializeValue(void* pData, IArchive& rArc) const { - rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) ); + rArc.SerializePrimitive( (u32&) ValueRef(pData), SH_HexDisplay ); } virtual void InitFromArchetype(IPropertyNew* pOther) diff --git a/src/Core/Resource/Script/Property/CFloatProperty.h b/src/Core/Resource/Script/Property/CFloatProperty.h index ba310938..26c24a6f 100644 --- a/src/Core/Resource/Script/Property/CFloatProperty.h +++ b/src/Core/Resource/Script/Property/CFloatProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( (float&) ValueRef(pData) ); + Arc.SerializePrimitive( (float&) ValueRef(pData), 0 ); } virtual TString ValueAsString(void* pData) const diff --git a/src/Core/Resource/Script/Property/CGuidProperty.h b/src/Core/Resource/Script/Property/CGuidProperty.h index 6931ba71..98a80a38 100644 --- a/src/Core/Resource/Script/Property/CGuidProperty.h +++ b/src/Core/Resource/Script/Property/CGuidProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializeBulkData( ValueRef(pData) ); + Arc << SerialParameter("Data", ValueRef(pData)); } }; diff --git a/src/Core/Resource/Script/Property/CIntProperty.h b/src/Core/Resource/Script/Property/CIntProperty.h index 4e6ea93a..796fba1d 100644 --- a/src/Core/Resource/Script/Property/CIntProperty.h +++ b/src/Core/Resource/Script/Property/CIntProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( (u32&) ValueRef(pData) ); + Arc.SerializePrimitive( ValueRef(pData), 0 ); } virtual TString ValueAsString(void* pData) const diff --git a/src/Core/Resource/Script/Property/CShortProperty.h b/src/Core/Resource/Script/Property/CShortProperty.h index 427ccdbb..d40d088a 100644 --- a/src/Core/Resource/Script/Property/CShortProperty.h +++ b/src/Core/Resource/Script/Property/CShortProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( (u16&) ValueRef(pData) ); + Arc.SerializePrimitive( ValueRef(pData), 0 ); } virtual TString ValueAsString(void* pData) const diff --git a/src/Core/Resource/Script/Property/CSoundProperty.h b/src/Core/Resource/Script/Property/CSoundProperty.h index 8b7ed779..af7c2c20 100644 --- a/src/Core/Resource/Script/Property/CSoundProperty.h +++ b/src/Core/Resource/Script/Property/CSoundProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( (u32&) ValueRef(pData) ); + Arc.SerializePrimitive( ValueRef(pData), 0 ); } virtual TString ValueAsString(void* pData) diff --git a/src/Core/Resource/Script/Property/CSplineProperty.h b/src/Core/Resource/Script/Property/CSplineProperty.h index 1aeb8e5b..4a479981 100644 --- a/src/Core/Resource/Script/Property/CSplineProperty.h +++ b/src/Core/Resource/Script/Property/CSplineProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializeBulkData( ValueRef(pData) ); + Arc << SerialParameter("Data", ValueRef(pData)); } }; diff --git a/src/Core/Resource/Script/Property/CStringProperty.h b/src/Core/Resource/Script/Property/CStringProperty.h index e33b9f15..8a277731 100644 --- a/src/Core/Resource/Script/Property/CStringProperty.h +++ b/src/Core/Resource/Script/Property/CStringProperty.h @@ -15,7 +15,7 @@ protected: public: virtual void SerializeValue(void* pData, IArchive& Arc) const { - Arc.SerializePrimitive( ValueRef(pData) ); + Arc.SerializePrimitive( ValueRef(pData), 0 ); } virtual TString ValueAsString(void* pData) const diff --git a/src/Core/Resource/Script/Property/CStructProperty.h b/src/Core/Resource/Script/Property/CStructProperty.h index 3bf0aef9..5b73fdfa 100644 --- a/src/Core/Resource/Script/Property/CStructProperty.h +++ b/src/Core/Resource/Script/Property/CStructProperty.h @@ -90,43 +90,14 @@ public: virtual void Serialize(IArchive& rArc) { IPropertyNew::Serialize(rArc); - - if (rArc.ParamBegin("SubProperties")) - { - u32 NumChildren = mChildren.size(); - rArc.SerializeContainerSize(NumChildren, "Property"); - - if (rArc.IsReader()) - { - mChildren.resize(NumChildren); - } - - for (u32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++) - { - if (rArc.ParamBegin("Property")) - { - EPropertyTypeNew Type = (rArc.IsWriter() ? mChildren[ChildIdx]->Type() : EPropertyTypeNew::Invalid); - rArc << SERIAL_AUTO(Type); - - if (rArc.IsReader()) - { - mChildren[ChildIdx] = Create(Type, this, mGame, mpScriptTemplate); - } - - mChildren[ChildIdx]->Serialize(rArc); - rArc.ParamEnd(); - } - } - - rArc.ParamEnd(); - } + rArc << SerialParameter("SubProperties", mChildren); } virtual void SerializeValue(void* pData, IArchive& Arc) const { for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++) { - if (Arc.ParamBegin("Property")) + if (Arc.ParamBegin("Property", 0)) { mChildren[ChildIdx]->SerializeValue(pData, Arc); Arc.ParamEnd(); diff --git a/src/Core/Resource/TResPtr.h b/src/Core/Resource/TResPtr.h index fc26c87f..738dc4b8 100644 --- a/src/Core/Resource/TResPtr.h +++ b/src/Core/Resource/TResPtr.h @@ -33,7 +33,7 @@ public: inline void Serialize(IArchive& rArc) { CAssetID ID = (mpRes && !rArc.IsReader() ? mpRes->ID() : CAssetID::InvalidID(rArc.Game())); - rArc.SerializePrimitive(ID); + rArc.SerializePrimitive(ID, 0); if (rArc.IsReader()) { diff --git a/src/Math/CAABox.cpp b/src/Math/CAABox.cpp index a6b072ed..b25d59c0 100644 --- a/src/Math/CAABox.cpp +++ b/src/Math/CAABox.cpp @@ -24,8 +24,8 @@ CAABox::CAABox(IInputStream& rInput) void CAABox::Serialize(IArchive& rArc) { - rArc << SERIAL("Min", mMin) - << SERIAL("Max", mMax); + rArc << SerialParameter("Min", mMin) + << SerialParameter("Max", mMax); } void CAABox::Write(IOutputStream& rOutput) diff --git a/src/Math/CTransform4f.cpp b/src/Math/CTransform4f.cpp index dc70a5b0..d392b2c9 100644 --- a/src/Math/CTransform4f.cpp +++ b/src/Math/CTransform4f.cpp @@ -73,9 +73,9 @@ CTransform4f::CTransform4f(CVector3f Position, CVector3f Rotation, CVector3f Sca void CTransform4f::Serialize(IArchive& rOut) { - rOut << SERIAL("Row0Col0", m[0][0]) << SERIAL("Row0Col1", m[0][1]) << SERIAL("Row0Col2", m[0][2]) << SERIAL("Row0Col3", m[0][3]) - << SERIAL("Row1Col0", m[1][0]) << SERIAL("Row1Col1", m[1][1]) << SERIAL("Row1Col2", m[1][2]) << SERIAL("Row1Col3", m[1][3]) - << SERIAL("Row2Col0", m[2][0]) << SERIAL("Row2Col1", m[2][1]) << SERIAL("Row2Col2", m[2][2]) << SERIAL("Row2Col3", m[2][3]); + rOut << SerialParameter("Row0Col0", m[0][0]) << SerialParameter("Row0Col1", m[0][1]) << SerialParameter("Row0Col2", m[0][2]) << SerialParameter("Row0Col3", m[0][3]) + << SerialParameter("Row1Col0", m[1][0]) << SerialParameter("Row1Col1", m[1][1]) << SerialParameter("Row1Col2", m[1][2]) << SerialParameter("Row1Col3", m[1][3]) + << SerialParameter("Row2Col0", m[2][0]) << SerialParameter("Row2Col1", m[2][1]) << SerialParameter("Row2Col2", m[2][2]) << SerialParameter("Row2Col3", m[2][3]); } void CTransform4f::Write(IOutputStream& rOut) diff --git a/src/Math/CVector3f.cpp b/src/Math/CVector3f.cpp index 1b8a771d..19ac0bbc 100644 --- a/src/Math/CVector3f.cpp +++ b/src/Math/CVector3f.cpp @@ -38,7 +38,9 @@ void CVector3f::Write(IOutputStream& rOutput) const void CVector3f::Serialize(IArchive& rArc) { - rArc << SERIAL_AUTO(X) << SERIAL_AUTO(Y) << SERIAL_AUTO(Z); + rArc << SerialParameter("X", X) + << SerialParameter("Y", Y) + << SerialParameter("Z", Z); } TString CVector3f::ToString() const diff --git a/templates/Properties.xml b/templates/Properties.xml index 3bd0fb9a..5456db87 100644 --- a/templates/Properties.xml +++ b/templates/Properties.xml @@ -559,7 +559,7 @@ - +