Fixed a few last things to get script template serialization working 100%. Fixed some bugs that caused the serializer to crash on loading old projects and prevented dependency trees from serializing correctly.

This commit is contained in:
Aruki
2018-09-20 13:11:42 -06:00
parent e2a57b7d49
commit 33e915a638
22 changed files with 575 additions and 270 deletions

View File

@@ -366,9 +366,12 @@ SOURCES += \
GameProject\COpeningBanner.cpp \
IProgressNotifier.cpp \
Resource/Script/CPropertyNameGenerator.cpp \
Resource/Script/IPropertyNew.cpp
Resource/Script/IPropertyNew.cpp \
Resource/Script/Property/CStructProperty.cpp \
Resource/Script/Property/CFlagsProperty.cpp
# Codegen
CODEGEN_DIR = $$EXTERNALS_DIR/CodeGen
CODEGEN_OUT_PATH = $$BUILD_DIR/Core/codegen_build/auto_codegen.cpp
CODEGEN_SRC_PATH = $$PWD
include($$EXTERNALS_DIR/CodeGen/codegen.pri)

View File

@@ -30,7 +30,7 @@ CGameExporter::CGameExporter(EDiscType DiscType, EGame Game, bool FrontEnd, EReg
, mpProgress(nullptr)
{
ASSERT(mGame != eUnknownGame);
ASSERT(mRegion != eRegion_Unknown);
ASSERT(mRegion != ERegion::Unknown);
}
#if PUBLIC_RELEASE

View File

@@ -46,7 +46,7 @@ class CGameProject
CGameProject()
: mProjectName("Unnamed Project")
, mGame(eUnknownGame)
, mRegion(eRegion_Unknown)
, mRegion(ERegion::Unknown)
, mGameID("000000")
, mBuildVersion(0.f)
, mpResourceStore(nullptr)

View File

@@ -376,7 +376,13 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
{
// Check whether this struct has already been read
TString StructName = rkTemplateFileName.GetFileName(false);
CStructPropertyNew* pArchetype = mpMaster->FindStructArchetype(StructName);
CStructPropertyNew* pArchetype = static_cast<CStructPropertyNew*>( mpMaster->FindPropertyArchetype(StructName) );
// Names cannot be shared between multiple property archetypes
if (pArchetype != nullptr)
{
ASSERT(pArchetype->Type() == EPropertyTypeNew::Struct);
}
// If the struct template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@@ -434,7 +440,7 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
LoadProperties(pSubPropsElem, nullptr, pArchetype, rkTemplateFileName);
pArchetype->PostInitialize();
mpMaster->mStructTemplates.emplace(
mpMaster->mPropertyTemplates.emplace(
std::make_pair(
StructName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
@@ -450,7 +456,13 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
{
// Check whether this struct has already been read
TString EnumName = rkTemplateFileName.GetFileName(false);
CEnumProperty* pArchetype = mpMaster->FindEnumArchetype(EnumName);
CEnumProperty* pArchetype = static_cast<CEnumProperty*>( mpMaster->FindPropertyArchetype(EnumName) );
// Names cannot be shared between multiple property archetypes
if (pArchetype != nullptr)
{
ASSERT(pArchetype->Type() == EPropertyTypeNew::Enum || pArchetype->Type() == EPropertyTypeNew::Choice);
}
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@@ -470,6 +482,7 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
);
ASSERT(pArchetype != nullptr);
pArchetype->mName = rkTemplateFileName.GetFileName(false);
pArchetype->mFlags |= EPropertyFlag::IsArchetype;
pArchetype->mSourceFile = rkTemplateFileName;
@@ -482,7 +495,7 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
LoadEnumerators(pEnumers, pArchetype, rkTemplateFileName);
pArchetype->PostInitialize();
mpMaster->mEnumTemplates.emplace(
mpMaster->mPropertyTemplates.emplace(
std::make_pair(
EnumName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
@@ -498,7 +511,13 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
{
// Check whether this struct has already been read
TString FlagsName = rkTemplateFileName.GetFileName(false);
CFlagsProperty* pArchetype = mpMaster->FindFlagsArchetype(FlagsName);
CFlagsProperty* pArchetype = static_cast<CFlagsProperty*>( mpMaster->FindPropertyArchetype(FlagsName) );
// Names cannot be shared between multiple property archetypes
if (pArchetype != nullptr)
{
ASSERT(pArchetype->Type() == EPropertyTypeNew::Flags);
}
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@@ -517,6 +536,7 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
);
ASSERT(pArchetype != nullptr);
pArchetype->mName = rkTemplateFileName.GetFileName(false);
pArchetype->mFlags |= EPropertyFlag::IsArchetype;
pArchetype->mSourceFile = rkTemplateFileName;
@@ -529,7 +549,7 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
LoadBitFlags(pFlags, pArchetype, rkTemplateFileName);
pArchetype->PostInitialize();
mpMaster->mFlagsTemplates.emplace(
mpMaster->mPropertyTemplates.emplace(
std::make_pair(
FlagsName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
@@ -1119,8 +1139,69 @@ TString CTemplateLoader::ErrorName(XMLError Error)
}
// ************ PUBLIC ************
#define USE_NEW_TEMPLATES 0
void CTemplateLoader::LoadGameList()
{
#if USE_NEW_TEMPLATES
const TString kTemplatesDir = "../templates_new/";
// Read game list
{
const TString kGameListPath = kTemplatesDir + "GameList.xml";
CXMLReader Reader(kGameListPath);
ASSERT(Reader.IsValid());
if (Reader.ParamBegin("Games", 0))
{
u32 NumGames;
Reader.SerializeArraySize(NumGames);
for (u32 GameIdx = 0; GameIdx < NumGames; GameIdx++)
{
if (Reader.ParamBegin("Game", 0))
{
EGame Game;
TString Name, MasterPath;
Reader << SerialParameter("ID", Game, SH_Attribute)
<< SerialParameter("Name", Name)
<< SerialParameter("MasterTemplate", MasterPath);
CMasterTemplate* pMaster = new CMasterTemplate();
pMaster->mGame = Game;
pMaster->mGameName = Name;
pMaster->mSourceFile = MasterPath;
CMasterTemplate::smMasterMap[Game] = pMaster;
Reader.ParamEnd();
}
}
Reader.ParamEnd();
}
}
{
// Read property list
const TString kPropertyMapPath = kTemplatesDir + "PropertyMap.xml";
CXMLReader Reader(kPropertyMapPath);
ASSERT(Reader.IsValid());
Reader << SerialParameter("PropertyMap", CMasterTemplate::smPropertyNames, SH_HexDisplay);
}
{
// Read master templates
std::list<CMasterTemplate*> MasterList = CMasterTemplate::MasterList();
for (auto Iter = MasterList.begin(); Iter != MasterList.end(); Iter++)
{
CMasterTemplate* pMaster = *Iter;
const TString kMasterPath = kTemplatesDir + pMaster->GetDirectory() + "Game.xml";
CXMLReader Reader(kMasterPath);
ASSERT(Reader.IsValid());
pMaster->Serialize(Reader);
pMaster->LoadSubTemplates();
}
}
#else
Log::Write("Loading game list");
// Load Game List XML
@@ -1164,6 +1245,7 @@ void CTemplateLoader::LoadGameList()
pElem = pElem->NextSiblingElement();
}
#endif
}
void CTemplateLoader::LoadGameTemplates(EGame Game)
@@ -1247,10 +1329,10 @@ void CTemplateLoader::SaveGameList()
{
const TString kGameListPath = kTemplatesDir + "GameList.xml";
CXMLWriter Writer(kGameListPath, "GameList");
TString PropertyListPath = "PropertyNameMap.xml";
Writer << SerialParameter("PropertyList", PropertyListPath, 0);
u32 NumGames = CMasterTemplate::smMasterMap.size();
Writer.ParamBegin("Games", 0);
Writer.SerializeArraySize(NumGames);
for (auto Iter = CMasterTemplate::smMasterMap.begin(); Iter != CMasterTemplate::smMasterMap.end(); Iter++)
{
@@ -1272,7 +1354,7 @@ void CTemplateLoader::SaveGameList()
SGameInfo Info;
Info.Game = pMaster->Game();
Info.Name = pMaster->GameName();
Info.MasterPath = pMaster->GetDirectory() + "MasterTemplate.xml";
Info.MasterPath = pMaster->GetDirectory() + "Game.xml";
Writer << SerialParameter("Game", Info);
}
Writer.ParamEnd();

View File

@@ -10,9 +10,7 @@ CMasterTemplate::CMasterTemplate()
void CMasterTemplate::Serialize(IArchive& Arc)
{
Arc << SerialParameter("ScriptObjects", mScriptTemplates)
<< SerialParameter("Structs", mStructTemplates)
<< SerialParameter("Enums", mEnumTemplates)
<< SerialParameter("Flags", mFlagsTemplates)
<< SerialParameter("PropertyArchetypes", mPropertyTemplates)
<< SerialParameter("States", mStates)
<< SerialParameter("Messages", mMessages);
}
@@ -36,33 +34,13 @@ void CMasterTemplate::SaveSubTemplates()
Path.pTemplate->Serialize(Writer);
}
for (auto Iter = mStructTemplates.begin(); Iter != mStructTemplates.end(); Iter++)
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
{
SPropertyTemplatePath& Path = Iter->second;
TString OutPath = GameDir + Path.Path;
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
CXMLWriter Writer(OutPath, "Struct", 0, Game());
Path.pTemplate->Serialize(Writer);
}
for (auto Iter = mEnumTemplates.begin(); Iter != mEnumTemplates.end(); Iter++)
{
SPropertyTemplatePath& Path = Iter->second;
TString OutPath = GameDir + Path.Path;
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
CXMLWriter Writer(OutPath, "Enum", 0, Game());
Path.pTemplate->Serialize(Writer);
}
for (auto Iter = mFlagsTemplates.begin(); Iter != mFlagsTemplates.end(); Iter++)
{
SPropertyTemplatePath& Path = Iter->second;
TString OutPath = GameDir + Path.Path;
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
CXMLWriter Writer(OutPath, "Flags", 0, Game());
CXMLWriter Writer(OutPath, "PropertyArchetype", 0, Game());
Path.pTemplate->Serialize(Writer);
}
}
@@ -137,26 +115,10 @@ SMessage CMasterTemplate::MessageByIndex(u32 Index)
return SMessage(Iter->first, Iter->second);
}
CStructPropertyNew* CMasterTemplate::FindStructArchetype(const TString& kStructName) const
IPropertyNew* CMasterTemplate::FindPropertyArchetype(const TString& kTypeName) const
{
auto Iter = mStructTemplates.find(kStructName);
IPropertyNew* pProperty = (Iter != mStructTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
return TPropCast<CStructPropertyNew>(pProperty);
}
CEnumProperty* CMasterTemplate::FindEnumArchetype(const TString& kEnumName) const
{
auto Iter = mEnumTemplates.find(kEnumName);
IPropertyNew* pProperty = (Iter != mEnumTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
return TPropCast<CEnumProperty>(pProperty);
}
CFlagsProperty* CMasterTemplate::FindFlagsArchetype(const TString& kFlagsName) const
{
auto Iter = mFlagsTemplates.find(kFlagsName);
IPropertyNew* pProperty = (Iter != mFlagsTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
return TPropCast<CFlagsProperty>(pProperty);
auto Iter = mPropertyTemplates.find(kTypeName);
return (Iter != mPropertyTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
}
// ************ STATIC ************

View File

@@ -109,9 +109,7 @@ class CMasterTemplate
/** Template arrays */
std::map<SObjId, SScriptTemplatePath> mScriptTemplates;
std::map<TString, SPropertyTemplatePath> mStructTemplates;
std::map<TString, SPropertyTemplatePath> mEnumTemplates;
std::map<TString, SPropertyTemplatePath> mFlagsTemplates;
std::map<TString, SPropertyTemplatePath> mPropertyTemplates;
std::map<SObjId, TString> mStates;
std::map<SObjId, TString> mMessages;
@@ -141,10 +139,7 @@ public:
SMessage MessageByID(u32 MessageID);
SMessage MessageByID(const CFourCC& MessageID);
SMessage MessageByIndex(u32 Index);
CStructPropertyNew* FindStructArchetype(const TString& kStructName) const;
CEnumProperty* FindEnumArchetype(const TString& kEnumName) const;
CFlagsProperty* FindFlagsArchetype(const TString& kFlagsName) const;
IPropertyNew* FindPropertyArchetype(const TString& kTypeName) const;
// Inline Accessors
inline EGame Game() const { return mGame; }

View File

@@ -93,16 +93,41 @@ void* IPropertyNew::GetChildDataPointer(void* pPropertyData) const
void IPropertyNew::Serialize(IArchive& rArc)
{
if (rArc.Game() <= ePrime && !IsArchetype())
// Always serialize ID first! ID is always required (except for root properties, which have an ID of 0xFFFFFFFF)
// because they are needed to look up the correct property to apply parameter overrides to.
rArc << SerialParameter("ID", mID, SH_HexDisplay | SH_Attribute | SH_Optional, (u32) 0xFFFFFFFF);
// Now we can serialize the archetype reference and initialize if needed
if ( ((mpArchetype && mpArchetype->IsRootParent()) || rArc.IsReader()) && rArc.CanSkipParameters() )
{
rArc << SerialParameter("Name", mName);
TString ArchetypeName = (mpArchetype ? mpArchetype->Name() : "");
rArc << SerialParameter("Archetype", ArchetypeName, SH_Attribute);
if (rArc.IsReader() && !ArchetypeName.IsEmpty())
{
CMasterTemplate* pMaster = CMasterTemplate::MasterForGame( Game() );
IPropertyNew* pArchetype = pMaster->FindPropertyArchetype(ArchetypeName);
// The archetype must exist, or else the template file is malformed.
//@TODO: I think this will actually always fail right now, because property archetype loading has not been implemented yet
ASSERT(pArchetype != nullptr);
InitFromArchetype(pArchetype);
}
}
rArc << SerialParameter("ID", mID, SH_HexDisplay | SH_Attribute | SH_Optional, (u32) 0xFFFFFFFF)
<< SerialParameter("Description", mDescription, SH_Optional)
<< SerialParameter("CookPreference", mCookPreference, SH_Optional, ECookPreferenceNew::Default)
<< SerialParameter("MinVersion", mMinVersion, SH_Optional, 0.f)
<< SerialParameter("MaxVersion", mMaxVersion, SH_Optional, FLT_MAX);
// In MP1, the game data does not use property IDs, so we serialize the name directly.
// In MP2 and on, property names are looked up based on the property ID via the property name map.
if (rArc.Game() <= ePrime && !IsArchetype())
{
rArc << SerialParameter("Name", mName, mpArchetype ? SH_Optional : 0, mpArchetype ? mpArchetype->mName : "");
}
rArc << SerialParameter("Description", mDescription, SH_Optional, mpArchetype ? mpArchetype->mDescription : "")
<< SerialParameter("CookPreference", mCookPreference, SH_Optional, mpArchetype ? mpArchetype->mCookPreference : ECookPreferenceNew::Default)
<< SerialParameter("MinVersion", mMinVersion, SH_Optional, mpArchetype ? mpArchetype->mMinVersion : 0.f)
<< SerialParameter("MaxVersion", mMaxVersion, SH_Optional, mpArchetype ? mpArchetype->mMaxVersion : FLT_MAX)
<< SerialParameter("Suffix", mSuffix, SH_Optional, mpArchetype ? mpArchetype->mSuffix : "");
// Children don't get serialized for most property types
}
@@ -129,6 +154,17 @@ void IPropertyNew::InitFromArchetype(IPropertyNew* pOther)
}
}
bool IPropertyNew::ShouldSerialize() const
{
return mpArchetype == nullptr ||
mName != mpArchetype->mName ||
mDescription != mpArchetype->mDescription ||
mSuffix != mpArchetype->mSuffix ||
mCookPreference != mpArchetype->mCookPreference ||
mMinVersion != mpArchetype->mMinVersion ||
mMaxVersion != mpArchetype->mMaxVersion;
}
TString IPropertyNew::GetTemplateFileName()
{
if (mpScriptTemplate)

View File

@@ -184,6 +184,7 @@ public:
virtual void* GetChildDataPointer(void* pPropertyData) const;
virtual void Serialize(IArchive& rArc);
virtual void InitFromArchetype(IPropertyNew* pOther);
virtual bool ShouldSerialize() const;
virtual TString GetTemplateFileName();
/** Utility methods */
@@ -215,6 +216,7 @@ public:
inline bool IsArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArchetype); }
inline bool IsArrayArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArrayArchetype); }
inline bool IsAtomic() const { return mFlags.HasFlag(EPropertyFlag::IsAtomic); }
inline bool IsRootParent() const { return mpParent == nullptr; }
/** Create */
static IPropertyNew* Create(EPropertyTypeNew Type,
@@ -362,6 +364,11 @@ public:
return *ValuePtr(pData);
}
inline const PropType& DefaultValue() const
{
return mDefaultValue;
}
inline static EPropertyTypeNew StaticType() { return PropEnum; }
};
@@ -377,13 +384,14 @@ public:
virtual void Serialize(IArchive& rArc)
{
TTypedPropertyNew::Serialize(rArc);
TSerializeableTypedProperty* pArchetype = static_cast<TSerializeableTypedProperty*>(mpArchetype);
// 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)
if (Game() <= ePrime || pArchetype != nullptr)
{
MakeOptional = true;
}
@@ -405,11 +413,19 @@ public:
// Branch here to avoid constructing a default value if we don't need to.
if (MakeOptional)
rArc << SerialParameter("DefaultValue", mDefaultValue, SH_Optional, GetSerializationDefaultValue());
rArc << SerialParameter("DefaultValue", mDefaultValue, SH_Optional, pArchetype ? pArchetype->mDefaultValue : GetSerializationDefaultValue());
else
rArc << SerialParameter("DefaultValue", mDefaultValue);
}
virtual bool ShouldSerialize() const
{
TTypedPropertyNew* pArchetype = static_cast<TTypedPropertyNew*>(mpArchetype);
return TTypedPropertyNew::ShouldSerialize() ||
!(mDefaultValue == pArchetype->DefaultValue());
}
/** Return default value for serialization - can be customized per type */
virtual PropType GetSerializationDefaultValue()
{
@@ -437,8 +453,18 @@ public:
virtual void Serialize(IArchive& rArc)
{
TSerializeableTypedProperty::Serialize(rArc);
rArc << SerialParameter("Min", mMinValue, SH_Optional, (PropType) -1)
<< SerialParameter("Max", mMaxValue, SH_Optional, (PropType) -1);
TNumericalPropertyNew* pArchetype = static_cast<TNumericalPropertyNew*>(mpArchetype);
rArc << SerialParameter("Min", mMinValue, SH_Optional, pArchetype ? pArchetype->mMinValue : (PropType) -1)
<< SerialParameter("Max", mMaxValue, SH_Optional, pArchetype ? pArchetype->mMaxValue : (PropType) -1);
}
virtual bool ShouldSerialize() const
{
TNumericalPropertyNew* pArchetype = static_cast<TNumericalPropertyNew*>(mpArchetype);
return TSerializeableTypedProperty::ShouldSerialize() ||
mMinValue != pArchetype->mMinValue ||
mMaxValue != pArchetype->mMaxValue;
}
virtual void InitFromArchetype(IPropertyNew* pOther)

View File

@@ -22,7 +22,15 @@ public:
virtual void Serialize(IArchive& rArc)
{
TSerializeableTypedProperty::Serialize(rArc);
rArc << SerialParameter("TypeFilter", mTypeFilter);
CAssetProperty* pArchetype = static_cast<CAssetProperty*>(mpArchetype);
rArc << SerialParameter("TypeFilter", mTypeFilter, pArchetype ? SH_Optional : 0, pArchetype ? pArchetype->mTypeFilter : CResTypeFilter());
}
virtual bool ShouldSerialize() const
{
CAssetProperty* pArchetype = static_cast<CAssetProperty*>(mpArchetype);
return TSerializeableTypedProperty::ShouldSerialize() ||
mTypeFilter != pArchetype->mTypeFilter;
}
virtual void InitFromArchetype(IPropertyNew* pOther)

View File

@@ -34,8 +34,8 @@ class TEnumPropertyBase : public TSerializeableTypedProperty<s32, TypeEnum>
void Serialize(IArchive& rArc)
{
rArc << SerialParameter("Name", Name)
<< SerialParameter("ID", ID, SH_HexDisplay);
rArc << SerialParameter("Name", Name, SH_Attribute)
<< SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
}
};
std::vector<SEnumValue> mValues;
@@ -57,8 +57,14 @@ public:
// Skip TSerializeableTypedProperty, serialize default value ourselves so we can set SH_HexDisplay
TTypedPropertyNew::Serialize(rArc);
rArc << SerialParameter("DefaultValue", mDefaultValue, SH_HexDisplay | (Game() <= ePrime ? SH_Optional : 0))
<< SerialParameter("Values", mValues);
TEnumPropertyBase* pArchetype = static_cast<TEnumPropertyBase*>(mpArchetype);
u32 DefaultValueFlags = SH_HexDisplay | (pArchetype || Game() <= ePrime ? SH_Optional : 0);
rArc << SerialParameter("DefaultValue", mDefaultValue, DefaultValueFlags, pArchetype ? pArchetype->mDefaultValue : 0);
if (!pArchetype || !rArc.CanSkipParameters() || mValues != pArchetype->mValues)
{
rArc << SerialParameter("Values", mValues);
}
}
virtual void SerializeValue(void* pData, IArchive& Arc) const

View File

@@ -0,0 +1,53 @@
#include "CFlagsProperty.h"
#include "Core/Resource/Script/CMasterTemplate.h"
void CFlagsProperty::Serialize(IArchive& rArc)
{
TSerializeableTypedProperty::Serialize(rArc);
CFlagsProperty* pArchetype = static_cast<CFlagsProperty*>(mpArchetype);
if (!pArchetype || !rArc.CanSkipParameters() || mBitFlags != pArchetype->mBitFlags)
{
rArc << SerialParameter("Flags", mBitFlags);
}
}
void CFlagsProperty::PostInitialize()
{
TSerializeableTypedProperty::PostInitialize();
// Create AllFlags mask
mAllFlags = 0;
for (int FlagIdx = 0; FlagIdx < mBitFlags.size(); FlagIdx++)
mAllFlags |= mBitFlags[FlagIdx].Mask;
}
void CFlagsProperty::SerializeValue(void* pData, IArchive& rArc) const
{
rArc.SerializePrimitive( (u32&) ValueRef(pData), SH_HexDisplay );
}
void CFlagsProperty::InitFromArchetype(IPropertyNew* pOther)
{
TSerializeableTypedProperty::InitFromArchetype(pOther);
CFlagsProperty* pOtherFlags = static_cast<CFlagsProperty*>(pOther);
mBitFlags = pOtherFlags->mBitFlags;
mAllFlags = pOtherFlags->mAllFlags;
}
TString CFlagsProperty::GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mSourceFile : mpArchetype->GetTemplateFileName();
}
/**
* Checks whether there are any unrecognized bits toggled on in the property value.
* Returns the mask of any invalid bits. If all bits are valid, returns 0.
*/
u32 CFlagsProperty::HasValidValue(void* pPropertyData)
{
return ValueRef(pPropertyData) & ~mAllFlags;
}

View File

@@ -28,8 +28,8 @@ class CFlagsProperty : public TSerializeableTypedProperty<u32, EPropertyTypeNew:
void Serialize(IArchive& rArc)
{
rArc << SerialParameter("Name", Name)
<< SerialParameter("Mask", Mask, SH_HexDisplay);
rArc << SerialParameter("Name", Name, SH_Attribute)
<< SerialParameter("Mask", Mask, SH_Attribute | SH_HexDisplay);
}
};
std::vector<SBitFlag> mBitFlags;
@@ -61,50 +61,17 @@ public:
return mBitFlags[Idx].Mask;
}
virtual void Serialize(IArchive& rArc)
{
TSerializeableTypedProperty::Serialize(rArc);
rArc << SerialParameter("Flags", mBitFlags);
}
virtual void PostInitialize()
{
TTypedPropertyNew::PostInitialize();
// Create AllFlags mask
mAllFlags = 0;
for (int FlagIdx = 0; FlagIdx < mBitFlags.size(); FlagIdx++)
mAllFlags |= mBitFlags[FlagIdx].Mask;
}
virtual void SerializeValue(void* pData, IArchive& rArc) const
{
rArc.SerializePrimitive( (u32&) ValueRef(pData), SH_HexDisplay );
}
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
CFlagsProperty* pOtherFlags = static_cast<CFlagsProperty*>(pOther);
mBitFlags = pOtherFlags->mBitFlags;
mAllFlags = pOtherFlags->mAllFlags;
}
virtual TString GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mSourceFile : mpArchetype->GetTemplateFileName();
}
virtual void Serialize(IArchive& rArc);
virtual void PostInitialize();
virtual void SerializeValue(void* pData, IArchive& rArc) const;
virtual void InitFromArchetype(IPropertyNew* pOther);
virtual TString GetTemplateFileName();
/**
* Checks whether there are any unrecognized bits toggled on in the property value.
* Returns the mask of any invalid bits. If all bits are valid, returns 0.
*/
u32 HasValidValue(void* pPropertyData)
{
return ValueRef(pPropertyData) & ~mAllFlags;
}
u32 HasValidValue(void* pPropertyData);
};
#endif // CFLAGSPROPERTY_H

