WIP script object template serialization

This commit is contained in:
Aruki 2018-09-16 09:44:19 -07:00
parent 5182f436b8
commit 36926ca28e
14 changed files with 634 additions and 179 deletions

View File

@ -9,13 +9,13 @@ namespace NBasics
/** Remove an element from a vector */
template<typename T>
bool VectorRemoveOne(std::vector<T>& rVector, const T& rkElement)
bool VectorRemoveOne(std::vector<T>& Vector, const T& kElement)
{
for (auto Iter = rVector.begin(); Iter != rVector.end(); Iter++)
for (auto Iter = Vector.begin(); Iter != Vector.end(); Iter++)
{
if (*Iter == rkElement)
if (*Iter == kElement)
{
rVector.erase(Iter);
Vector.erase(Iter);
return true;
}
}
@ -24,15 +24,15 @@ bool VectorRemoveOne(std::vector<T>& rVector, const T& rkElement)
/** Remove all occurrences of an element from a vector. Returns the number of elements that were removed. */
template<typename T>
int VectorRemoveAll(std::vector<T>& rVector, const T& rkElement)
int VectorRemoveAll(std::vector<T>& Vector, const T& kElement)
{
int NumRemoved = 0;
for (auto Iter = rVector.begin(); Iter != rVector.end(); Iter++)
for (auto Iter = Vector.begin(); Iter != Vector.end(); Iter++)
{
if (*Iter == rkElement)
if (*Iter == kElement)
{
Iter = rVector.erase(Iter);
Iter = Vector.erase(Iter);
NumRemoved++;
}
}
@ -40,6 +40,34 @@ int VectorRemoveAll(std::vector<T>& rVector, const T& rkElement)
return NumRemoved;
}
/** Returns whether the vector contains the given element */
template<typename T>
bool VectorContains(std::vector<T>& Vector, const T& kElement)
{
for (auto Iter = Vector.begin(); Iter != Vector.end(); Iter++)
{
if (*Iter == kElement)
{
return true;
}
}
return false;
}
/** Adds an element to a vector only if it is not already present */
template<typename T>
bool VectorAddUnique(std::vector<T>& Vector, const T& kElement)
{
if (!VectorContainsElement(Vector, kElement))
{
Vector.push_back(kElement);
return true;
}
return false;
}
}
#endif // NBASICS_H

View File