View File

@@ -0,0 +1,175 @@
#include "CStructProperty.h"
#include "Core/Resource/Script/CMasterTemplate.h"
EPropertyTypeNew CStructPropertyNew::Type() const
{
return EPropertyTypeNew::Struct;
}
u32 CStructPropertyNew::DataSize() const
{
if (!mChildren.empty())
{
IPropertyNew* pLastChild = mChildren.back();
return (pLastChild->Offset() - Offset()) + pLastChild->DataSize();
}
else
{
return 0;
}
}
u32 CStructPropertyNew::DataAlignment() const
{
// TODO. Should be aligned with the first child, but this function is called before children are loaded.
// So for now just use 8 to ensure correct alignment for all child types, but this is wasteful...
// It's also problematic for casting property data to a struct
return 8;
//return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment());
}
void CStructPropertyNew::Construct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Construct(pData);
}
}
void CStructPropertyNew::Destruct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Destruct(pData);
}
}
bool CStructPropertyNew::MatchesDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (!mChildren[ChildIdx]->MatchesDefault(pData))
{
return false;
}
}
return true;
}
void CStructPropertyNew::RevertToDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->RevertToDefault(pData);
}
}
const char* CStructPropertyNew::HashableTypeName() const
{
if (IsArchetype() || !mpArchetype)
return *mName;
else
return mpArchetype->HashableTypeName();
}
void CStructPropertyNew::Serialize(IArchive& rArc)
{
IPropertyNew::Serialize(rArc);
// Serialize archetype
if (mpArchetype)
{
CStructPropertyNew* pArchetype = static_cast<CStructPropertyNew*>(mpArchetype);
ASSERT(pArchetype != nullptr);
if (rArc.IsReader())
{
// We've initialized from the archetypes, now serialize parameter overrides
if (rArc.ParamBegin("SubProperties", 0))
{
u32 NumChildOverrides;
rArc.SerializeArraySize(NumChildOverrides);
for (u32 ChildIdx = 0; ChildIdx < NumChildOverrides; ChildIdx++)
{
if (rArc.ParamBegin("Element", SH_IgnoreName))
{
// Serialize type and ID, then look up the matching property and serialize it.
// We don't really need the type, but it's a good sanity check, and it's also helpful
// to guarantee that parameters are read in order, as some serializers are order-dependent.
EPropertyTypeNew ChildType;
u32 ChildID;
rArc << SerialParameter("Type", ChildType, SH_Attribute)
<< SerialParameter("ID", ChildID, SH_Attribute);
IPropertyNew* pChild = ChildByID(ChildID);
ASSERT(pChild != nullptr && pChild->Type() == ChildType);
pChild->Serialize(rArc);
rArc.ParamEnd();
}
}
rArc.ParamEnd();
}
}
else
{
// Check if any properties need to override parameters from their archetype.
std::vector<IPropertyNew*> PropertiesToSerialize;
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (mChildren[ChildIdx]->ShouldSerialize())
{
PropertiesToSerialize.push_back(mChildren[ChildIdx]);
}
}
u32 NumChildOverrides = PropertiesToSerialize.size();
if (NumChildOverrides > 0)
{
rArc << SerialParameter("SubProperties", PropertiesToSerialize);
}
}
}
else
{
rArc << SerialParameter("SubProperties", mChildren);
}
}
void CStructPropertyNew::SerializeValue(void* pData, IArchive& Arc) const
{
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (Arc.ParamBegin("Property", 0))
{
mChildren[ChildIdx]->SerializeValue(pData, Arc);
Arc.ParamEnd();
}
}
}
bool CStructPropertyNew::ShouldSerialize() const
{
if (IPropertyNew::ShouldSerialize())
return true;
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (mChildren[ChildIdx]->ShouldSerialize())
return true;
}
return false;
}
TString CStructPropertyNew::GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mTemplateFileName : mpArchetype->GetTemplateFileName();
}