@ -57,22 +57,24 @@
/** 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_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!
SH_InheritHints = 0x40, // The parameter will inherit hints from its parent parameter (except for this flag).
SH_Proxy = 0x80, // The parameter is a proxy of the parent and will display inline instead of as a child parameter.
};
/** 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
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 */
@ -128,7 +130,14 @@ inline ParameterMatchesDefault( const TSerialParameter<ValType>& kParameter )
}
template<typename ValType>
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES, bool )
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES && TIsContainer<ValType>::value, bool )
inline ParameterMatchesDefault( const TSerialParameter<ValType>& kParameter )
{
return kParameter.rValue.size() == 0;
}
template<typename ValType>
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES && !TIsContainer<ValType>::value, bool )
inline ParameterMatchesDefault( const TSerialParameter<ValType>& )
{
return false;
@ -149,7 +158,15 @@ inline InitParameterToDefault( TSerialParameter<ValType>& Param )
}
template<typename ValType>
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES, bool )
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES && TIsContainer<ValType>::value, bool )
inline InitParameterToDefault( TSerialParameter<ValType>& Param )
{
Param.rValue.clear();
return true;
}
template<typename ValType>
ENABLE_IF( !SUPPORTS_DEFAULT_VALUES && !TIsContainer<ValType>::value, bool )
inline InitParameterToDefault( TSerialParameter<ValType>& )
{
return false;
@ -266,7 +283,6 @@ public:
virtual ~IArchive() {}
protected:
// Serialize archive version. Always call after opening a file.
void SerializeVersion()
{
@ -275,6 +291,25 @@ protected:
<< SerialParameter("Game", mGame, SH_Attribute | SH_Optional, eUnknownGame);
}
private:
// Attempts to start a new parameter. Return whether the parameter should be serialized.
template<typename ValType>
bool InternalStartParam(const TSerialParameter<ValType>& Param)
{
bool IsProxy = (Param.HintFlags & SH_Proxy) != 0;
return ShouldSerializeParameter(Param) && (IsProxy || ParamBegin(Param.pkName, Param.HintFlags) );
}
// Ends a parameter.
template<typename ValType>
void InternalEndParam(const TSerialParameter<ValType>& Param)
{
if ((Param.HintFlags & SH_Proxy) == 0)
{
ParamEnd();
}
}
// Return whether this parameter should be serialized
template<typename ValType>
bool ShouldSerializeParameter(const TSerialParameter<ValType>& Param)
@ -318,7 +353,7 @@ protected:
// Parameter stack handling
template<typename ValType>
inline void PushParameter(const TSerialParameter<ValType>& Param)
inline void PushParameter(TSerialParameter<ValType>& Param)
{
#if _DEBUG
if (mParmStack.size() > 0)
@ -328,6 +363,13 @@ protected:
}
#endif
// For InheritHints parameters, and for proxy parameters, copy the hint flags from the parent parameter.
if (Param.HintFlags & (SH_InheritHints | SH_Proxy))
{
Param.HintFlags |= mParmStack.back().HintFlags;
Param.HintFlags &= ~SH_InheritHints;
}
SParmStackEntry Entry;
Entry.TypeID = typeid(ValType).hash_code();
Entry.TypeSize = sizeof(ValType);
@ -357,11 +399,10 @@ public:
{
PushParameter(rParam);
if (ShouldSerializeParameter(rParam)
&& ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
SerializePrimitive(rParam.rValue, rParam.HintFlags);
ParamEnd();
InternalEndParam(rParam);
}
else if (IsReader())
InitParameterToDefault(rParam);
@ -377,8 +418,7 @@ public:
ASSERT( !(mArchiveFlags & AF_Writer) || rParam.rValue != nullptr );
PushParameter(rParam);
if (ShouldSerializeParameter(rParam)
&& ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
// Support for old versions of archives that serialize types on non-abstract polymorphic pointers
if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v<ValType>)
@ -398,7 +438,7 @@ public:
else if (IsReader())
rParam.rValue = nullptr;
ParamEnd();
InternalEndParam(rParam);
}
PopParameter(rParam);
@ -412,11 +452,10 @@ public:
{
PushParameter(rParam);
if (ShouldSerializeParameter(rParam)
&& ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
Serialize(*this, rParam.rValue);
ParamEnd();
InternalEndParam(rParam);
}
else if (IsReader())
InitParameterToDefault(rParam);
@ -432,8 +471,7 @@ public:
ASSERT( !IsWriter() || rParam.rValue != nullptr );
PushParameter(rParam);
if (ShouldSerializeParameter(rParam)
&& ParamBegin(rParam.pkName))
if (InternalStartParam(rParam))
{
// Support for old versions of archives that serialize types on non-abstract polymorphic pointers
if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v<ValType>)
@ -453,7 +491,7 @@ public:
else if (IsReader())
rParam.rValue = nullptr;
ParamEnd();
InternalEndParam(rParam);
}
PopParameter(rParam);
@ -467,11 +505,10 @@ public:
{
PushParameter(rParam);
if (ShouldSerializeParameter(rParam) &&
ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
rParam.rValue.Serialize(*this);
ParamEnd();
InternalEndParam(rParam);
}
else if (IsReader())
InitParameterToDefault(rParam);
@ -486,8 +523,7 @@ public:
{
PushParameter(rParam);
if (ShouldSerializeParameter(rParam) &&
ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
// Support for old versions of archives that serialize types on non-abstract polymorphic pointers
if (ArchiveVersion() < eArVer_Refactor && IsReader() && std::is_polymorphic_v<ValType>)
@ -507,7 +543,7 @@ public:
else if (IsReader())
rParam.rValue = nullptr;
ParamEnd();
InternalEndParam(rParam);
}
PopParameter(rParam);
@ -521,8 +557,7 @@ public:
{
PushParameter(rParam);
if (ShouldSerializeParameter(rParam) &&
ParamBegin(rParam.pkName, rParam.HintFlags))
if (InternalStartParam(rParam))
{
if (PreSerializePointer( (void*&) rParam.rValue, rParam.HintFlags ))
{
@ -560,7 +595,7 @@ public:
else if (IsReader())
rParam.rValue = nullptr;
ParamEnd();
InternalEndParam(rParam);
}
else
{
@ -664,11 +699,36 @@ public:
}
};
/** Function that serializes a value directly */
template<typename ValType>
ENABLE_IF( IS_SERIAL_TYPE(Primitive), IArchive& )
inline SerializeDirect(IArchive& Arc, ValType& Value)
{
Arc.SerializePrimitive(Value, SH_InheritHints);
return Arc;
}
template<typename ValType>
ENABLE_IF( IS_SERIAL_TYPE(Global), IArchive& )
inline SerializeDirect(IArchive& Arc, ValType& Value)
{
Serialize(Arc, Value);
return Arc;
}
template<typename ValType>
ENABLE_IF( IS_SERIAL_TYPE(Member), IArchive& )
inline SerializeDirect(IArchive& Arc, ValType& Value)
{
Value.Serialize(Arc);
return Arc;
}
#if WITH_CODEGEN
// Default enum serializer; can be overridden
#include <codegen/EnumReflection.h>
template<typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
template<typename T, typename = typename std::enable_if< std::is_enum<T>::value >::type>
inline void Serialize(IArchive& Arc, T& Val)
{
if (Arc.IsTextFormat())
@ -709,7 +769,7 @@ inline void Serialize(IArchive& Arc, std::vector<T>& Vector)
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);
Arc << SerialParameter("Element", Vector[i], SH_IgnoreName);
}
}
@ -742,7 +802,7 @@ inline void Serialize(IArchive& Arc, std::list<T>& List)
}
for (auto Iter = List.begin(); Iter != List.end(); Iter++)
Arc << SerialParameter("Item", *Iter, SH_IgnoreName);
Arc << SerialParameter("Element", *Iter, SH_IgnoreName);
}
// Overload for TStringList and TWideStringList so they can use the TString/TWideString serialize functions
@ -770,7 +830,7 @@ inline void Serialize(IArchive& Arc, std::set<T>& Set)
for (u32 i = 0; i < Size; i++)
{
T Val;
Arc << SerialParameter("Item", Val, SH_IgnoreName);
Arc << SerialParameter("Element", Val, SH_IgnoreName);
Set.insert(Val);
}
}
@ -780,7 +840,7 @@ inline void Serialize(IArchive& Arc, std::set<T>& Set)
for (auto Iter = Set.begin(); Iter != Set.end(); Iter++)
{
T Val = *Iter;
Arc << SerialParameter("Item", Val, SH_IgnoreName);
Arc << SerialParameter("Element", Val, SH_IgnoreName);
}
}
}
@ -799,7 +859,7 @@ inline void SerializeMap_Internal(IArchive& Arc, MapType& Map)
KeyType Key;
ValType Val;
if (Arc.ParamBegin("Item", SH_IgnoreName))
if (Arc.ParamBegin("Element", SH_IgnoreName))
{
Arc << SerialParameter("Key", Key, SH_IgnoreName)
<< SerialParameter("Value", Val, SH_IgnoreName);
@ -820,7 +880,7 @@ inline void SerializeMap_Internal(IArchive& Arc, MapType& Map)
KeyType Key = Iter->first;
ValType Val = Iter->second;
if (Arc.ParamBegin("Item", SH_IgnoreName))
if (Arc.ParamBegin("Element", SH_IgnoreName))
{
Arc << SerialParameter("Key", Key, SH_IgnoreName)
<< SerialParameter("Value", Val, SH_IgnoreName);
@ -843,6 +903,27 @@ inline void Serialize(IArchive& Arc, std::unordered_map<KeyType, ValType>& Map)
SerializeMap_Internal<KeyType, ValType, std::unordered_map<KeyType, ValType> >(Arc, Map);
}
// Smart pointer serialize methods
template<typename T>
void Serialize(IArchive& Arc, std::unique_ptr<T>& Pointer)
{
T* pRawPtr = Pointer.get();
Arc << SerialParameter("RawPointer", pRawPtr, SH_Proxy);
if (Arc.IsReader())
Pointer = std::unique_ptr<T>(pRawPtr);
}
template<typename T>
void Serialize(IArchive& Arc, std::shared_ptr<T>& Pointer)
{
T* pRawPtr = Pointer.get();
Arc << SerialParameter("RawPointer", pRawPtr, SH_Proxy);
if (Arc.IsReader())
Pointer = std::shared_ptr<T>(pRawPtr);
}
// Remove header-only macros
#undef ENABLE_IF
#undef SUPPORTS_DEFAULT_VALUES

View File

@ -50,7 +50,7 @@ public:
void Serialize(IArchive& rArc)
{
if (rArc.IsReader()) mGame = rArc.Game();
rArc << SerialParameter("AcceptedTypes", mAcceptedTypes);
rArc << SerialParameter("AcceptedTypes", mAcceptedTypes, SH_Proxy);
}
inline bool Accepts(EResType Type) const

View File

@ -375,8 +375,8 @@ IPropertyNew* CTemplateLoader::LoadProperty(XMLElement* pElem, CScriptTemplate*
CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTemplateFileName)
{
// Check whether this struct has already been read
auto it = mpMaster->mStructTemplates.find(rkTemplateFileName);
CStructPropertyNew* pArchetype = (it == mpMaster->mStructTemplates.end() ? nullptr : it->second);
TString StructName = rkTemplateFileName.GetFileName(false);
CStructPropertyNew* pArchetype = mpMaster->FindStructArchetype(StructName);
// If the struct template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@ -432,8 +432,13 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
ASSERT(pSubPropsElem);
LoadProperties(pSubPropsElem, nullptr, pArchetype, rkTemplateFileName);
mpMaster->mStructTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
mpMaster->mStructTemplates.emplace(
std::make_pair(
StructName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
));
}
}
@ -444,8 +449,8 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileName, bool bIsChoice)
{
// Check whether this struct has already been read
auto it = mpMaster->mEnumTemplates.find(rkTemplateFileName);
CEnumProperty* pArchetype = (it == mpMaster->mEnumTemplates.end() ? nullptr : it->second);
TString EnumName = rkTemplateFileName.GetFileName(false);
CEnumProperty* pArchetype = mpMaster->FindEnumArchetype(EnumName);
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@ -475,8 +480,13 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
ASSERT(pEnumers);
LoadEnumerators(pEnumers, pArchetype, rkTemplateFileName);
mpMaster->mEnumTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
mpMaster->mEnumTemplates.emplace(
std::make_pair(
EnumName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
));
}
}
@ -487,8 +497,8 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFileName)
{
// Check whether this struct has already been read
auto it = mpMaster->mFlagsTemplates.find(rkTemplateFileName);
CFlagsProperty* pArchetype = (it == mpMaster->mFlagsTemplates.end() ? nullptr : it->second);
TString FlagsName = rkTemplateFileName.GetFileName(false);
CFlagsProperty* pArchetype = mpMaster->FindFlagsArchetype(FlagsName);
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
@ -517,8 +527,14 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
ASSERT(pFlags);
LoadBitFlags(pFlags, pArchetype, rkTemplateFileName);
mpMaster->mFlagsTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
mpMaster->mFlagsTemplates.emplace(
std::make_pair(
FlagsName,
CMasterTemplate::SPropertyTemplatePath(rkTemplateFileName, pArchetype)
));
}
}
@ -937,28 +953,14 @@ void CTemplateLoader::LoadMasterTemplate(XMLDocument *pDoc, CMasterTemplate *pMa
mMasterDir = pMaster->mSourceFile.GetFileDirectory();
XMLElement *pRoot = pDoc->FirstChildElement("MasterTemplate");
mpMaster->mVersion = TString(pRoot->Attribute("version")).ToInt32();
XMLElement *pElem = pRoot->FirstChildElement();
while (pElem)
{
TString NodeName = pElem->Name();
// Versions
if (NodeName == "versions")
{
XMLElement *pVersion = pElem->FirstChildElement("version");
while (pVersion)
{
mpMaster->mGameVersions.push_back(pVersion->GetText());
pVersion = pVersion->NextSiblingElement("version");
}
}
// Objects
else if (NodeName == "objects")
if (NodeName == "objects")
{
XMLElement *pObj = pElem->FirstChildElement("object");
@ -984,7 +986,13 @@ void CTemplateLoader::LoadMasterTemplate(XMLDocument *pDoc, CMasterTemplate *pMa
CScriptTemplate *pTemp = LoadScriptTemplate(&ScriptXML, TemplateName, ID);
if (pTemp)
mpMaster->mTemplates[ID] = pTemp;
{
mpMaster->mScriptTemplates.emplace(
std::make_pair(
ID,
CMasterTemplate::SScriptTemplatePath(ID, TemplateName, pTemp)
));
}
}
pObj = pObj->NextSiblingElement("object");
@ -1007,7 +1015,7 @@ void CTemplateLoader::LoadMasterTemplate(XMLDocument *pDoc, CMasterTemplate *pMa
StateID = CFourCC(StrID).ToLong();
TString StateName = pState->Attribute("name");
mpMaster->mStates[StateID] = SState(StateID, StateName);
mpMaster->mStates[StateID] = StateName;
pState = pState->NextSiblingElement("state");
}
}
@ -1028,7 +1036,7 @@ void CTemplateLoader::LoadMasterTemplate(XMLDocument *pDoc, CMasterTemplate *pMa
MessageID = CFourCC(StrID).ToLong();
TString MessageName = pMessage->Attribute("name");
mpMaster->mMessages[MessageID] = SMessage(MessageID, MessageName);
mpMaster->mMessages[MessageID] = MessageName;
pMessage = pMessage->NextSiblingElement("message");
}
}
@ -1229,3 +1237,60 @@ void CTemplateLoader::LoadPropertyList(XMLDocument *pDoc, const TString& ListNam
}
}
}
void CTemplateLoader::SaveGameList()
{
const TString kTemplatesDir = "../templates_new/";
FileUtil::MakeDirectory( kTemplatesDir );
// Write game list
{
const TString kGameListPath = kTemplatesDir + "GameList.xml";
CXMLWriter Writer(kGameListPath, "GameList");
TString PropertyListPath = "PropertyNameMap.xml";
Writer << SerialParameter("PropertyList", PropertyListPath, 0);
Writer.ParamBegin("Games", 0);
for (auto Iter = CMasterTemplate::smMasterMap.begin(); Iter != CMasterTemplate::smMasterMap.end(); Iter++)
{
struct SGameInfo
{
EGame Game;
TString Name;
TString MasterPath;
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("ID", Game, SH_Attribute)
<< SerialParameter("Name", Name)
<< SerialParameter("MasterTemplate", MasterPath);
}
};
CMasterTemplate* pMaster = Iter->second;
SGameInfo Info;
Info.Game = pMaster->Game();
Info.Name = pMaster->GameName();
Info.MasterPath = pMaster->GetDirectory() + "MasterTemplate.xml";
Writer << SerialParameter("Game", Info);
}
Writer.ParamEnd();
}
// Write master templates
{
std::list<CMasterTemplate*> MasterList = CMasterTemplate::MasterList();
for (auto Iter = MasterList.begin(); Iter != MasterList.end(); Iter++)
{
CMasterTemplate* pMasterTemplate = *Iter;
TString MasterFilePath = kTemplatesDir + pMasterTemplate->GetDirectory() + "Game.xml";
FileUtil::MakeDirectory( MasterFilePath.GetFileDirectory() );
CXMLWriter Writer(MasterFilePath, "Game", 0, pMasterTemplate->Game());
pMasterTemplate->Serialize(Writer);
pMasterTemplate->SaveSubTemplates();
}
}
}

View File

@ -50,6 +50,8 @@ public:
static void LoadGameTemplates(EGame Game);
static void LoadAllGames();
static void LoadPropertyList(tinyxml2::XMLDocument* pDoc, const TString& rkListName);
static void SaveGameList();
};
#endif // CTEMPLATELOADER_H

View File

@ -8,20 +8,56 @@
struct SState
{
u32 ID;
union {
u32 ID;
CFourCC ID_4CC;
};
TString Name;
SState() {}
SState(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
SState()
{}
SState(u32 InID, const TString& kInName)
: ID(InID)
, Name(kInName)
{}
void Serialize(IArchive& Arc)
{
if (Arc.Game() <= ePrime)
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
else
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
Arc << SerialParameter("Name", Name, SH_Attribute);
}
};
struct SMessage
{
u32 ID;
union {
u32 ID;
CFourCC ID_4CC;
};
TString Name;
SMessage() {}
SMessage(u32 _ID, const TString& rkName) : ID(_ID), Name(rkName) {}
SMessage()
{}
SMessage(u32 InID, const TString& kInName)
: ID(InID)
, Name(kInName)
{}
void Serialize(IArchive& Arc)
{
if (Arc.Game() <= ePrime)
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
else
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
Arc << SerialParameter("Name", Name, SH_Attribute);
}
};
class CLink

View File

@ -3,34 +3,81 @@
#include <Common/Log.h>
CMasterTemplate::CMasterTemplate()
: mVersion(0)
, mFullyLoaded(false)
: mFullyLoaded(false)
{
}
CMasterTemplate::~CMasterTemplate()
void CMasterTemplate::Serialize(IArchive& Arc)
{
for (auto it = mTemplates.begin(); it != mTemplates.end(); it++)
delete it->second;
Arc << SerialParameter("ScriptObjects", mScriptTemplates)
<< SerialParameter("Structs", mStructTemplates)
<< SerialParameter("Enums", mEnumTemplates)
<< SerialParameter("Flags", mFlagsTemplates)
<< SerialParameter("States", mStates)
<< SerialParameter("Messages", mMessages);
}
void CMasterTemplate::LoadSubTemplates()
{
//todo
}
void CMasterTemplate::SaveSubTemplates()
{
TString GameDir = "../templates_new/" + GetDirectory();
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
{
SScriptTemplatePath& Path = Iter->second;
TString OutPath = GameDir + Path.Path;
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
CXMLWriter Writer(OutPath, "ScriptObject", 0, Game());
Path.pTemplate->Serialize(Writer);
}
for (auto Iter = mStructTemplates.begin(); Iter != mStructTemplates.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());
Path.pTemplate->Serialize(Writer);
}
}
u32 CMasterTemplate::GameVersion(TString VersionName)
{
VersionName = VersionName.ToLower();
for (u32 iVer = 0; iVer < mGameVersions.size(); iVer++)
if (mGameVersions[iVer].ToLower() == VersionName)
return iVer;
return -1;
}
CScriptTemplate* CMasterTemplate::TemplateByID(u32 ObjectID)
{
auto it = mTemplates.find(ObjectID);
auto it = mScriptTemplates.find(ObjectID);
if (it != mTemplates.end())
return it->second;
if (it != mScriptTemplates.end())
return it->second.pTemplate.get();
else
return nullptr;
}
@ -42,16 +89,16 @@ CScriptTemplate* CMasterTemplate::TemplateByID(const CFourCC& ObjectID)
CScriptTemplate* CMasterTemplate::TemplateByIndex(u32 Index)
{
auto it = mTemplates.begin();
return (std::next(it, Index))->second;
auto it = mScriptTemplates.begin();
return (std::next(it, Index))->second.pTemplate.get();
}
SState CMasterTemplate::StateByID(u32 StateID)
{
auto it = mStates.find(StateID);
auto Iter = mStates.find(StateID);
if (it != mStates.end())
return it->second;
if (Iter != mStates.end())
return SState(Iter->first, Iter->second);
else
return SState(-1, "Invalid");
}
@ -63,16 +110,17 @@ SState CMasterTemplate::StateByID(const CFourCC& State)
SState CMasterTemplate::StateByIndex(u32 Index)
{
auto it = mStates.begin();
return (std::next(it, Index))->second;
auto Iter = mStates.begin();
Iter = std::next(Iter, Index);
return SState(Iter->first, Iter->second);
}
SMessage CMasterTemplate::MessageByID(u32 MessageID)
{
auto it = mMessages.find(MessageID);
auto Iter = mMessages.find(MessageID);
if (it != mMessages.end())
return it->second;
if (Iter != mMessages.end())
return SMessage(Iter->first, Iter->second);
else
return SMessage(-1, "Invalid");
}
@ -84,18 +132,31 @@ SMessage CMasterTemplate::MessageByID(const CFourCC& MessageID)
SMessage CMasterTemplate::MessageByIndex(u32 Index)
{
auto it = mMessages.begin();
return (std::next(it, Index))->second;
auto Iter = mMessages.begin();
Iter = std::next(Iter, Index);
return SMessage(Iter->first, Iter->second);
}
CStructPropertyNew* CMasterTemplate::StructAtSource(const TString& rkSource)
CStructPropertyNew* CMasterTemplate::FindStructArchetype(const TString& kStructName) const
{
auto InfoIt = mStructTemplates.find(rkSource);
auto Iter = mStructTemplates.find(kStructName);
IPropertyNew* pProperty = (Iter != mStructTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
return TPropCast<CStructPropertyNew>(pProperty);
}
if (InfoIt != mStructTemplates.end())
return InfoIt->second;
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);
}
else return nullptr;
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);
}
// ************ STATIC ************