View File

@@ -16,100 +16,18 @@ protected:
TString mTemplateFileName;
public:
virtual EPropertyTypeNew Type() const
{
return EPropertyTypeNew::Struct;
}
virtual u32 DataSize() const
{
if (!mChildren.empty())
{
IPropertyNew* pLastChild = mChildren.back();
return (pLastChild->Offset() - Offset()) + pLastChild->DataSize();
}
else
{
return 0;
}
}
virtual u32 DataAlignment() const
{
// TODO. Should be aligned with the first child, but this function is called before children are loaded.
// So for now just use 8 to ensure correct alignment for all child types, but this is wasteful...
return 8;
//return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment());
}
virtual void Construct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Construct(pData);
}
}
virtual void Destruct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Destruct(pData);
}
}
virtual bool MatchesDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (!mChildren[ChildIdx]->MatchesDefault(pData))
{
return false;
}
}
return true;
}
virtual void RevertToDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->RevertToDefault(pData);
}
}
virtual const char* HashableTypeName() const
{
if (IsArchetype() || !mpArchetype)
return *mName;
else
return mpArchetype->HashableTypeName();
}
virtual void Serialize(IArchive& rArc)
{
IPropertyNew::Serialize(rArc);
rArc << SerialParameter("SubProperties", mChildren);
}
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (Arc.ParamBegin("Property", 0))
{
mChildren[ChildIdx]->SerializeValue(pData, Arc);
Arc.ParamEnd();
}
}
}
virtual TString GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mTemplateFileName : mpArchetype->GetTemplateFileName();
}
virtual EPropertyTypeNew Type() const;
virtual u32 DataSize() const;
virtual u32 DataAlignment() const;
virtual void Construct(void* pData) const;
virtual void Destruct(void* pData) const;
virtual bool MatchesDefault(void* pData) const;
virtual void RevertToDefault(void* pData) const;
virtual const char* HashableTypeName() const;
virtual void Serialize(IArchive& rArc);
virtual void SerializeValue(void* pData, IArchive& Arc) const;
virtual bool ShouldSerialize() const;
virtual TString GetTemplateFileName();
inline static EPropertyTypeNew StaticType() { return EPropertyTypeNew::Struct; }
};