View File

@ -8,25 +8,113 @@
#include <Common/types.h>
#include <map>
/** Serialization aid
* Retro switched from using integers to fourCCs to represent IDs in several cases (states/messages, object IDs).
* This struct is functionally an integer but it serializes as an int for MP1 and a fourCC for MP2 and on.
*/
struct SObjId
{
union {
u32 ID;
CFourCC ID_4CC;
};
inline SObjId() {}
inline SObjId(u32 InID) : ID(InID) {}
inline SObjId(CFourCC InID) : ID_4CC(InID) {}
inline operator u32() const { return ID; }
inline operator CFourCC() const { return ID_4CC; }
void Serialize(IArchive& Arc)
{
if (Arc.Game() <= ePrime)
Arc.SerializePrimitive(ID, SH_HexDisplay);
else
Arc.SerializePrimitive(ID_4CC, 0);
}
};
class CMasterTemplate
{
friend class CTemplateLoader;
friend class CTemplateWriter;
/** Struct holding a reference to a script object template */
struct SScriptTemplatePath
{
/** Script object ID */
SObjId ID;
/** File path to the template file, relative to the game directory */
TString Path;
/** Template in memory */
std::shared_ptr<CScriptTemplate> pTemplate;
/** Constructor */
SScriptTemplatePath()
: ID(0)
{}
SScriptTemplatePath(u32 InID, const TString& kInPath, CScriptTemplate* pInTemplate)
: ID(InID)
, Path(kInPath)
, pTemplate( std::shared_ptr<CScriptTemplate>(pInTemplate) )
{}
SScriptTemplatePath(const CFourCC& kInID, const TString& kInPath, CScriptTemplate* pInTemplate)
: ID(kInID)
, Path(kInPath)
, pTemplate( std::shared_ptr<CScriptTemplate>(pInTemplate) )
{}
/** Serializer */
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("ID", ID, SH_Attribute)
<< SerialParameter("Path", Path, SH_Attribute);
}
};
/** Struct holding a reference to a property template */
struct SPropertyTemplatePath
{
/** File path to the template file, relative to the game directory */
TString Path;
/** Template in memory */
std::shared_ptr<IPropertyNew> pTemplate;
/** Constructor */
SPropertyTemplatePath()
{}
SPropertyTemplatePath(const TString& kInPath, IPropertyNew* pInTemplate)
: Path(kInPath)
, pTemplate( std::shared_ptr<IPropertyNew>(pInTemplate) )
{}
/** Serializer */
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("Path", Path, SH_Attribute);
}
};
EGame mGame;
TString mGameName;
TString mSourceFile;
u32 mVersion;
bool mFullyLoaded;
std::vector<TString> mGameVersions;
std::map<TString, CStructPropertyNew*> mStructTemplates;
std::map<TString, CEnumProperty*> mEnumTemplates;
std::map<TString, CFlagsProperty*> mFlagsTemplates;
/** Template arrays */
std::map<SObjId, SScriptTemplatePath> mScriptTemplates;
std::map<TString, SPropertyTemplatePath> mStructTemplates;
std::map<TString, SPropertyTemplatePath> mEnumTemplates;
std::map<TString, SPropertyTemplatePath> mFlagsTemplates;
std::map<u32, CScriptTemplate*> mTemplates;
std::map<u32, SState> mStates;
std::map<u32, SMessage> mMessages;
std::map<SObjId, TString> mStates;
std::map<SObjId, TString> mMessages;
struct SPropIDInfo
{
@ -40,7 +128,9 @@ class CMasterTemplate
public:
CMasterTemplate();
~CMasterTemplate();
void Serialize(IArchive& Arc);
void LoadSubTemplates();
void SaveSubTemplates();
u32 GameVersion(TString VersionName);
CScriptTemplate* TemplateByID(u32 ObjectID);
CScriptTemplate* TemplateByID(const CFourCC& ObjectID);
@ -51,13 +141,15 @@ public:
SMessage MessageByID(u32 MessageID);
SMessage MessageByID(const CFourCC& MessageID);
SMessage MessageByIndex(u32 Index);
CStructPropertyNew* StructAtSource(const TString& rkSource);
CStructPropertyNew* FindStructArchetype(const TString& kStructName) const;
CEnumProperty* FindEnumArchetype(const TString& kEnumName) const;
CFlagsProperty* FindFlagsArchetype(const TString& kFlagsName) const;
// Inline Accessors
inline EGame Game() const { return mGame; }
inline TString GameName() const { return mGameName; }
inline u32 NumGameVersions() const { return mGameVersions.empty() ? 1 : mGameVersions.size(); }
inline u32 NumScriptTemplates() const { return mTemplates.size(); }
inline u32 NumScriptTemplates() const { return mScriptTemplates.size(); }
inline u32 NumStates() const { return mStates.size(); }
inline u32 NumMessages() const { return mMessages.size(); }
inline bool IsLoadedSuccessfully() { return mFullyLoaded; }

View File

@ -8,6 +8,7 @@
#include <iostream>
#include <string>
// Old constructor
CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster)
: mpMaster(pMaster)
, mpProperties(nullptr)
@ -24,10 +25,58 @@ CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster)
{
}
// New constructor
CScriptTemplate::CScriptTemplate(CMasterTemplate* pInMaster, u32 InObjectID, const TString& kInFilePath)
: mRotationType(eRotationEnabled)
, mScaleType(eScaleEnabled)
, mPreviewScale(1.f)
, mVolumeShape(eNoShape)
, mVolumeScale(1.f)
, mSourceFile(kInFilePath)
, mObjectID(InObjectID)
, mpMaster(pInMaster)
, mpNameProperty(nullptr)
, mpPositionProperty(nullptr)
, mpRotationProperty(nullptr)
, mpScaleProperty(nullptr)
, mpActiveProperty(nullptr)
, mpLightParametersProperty(nullptr)
, mVisible(true)
{
}
CScriptTemplate::~CScriptTemplate()
{
}
void CScriptTemplate::Serialize(IArchive& Arc)
{
Arc << SerialParameter("Modules", mModules, SH_Optional)
<< SerialParameter("Properties", mpProperties);
if (Arc.ParamBegin("EditorProperties", 0))
{
Arc << SerialParameter("NameProperty", mNameIDString, SH_Optional)
<< SerialParameter("PositionProperty", mPositionIDString, SH_Optional)
<< SerialParameter("RotationProperty", mRotationIDString, SH_Optional)
<< SerialParameter("ScaleProperty", mScaleIDString, SH_Optional)
<< SerialParameter("ActiveProperty", mActiveIDString, SH_Optional)
<< SerialParameter("LightParametersProperty", mLightParametersIDString, SH_Optional);
Arc.ParamEnd();
}
Arc << SerialParameter("Assets", mAssets, SH_Optional)
<< SerialParameter("Attachments", mAttachments, SH_Optional)
<< SerialParameter("RotationType", mRotationType, SH_Optional, eRotationEnabled)
<< SerialParameter("ScaleType", mScaleType, SH_Optional, eScaleEnabled)
<< SerialParameter("PreviewScale", mPreviewScale, SH_Optional, 1.0f)
<< SerialParameter("VolumeShape", mVolumeShape, SH_Optional, eNoShape)
<< SerialParameter("VolumeScale", mVolumeScale, SH_Optional, 1.0f)
<< SerialParameter("VolumeConditionProperty", mVolumeConditionIDString, SH_Optional)
<< SerialParameter("VolumeConditions", mVolumeConditions, SH_Optional);
}
void CScriptTemplate::PostLoad()
{
if (!mNameIDString.IsEmpty()) mpNameProperty = TPropCast<CStringProperty>( mpProperties->ChildByIDString(mNameIDString) );

View File

@ -26,6 +26,13 @@ struct SAttachment
TIDString AttachProperty; // Must point to a CMDL!
TString LocatorName;
EAttachType AttachType;
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("AttachProperty", AttachProperty, SH_Attribute)
<< SerialParameter("LocatorName", LocatorName, SH_Attribute)
<< SerialParameter("AttachType", AttachType, SH_Attribute);
}
};
/*
@ -52,41 +59,28 @@ public:
private:
struct SEditorAsset
{
enum {
enum EAssetType {
eModel, eAnimParams, eBillboard, eCollision
} AssetType;
enum {
enum EAssetSource {
eProperty, eFile
} AssetSource;
TIDString AssetLocation;
s32 ForceNodeIndex; // Force animsets to use specific node instead of one from property
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("Type", AssetType, SH_Attribute)
<< SerialParameter("Source", AssetSource, SH_Attribute)
<< SerialParameter("Location", AssetLocation, SH_Attribute)
<< SerialParameter("ForceCharacterIndex", ForceNodeIndex, SH_Attribute | SH_Optional, (s32) -1);
}
};
CMasterTemplate* mpMaster;
std::unique_ptr<CStructPropertyNew> mpProperties;
std::list<CScriptObject*> mObjectList;
std::vector<TString> mModules;
TString mSourceFile;
u32 mObjectID;
bool mVisible;
// Editor Properties
TIDString mNameIDString;
TIDString mPositionIDString;
TIDString mRotationIDString;
TIDString mScaleIDString;
TIDString mActiveIDString;
TIDString mLightParametersIDString;
CStringProperty* mpNameProperty;
CVectorProperty* mpPositionProperty;
CVectorProperty* mpRotationProperty;
CVectorProperty* mpScaleProperty;
CBoolProperty* mpActiveProperty;
CStructPropertyNew* mpLightParametersProperty;
std::unique_ptr<CStructPropertyNew> mpProperties;
std::vector<SEditorAsset> mAssets;
std::vector<SAttachment> mAttachments;
@ -99,15 +93,47 @@ private:
float mVolumeScale;
TIDString mVolumeConditionIDString;
TString mSourceFile;
u32 mObjectID;
// Editor Properties
TIDString mNameIDString;
TIDString mPositionIDString;
TIDString mRotationIDString;
TIDString mScaleIDString;
TIDString mActiveIDString;
TIDString mLightParametersIDString;
CMasterTemplate* mpMaster;
std::list<CScriptObject*> mObjectList;
CStringProperty* mpNameProperty;
CVectorProperty* mpPositionProperty;
CVectorProperty* mpRotationProperty;
CVectorProperty* mpScaleProperty;
CBoolProperty* mpActiveProperty;
CStructPropertyNew* mpLightParametersProperty;
struct SVolumeCondition {
int Value;
u32 Value;
EVolumeShape Shape;
float Scale;
void Serialize(IArchive& Arc)
{
Arc << SerialParameter("Value", Value)
<< SerialParameter("Shape", Shape)
<< SerialParameter("Scale", Scale, SH_Optional, 1.0f);
}
};
std::vector<SVolumeCondition> mVolumeConditions;
bool mVisible;
public:
// Old constructor
CScriptTemplate(CMasterTemplate *pMaster);
// New constructor
CScriptTemplate(CMasterTemplate* pMaster, u32 ObjectID, const TString& kFilePath);
~CScriptTemplate();
void Serialize(IArchive& rArc);
void PostLoad();
@ -133,11 +159,11 @@ public:
const SAttachment& Attachment(u32 Index) const { return mAttachments[Index]; }
const std::vector<TString>& RequiredModules() const { return mModules; }
inline CStringProperty* NameProperty() const { return mpNameProperty; }
inline CVectorProperty* PositionProperty() const { return mpPositionProperty; }
inline CVectorProperty* RotationProperty() const { return mpRotationProperty; }
inline CVectorProperty* ScaleProperty() const { return mpScaleProperty; }
inline CBoolProperty* ActiveProperty() const { return mpActiveProperty; }
inline CStringProperty* NameProperty() const { return mpNameProperty; }
inline CVectorProperty* PositionProperty() const { return mpPositionProperty; }
inline CVectorProperty* RotationProperty() const { return mpRotationProperty; }
inline CVectorProperty* ScaleProperty() const { return mpScaleProperty; }
inline CBoolProperty* ActiveProperty() const { return mpActiveProperty; }
inline CStructPropertyNew* LightParametersProperty() const { return mpLightParametersProperty; }
inline void SetVisible(bool Visible) { mVisible = Visible; }

View File

@ -93,14 +93,14 @@ void* IPropertyNew::GetChildDataPointer(void* pPropertyData) const
void IPropertyNew::Serialize(IArchive& rArc)
{
if (rArc.Game() <= ePrime)
if (rArc.Game() <= ePrime && !IsArchetype())
{
rArc << SerialParameter("Name", mName);
}
rArc << SerialParameter("ID", mID, SH_HexDisplay | SH_Optional, (u32) 0xFFFFFFFF)
rArc << SerialParameter("ID", mID, SH_HexDisplay | SH_Attribute | SH_Optional, (u32) 0xFFFFFFFF)
<< SerialParameter("Description", mDescription, SH_Optional)
<< SerialParameter("CookPref", mCookPreference, SH_Optional, ECookPreferenceNew::Default)
<< SerialParameter("CookPreference", mCookPreference, SH_Optional, ECookPreferenceNew::Default)
<< SerialParameter("MinVersion", mMinVersion, SH_Optional, 0.f)
<< SerialParameter("MaxVersion", mMaxVersion, SH_Optional, FLT_MAX);

View File

@ -376,7 +376,7 @@ protected:
public:
virtual void Serialize(IArchive& rArc)
{
IPropertyNew::Serialize(rArc);
TTypedPropertyNew::Serialize(rArc);
// Determine if default value should be serialized as optional.
// All MP1 properties should be optional. For MP2 and on, we set optional
@ -436,14 +436,14 @@ protected:
public:
virtual void Serialize(IArchive& rArc)
{
TTypedPropertyNew::Serialize(rArc);
TSerializeableTypedProperty::Serialize(rArc);
rArc << SerialParameter("Min", mMinValue, SH_Optional, (PropType) -1)
<< SerialParameter("Max", mMaxValue, SH_Optional, (PropType) -1);
}
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
TSerializeableTypedProperty::InitFromArchetype(pOther);
TNumericalPropertyNew* pCastOther = static_cast<TNumericalPropertyNew*>(pOther);
mMinValue = pCastOther->mMinValue;
mMaxValue = pCastOther->mMaxValue;
@ -451,7 +451,7 @@ public:
virtual void PropertyValueChanged(void* pPropertyData)
{
IPropertyNew::PropertyValueChanged(pPropertyData);
TSerializeableTypedProperty::PropertyValueChanged(pPropertyData);
if (mMinValue >= 0 && mMaxValue >= 0)
{

View File

@ -122,16 +122,17 @@ typedef TEnumPropertyBase<EPropertyTypeNew::Enum> CEnumProperty;
template<>
inline CEnumProperty* TPropCast(IPropertyNew* pProperty)
{
EPropertyTypeNew InType = pProperty->Type();
if (pProperty)
{
EPropertyTypeNew InType = pProperty->Type();
if (InType == EPropertyTypeNew::Enum || InType == EPropertyTypeNew::Choice)
{
return static_cast<CEnumProperty*>(pProperty);
}
else
{
return nullptr;
if (InType == EPropertyTypeNew::Enum || InType == EPropertyTypeNew::Choice)
{
return static_cast<CEnumProperty*>(pProperty);
}
}
return nullptr;
}
template<>

View File

@ -128,24 +128,38 @@ void CTemplateEditDialog::ApplyChanges()
// ************ PROTECTED ************
void CTemplateEditDialog::AddTemplate(IPropertyNew* pProp)
{
TString Source = pProp->GetTemplateFileName();
IPropertyNew* pArchetype = pProp->Archetype();
if (!Source.IsEmpty())
if (pArchetype)
{
CStructPropertyNew* pStruct = CMasterTemplate::MasterForGame(pProp->Game())->StructAtSource(Source);
pArchetype = pArchetype->RootParent();
if (!mStructTemplatesToResave.contains(pStruct))
mStructTemplatesToResave << pStruct;
switch (pArchetype->Type())
{
case EPropertyTypeNew::Struct:
{
CStructPropertyNew* pStruct = TPropCast<CStructPropertyNew>(pArchetype);
if (!mStructTemplatesToResave.contains(pStruct))
{
mStructTemplatesToResave << pStruct;
}
break;
}
default:
Log::Warning("Couldn't resave unsupported property archetype: " + TString( EnumValueName(pArchetype->Type()) ));
break;
}
}
else
{
CScriptTemplate *pScript = pProp->ScriptTemplate();
if (pScript)
if (pScript && !mScriptTemplatesToResave.contains(pScript))
{
if (!mScriptTemplatesToResave.contains(pScript))
mScriptTemplatesToResave << pScript;
mScriptTemplatesToResave << pScript;
}
else