mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-14 23:56:23 +00:00
Changed EGame to an enum class. Created NGameList and NPropertyMap to change how templates are managed/saved/loaded. Added support for property map keeping track of ID/type pairs.
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
#include "CGameTemplate.h"
|
||||
#include "NPropertyMap.h"
|
||||
#include "Core/Resource/Factory/CWorldLoader.h"
|
||||
#include <Common/Log.h>
|
||||
|
||||
CGameTemplate::CGameTemplate()
|
||||
: mFullyLoaded(false)
|
||||
, mDirty(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,35 +17,57 @@ void CGameTemplate::Serialize(IArchive& Arc)
|
||||
<< SerialParameter("Messages", mMessages);
|
||||
}
|
||||
|
||||
void CGameTemplate::LoadSubTemplates()
|
||||
void CGameTemplate::Load(const TString& kFilePath)
|
||||
{
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
Internal_LoadScriptTemplate( Iter->second );
|
||||
|
||||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
Internal_LoadPropertyTemplate( Iter->second );
|
||||
}
|
||||
|
||||
void CGameTemplate::Internal_LoadScriptTemplate(SScriptTemplatePath& Path)
|
||||
{
|
||||
ASSERT(Path.pTemplate == nullptr); // make sure it hasn't been loaded yet
|
||||
|
||||
const TString kGameDir = GetGameDirectory(true);
|
||||
const TString kTemplateFilePath = kGameDir + Path.Path;
|
||||
CXMLReader Reader(kTemplateFilePath);
|
||||
CXMLReader Reader(kFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
Path.pTemplate = std::make_shared<CScriptTemplate>(this, Path.ID.ID, Path.Path);
|
||||
Path.pTemplate->Serialize(Reader);
|
||||
Path.pTemplate->PostLoad();
|
||||
mGame = Reader.Game();
|
||||
Serialize(Reader);
|
||||
|
||||
mSourceFile = kFilePath;
|
||||
mFullyLoaded = true;
|
||||
|
||||
// Load all sub-templates
|
||||
const TString gkGameRoot = GetGameDirectory();
|
||||
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
{
|
||||
SScriptTemplatePath& ScriptPath = Iter->second;
|
||||
TString AbsPath = gkGameRoot + ScriptPath.Path;
|
||||
ScriptPath.pTemplate = std::make_shared<CScriptTemplate>(this, ScriptPath.ID, AbsPath);
|
||||
}
|
||||
|
||||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
{
|
||||
// For properties, remember that property archetypes can reference other archetypes which
|
||||
// may not be loaded yet.. so if this happens, the referenced property will be loaded,
|
||||
// meaning property templates can be loaded out of order, so we need to make sure
|
||||
// that we don't load any template more than once.
|
||||
SPropertyTemplatePath& PropertyPath = Iter->second;
|
||||
|
||||
if (!PropertyPath.pTemplate)
|
||||
{
|
||||
Internal_LoadPropertyTemplate(Iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTemplate::Save()
|
||||
{
|
||||
CXMLWriter Writer(mSourceFile, "Game", 0, mGame);
|
||||
ASSERT(Writer.IsValid());
|
||||
Serialize(Writer);
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
/** Internal function for loading a property template from a file. */
|
||||
void CGameTemplate::Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path)
|
||||
{
|
||||
if (Path.pTemplate != nullptr) // don't load twice
|
||||
return;
|
||||
|
||||
const TString kGameDir = GetGameDirectory(true);
|
||||
const TString kGameDir = GetGameDirectory();
|
||||
const TString kTemplateFilePath = kGameDir + Path.Path;
|
||||
CXMLReader Reader(kTemplateFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
@@ -51,44 +75,49 @@ void CGameTemplate::Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path)
|
||||
Reader << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
ASSERT(Path.pTemplate != nullptr);
|
||||
|
||||
Path.pTemplate->SetPropertyFlags( EPropertyFlag::IsArchetype );
|
||||
Path.pTemplate->Initialize(nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
void CGameTemplate::SaveSubTemplates()
|
||||
void CGameTemplate::SaveGameTemplates(bool ForceAll /*= false*/)
|
||||
{
|
||||
const TString kGameDir = GetGameDirectory(true);
|
||||
const TString kGameDir = GetGameDirectory();
|
||||
|
||||
if (mDirty || ForceAll)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
{
|
||||
SScriptTemplatePath& Path = Iter->second;
|
||||
TString OutPath = kGameDir + Path.Path;
|
||||
|
||||
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
|
||||
CXMLWriter Writer(OutPath, "ScriptObject", 0, Game());
|
||||
Path.pTemplate->Serialize(Writer);
|
||||
if( Path.pTemplate )
|
||||
{
|
||||
Path.pTemplate->Save(ForceAll);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
{
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
TString OutPath = kGameDir + Path.Path;
|
||||
|
||||
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
|
||||
CXMLWriter Writer(OutPath, "PropertyTemplate", 0, Game());
|
||||
Writer << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
if( Path.pTemplate )
|
||||
{
|
||||
if( ForceAll || Path.pTemplate->IsDirty() )
|
||||
{
|
||||
const TString kOutPath = kGameDir + Path.Path;
|
||||
FileUtil::MakeDirectory( kOutPath.GetFileDirectory() );
|
||||
|
||||
CXMLWriter Writer(kOutPath, "PropertyTemplate", 0, Game());
|
||||
ASSERT(Writer.IsValid());
|
||||
|
||||
Writer << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
Path.pTemplate->ClearDirtyFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTemplate::SaveScriptTemplate(CScriptTemplate* pTemplate)
|
||||
{
|
||||
ASSERT( pTemplate->GameTemplate() == this );
|
||||
}
|
||||
|
||||
void CGameTemplate::SavePropertyTemplate(IProperty* pProperty)
|
||||
{
|
||||
}
|
||||
|
||||
u32 CGameTemplate::GameVersion(TString VersionName)
|
||||
{
|
||||
return -1;
|
||||
@@ -162,9 +191,8 @@ SMessage CGameTemplate::MessageByIndex(u32 Index)
|
||||
IProperty* CGameTemplate::FindPropertyArchetype(const TString& kTypeName)
|
||||
{
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
ASSERT(Iter != mPropertyTemplates.end()); // Requested archetype property does not exist; missing or malformed template
|
||||
|
||||
// Should require Iter to be valid in the future. For now, this is possible for some of the transition template loader code.
|
||||
// ASSERT(Iter != mPropertyTemplates.end()); // Requested archetype property does not exist; missing or malformed template
|
||||
if (Iter == mPropertyTemplates.end())
|
||||
{
|
||||
return nullptr;
|
||||
@@ -183,200 +211,14 @@ IProperty* CGameTemplate::FindPropertyArchetype(const TString& kTypeName)
|
||||
return Path.pTemplate.get();
|
||||
}
|
||||
|
||||
TString CGameTemplate::GetGameDirectory(bool Absolute) const
|
||||
TString CGameTemplate::GetPropertyArchetypeFilePath(const TString& kTypeName)
|
||||
{
|
||||
TString Out = mSourceFile.GetFileDirectory();
|
||||
return Absolute ? "../templates_new/" + Out : Out;
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
ASSERT(Iter != mPropertyTemplates.end());
|
||||
return GetGameDirectory() + Iter->second.Path;
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
CGameTemplate* CGameTemplate::GetGameTemplate(EGame Game)
|
||||
TString CGameTemplate::GetGameDirectory() const
|
||||
{
|
||||
auto it = smGameMap.find(Game);
|
||||
|
||||
if (it != smGameMap.end())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
return mSourceFile.GetFileDirectory();
|
||||
}
|
||||
|
||||
std::list<CGameTemplate*> CGameTemplate::GameTemplateList()
|
||||
{
|
||||
std::list<CGameTemplate*> list;
|
||||
|
||||
for (auto it = smGameMap.begin(); it != smGameMap.end(); it++)
|
||||
list.push_back(it->second);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
TString CGameTemplate::FindGameName(EGame Game)
|
||||
{
|
||||
CGameTemplate *pGame = GetGameTemplate(Game);
|
||||
return pGame ? pGame->GameName() : "Unknown Game";
|
||||
}
|
||||
|
||||
EGame CGameTemplate::FindGameForName(const TString& rkName)
|
||||
{
|
||||
std::list<CGameTemplate*> Games = GameTemplateList();
|
||||
|
||||
for (auto It = Games.begin(); It != Games.end(); It++)
|
||||
{
|
||||
CGameTemplate *pGame = *It;
|
||||
if (pGame->GameName() == rkName)
|
||||
return pGame->Game();
|
||||
}
|
||||
|
||||
return eUnknownGame;
|
||||
}
|
||||
|
||||
TString CGameTemplate::PropertyName(u32 PropertyID)
|
||||
{
|
||||
auto it = smPropertyNames.find(PropertyID);
|
||||
|
||||
if (it != smPropertyNames.end())
|
||||
return it->second;
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
// Removing these functions for now. I'm not sure of the best way to go about implementing them under the new system yet.
|
||||
u32 CGameTemplate::CreatePropertyID(IProperty* pProp)
|
||||
{
|
||||
// MP1 properties don't have IDs so we can use this function to create one to track instances of a particular property.
|
||||
// To ensure the IDs are unique we'll create a hash using two things: the struct source file and the ID string (relative to the struct).
|
||||
//
|
||||
// Note for properties that have accurate names we can apply a CRC32 to the name to generate a hash equivalent to what the hash would
|
||||
// have been if this were an MP2/3 property. In an ideal world where every property was named, this would be great. However, we have a
|
||||
// lot of properties that have generic names like "Unknown", and they should be tracked separately as they are in all likelihood
|
||||
// different properties. So for this reason, we only want to track sub-instances of one property under one ID.
|
||||
TString IDString = pProp->Archetype()->IDString(true);
|
||||
TString TemplateFile = pProp->GetTemplateFileName();
|
||||
|
||||
CCRC32 Hash;
|
||||
Hash.Hash(*IDString);
|
||||
Hash.Hash(*TemplateFile);
|
||||
return Hash.Digest();
|
||||
}
|
||||
|
||||
void CGameTemplate::AddProperty(IProperty* pProp, const TString& rkTemplateName /*= ""*/)
|
||||
{
|
||||
u32 ID;
|
||||
|
||||
if (pProp->Game() >= eEchoesDemo)
|
||||
ID = pProp->ID();
|
||||
|
||||
// Use a different ID for MP1
|
||||
else
|
||||
{
|
||||
// For MP1 we only really need to track properties that come from struct templates.
|
||||
IProperty* pArchetype = pProp->Archetype();
|
||||
|
||||
if (!pArchetype ||
|
||||
pArchetype->ScriptTemplate() != nullptr ||
|
||||
pArchetype->RootParent()->Type() != EPropertyType::Struct)
|
||||
return;
|
||||
|
||||
ID = CreatePropertyID(pProp);
|
||||
}
|
||||
|
||||
auto it = smIDMap.find(ID);
|
||||
|
||||
// Add this property/template to existing ID info
|
||||
if (it != smIDMap.end())
|
||||
{
|
||||
SPropIDInfo& rInfo = it->second;
|
||||
rInfo.PropertyList.push_back(pProp);
|
||||
|
||||
if (!rkTemplateName.IsEmpty())
|
||||
{
|
||||
bool NewTemplate = true;
|
||||
|
||||
for (u32 iTemp = 0; iTemp < rInfo.XMLList.size(); iTemp++)
|
||||
{
|
||||
if (rInfo.XMLList[iTemp] == rkTemplateName)
|
||||
{
|
||||
NewTemplate = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NewTemplate)
|
||||
rInfo.XMLList.push_back(rkTemplateName);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new ID info
|
||||
else
|
||||
{
|
||||
SPropIDInfo Info;
|
||||
if (!rkTemplateName.IsEmpty()) Info.XMLList.push_back(rkTemplateName);
|
||||
Info.PropertyList.push_back(pProp);
|
||||
smIDMap[ID] = Info;
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTemplate::RenameProperty(IProperty* pProp, const TString& rkNewName)
|
||||
{
|
||||
u32 ID = pProp->ID();
|
||||
if (ID <= 0xFF) ID = CreatePropertyID(pProp);
|
||||
RenameProperty(ID, rkNewName);
|
||||
}
|
||||
|
||||
void CGameTemplate::RenameProperty(u32 ID, const TString& rkNewName)
|
||||
{
|
||||
// Game name list
|
||||
auto NameIt = smPropertyNames.find(ID);
|
||||
TString Original;
|
||||
|
||||
if (NameIt != smPropertyNames.end())
|
||||
{
|
||||
Original = NameIt->second;
|
||||
smPropertyNames[ID] = rkNewName;
|
||||
}
|
||||
|
||||
// Properties
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
|
||||
for (u32 PropertyIdx = 0; PropertyIdx < rkInfo.PropertyList.size(); PropertyIdx++)
|
||||
{
|
||||
if (Original.IsEmpty() || rkInfo.PropertyList[PropertyIdx]->Name() == Original)
|
||||
rkInfo.PropertyList[PropertyIdx]->SetName(rkNewName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameTemplate::XMLsUsingID(u32 ID, std::vector<TString>& rOutList)
|
||||
{
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
rOutList = rkInfo.XMLList;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<IProperty*>* CGameTemplate::TemplatesWithMatchingID(IProperty* pProp)
|
||||
{
|
||||
u32 ID = pProp->ID();
|
||||
if (ID <= 0xFF) ID = CreatePropertyID(pProp);
|
||||
|
||||
auto InfoIt = smIDMap.find(ID);
|
||||
|
||||
if (InfoIt != smIDMap.end())
|
||||
{
|
||||
const SPropIDInfo& rkInfo = InfoIt->second;
|
||||
return &rkInfo.PropertyList;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::map<u32, CGameTemplate::SPropIDInfo> CGameTemplate::smIDMap;
|
||||
std::map<EGame, CGameTemplate*> CGameTemplate::smGameMap;
|
||||
std::map<u32, TString> CGameTemplate::smPropertyNames;
|
||||
u32 CGameTemplate::smGameListVersion;
|
||||
|
||||
@@ -28,84 +28,85 @@ struct SObjId
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= ePrime)
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc.SerializePrimitive(ID, SH_HexDisplay);
|
||||
else
|
||||
Arc.SerializePrimitive(ID_4CC, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/** 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<IProperty> pTemplate;
|
||||
|
||||
/** Constructor */
|
||||
SPropertyTemplatePath()
|
||||
{}
|
||||
|
||||
SPropertyTemplatePath(const TString& kInPath, IProperty* pInTemplate)
|
||||
: Path(kInPath)
|
||||
, pTemplate( std::shared_ptr<IProperty>(pInTemplate) )
|
||||
{}
|
||||
|
||||
/** Serializer */
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Path", Path, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
/** CGameTemplate - Per-game template data */
|
||||
class CGameTemplate
|
||||
{
|
||||
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<IProperty> pTemplate;
|
||||
|
||||
/** Constructor */
|
||||
SPropertyTemplatePath()
|
||||
{}
|
||||
|
||||
SPropertyTemplatePath(const TString& kInPath, IProperty* pInTemplate)
|
||||
: Path(kInPath)
|
||||
, pTemplate( std::shared_ptr<IProperty>(pInTemplate) )
|
||||
{}
|
||||
|
||||
/** Serializer */
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
Arc << SerialParameter("Path", Path, SH_Attribute);
|
||||
}
|
||||
};
|
||||
|
||||
EGame mGame;
|
||||
TString mGameName;
|
||||
TString mSourceFile;
|
||||
bool mFullyLoaded;
|
||||
bool mDirty;
|
||||
|
||||
/** Template arrays */
|
||||
std::map<SObjId, SScriptTemplatePath> mScriptTemplates;
|
||||
@@ -114,26 +115,16 @@ class CGameTemplate
|
||||
std::map<SObjId, TString> mStates;
|
||||
std::map<SObjId, TString> mMessages;
|
||||
|
||||
struct SPropIDInfo
|
||||
{
|
||||
std::vector<TString> XMLList; // List of script/struct templates that use this ID
|
||||
std::vector<IProperty*> PropertyList; // List of all properties that use this ID
|
||||
};
|
||||
static std::map<u32, SPropIDInfo> smIDMap;
|
||||
static std::map<EGame, CGameTemplate*> smGameMap;
|
||||
static std::map<u32, TString> smPropertyNames;
|
||||
static u32 smGameListVersion;
|
||||
|
||||
void Internal_LoadScriptTemplate(SScriptTemplatePath& Path);
|
||||
/** Internal function for loading a property template from a file. */
|
||||
void Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path);
|
||||
|
||||
public:
|
||||
CGameTemplate();
|
||||
void Serialize(IArchive& Arc);
|
||||
void LoadSubTemplates();
|
||||
void SaveSubTemplates();
|
||||
void SaveScriptTemplate(CScriptTemplate* pTemplate);
|
||||
void SavePropertyTemplate(IProperty* pProperty);
|
||||
void Load(const TString& kFilePath);
|
||||
void Save();
|
||||
void SaveGameTemplates(bool ForceAll = false);
|
||||
|
||||
u32 GameVersion(TString VersionName);
|
||||
CScriptTemplate* TemplateByID(u32 ObjectID);
|
||||
CScriptTemplate* TemplateByID(const CFourCC& ObjectID);
|
||||
@@ -145,28 +136,15 @@ public:
|
||||
SMessage MessageByID(const CFourCC& MessageID);
|
||||
SMessage MessageByIndex(u32 Index);
|
||||
IProperty* FindPropertyArchetype(const TString& kTypeName);
|
||||
TString GetGameDirectory(bool Absolute = false) const;
|
||||
TString GetPropertyArchetypeFilePath(const TString& kTypeName);
|
||||
TString GetGameDirectory() const;
|
||||
|
||||
// Inline Accessors
|
||||
inline EGame Game() const { return mGame; }
|
||||
inline TString GameName() const { return mGameName; }
|
||||
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; }
|
||||
|
||||
// Static
|
||||
static CGameTemplate* GetGameTemplate(EGame Game);
|
||||
static std::list<CGameTemplate*> GameTemplateList();
|
||||
static TString FindGameName(EGame Game);
|
||||
static EGame FindGameForName(const TString& rkName);
|
||||
static TString PropertyName(u32 PropertyID);
|
||||
static u32 CreatePropertyID(IProperty *pTemp);
|
||||
static void AddProperty(IProperty *pTemp, const TString& rkTemplateName = "");
|
||||
static void RenameProperty(IProperty *pTemp, const TString& rkNewName);
|
||||
static void RenameProperty(u32 ID, const TString& rkNewName);
|
||||
static void XMLsUsingID(u32 ID, std::vector<TString>& rOutList);
|
||||
static const std::vector<IProperty*>* TemplatesWithMatchingID(IProperty *pTemp);
|
||||
};
|
||||
|
||||
#endif // CGAMETEMPLATE_H
|
||||
|
||||
@@ -24,7 +24,7 @@ struct SState
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= ePrime)
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
|
||||
else
|
||||
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
|
||||
@@ -51,7 +51,7 @@ struct SMessage
|
||||
|
||||
void Serialize(IArchive& Arc)
|
||||
{
|
||||
if (Arc.Game() <= ePrime)
|
||||
if (Arc.Game() <= EGame::Prime)
|
||||
Arc << SerialParameter("ID", ID, SH_Attribute | SH_HexDisplay);
|
||||
else
|
||||
Arc << SerialParameter("ID", ID_4CC, SH_Attribute);
|
||||
|
||||
@@ -13,6 +13,7 @@ CScriptTemplate::CScriptTemplate(CGameTemplate *pGame)
|
||||
: mpGame(pGame)
|
||||
, mpProperties(nullptr)
|
||||
, mVisible(true)
|
||||
, mDirty(false)
|
||||
, mpNameProperty(nullptr)
|
||||
, mpPositionProperty(nullptr)
|
||||
, mpRotationProperty(nullptr)
|
||||
@@ -42,7 +43,23 @@ CScriptTemplate::CScriptTemplate(CGameTemplate* pInGame, u32 InObjectID, const T
|
||||
, mpActiveProperty(nullptr)
|
||||
, mpLightParametersProperty(nullptr)
|
||||
, mVisible(true)
|
||||
, mDirty(false)
|
||||
{
|
||||
// Load
|
||||
CXMLReader Reader(kInFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
Serialize(Reader);
|
||||
|
||||
// Post load initialization
|
||||
mSourceFile = kInFilePath;
|
||||
mpProperties->Initialize(nullptr, this, 0);
|
||||
|
||||
if (!mNameIDString.IsEmpty()) mpNameProperty = TPropCast<CStringProperty>( mpProperties->ChildByIDString(mNameIDString) );
|
||||
if (!mPositionIDString.IsEmpty()) mpPositionProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mPositionIDString) );
|
||||
if (!mRotationIDString.IsEmpty()) mpRotationProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mRotationIDString) );
|
||||
if (!mScaleIDString.IsEmpty()) mpScaleProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mScaleIDString) );
|
||||
if (!mActiveIDString.IsEmpty()) mpActiveProperty = TPropCast<CBoolProperty>( mpProperties->ChildByIDString(mActiveIDString) );
|
||||
if (!mLightParametersIDString.IsEmpty()) mpLightParametersProperty = TPropCast<CStructProperty>( mpProperties->ChildByIDString(mLightParametersIDString) );
|
||||
}
|
||||
|
||||
CScriptTemplate::~CScriptTemplate()
|
||||
@@ -77,16 +94,15 @@ void CScriptTemplate::Serialize(IArchive& Arc)
|
||||
<< SerialParameter("VolumeConditions", mVolumeConditions, SH_Optional);
|
||||
}
|
||||
|
||||
void CScriptTemplate::PostLoad()
|
||||
void CScriptTemplate::Save(bool Force)
|
||||
{
|
||||
mpProperties->Initialize(nullptr, this, 0);
|
||||
|
||||
if (!mNameIDString.IsEmpty()) mpNameProperty = TPropCast<CStringProperty>( mpProperties->ChildByIDString(mNameIDString) );
|
||||
if (!mPositionIDString.IsEmpty()) mpPositionProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mPositionIDString) );
|
||||
if (!mRotationIDString.IsEmpty()) mpRotationProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mRotationIDString) );
|
||||
if (!mScaleIDString.IsEmpty()) mpScaleProperty = TPropCast<CVectorProperty>( mpProperties->ChildByIDString(mScaleIDString) );
|
||||
if (!mActiveIDString.IsEmpty()) mpActiveProperty = TPropCast<CBoolProperty>( mpProperties->ChildByIDString(mActiveIDString) );
|
||||
if (!mLightParametersIDString.IsEmpty()) mpLightParametersProperty = TPropCast<CStructProperty>( mpProperties->ChildByIDString(mLightParametersIDString) );
|
||||
if (mDirty || Force)
|
||||
{
|
||||
CXMLWriter Writer(mSourceFile, "ScriptObject", 0, mpGame->Game());
|
||||
ASSERT(Writer.IsValid());
|
||||
Serialize(Writer);
|
||||
mDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
EGame CScriptTemplate::Game() const
|
||||
|
||||
@@ -127,6 +127,7 @@ private:
|
||||
};
|
||||
std::vector<SVolumeCondition> mVolumeConditions;
|
||||
bool mVisible;
|
||||
bool mDirty;
|
||||
|
||||
public:
|
||||
// Default constructor. Don't use. This is only here so the serializer doesn't complain
|
||||
@@ -137,7 +138,7 @@ public:
|
||||
CScriptTemplate(CGameTemplate* pGame, u32 ObjectID, const TString& kFilePath);
|
||||
~CScriptTemplate();
|
||||
void Serialize(IArchive& rArc);
|
||||
void PostLoad();
|
||||
void Save(bool Force = false);
|
||||
EGame Game() const;
|
||||
|
||||
// Property Fetching
|
||||
@@ -168,6 +169,8 @@ public:
|
||||
inline CStructProperty* LightParametersProperty() const { return mpLightParametersProperty; }
|
||||
|
||||
inline void SetVisible(bool Visible) { mVisible = Visible; }
|
||||
inline void MarkDirty() { mDirty = true; }
|
||||
inline bool IsDirty() const { return mDirty; }
|
||||
|
||||
// Object Tracking
|
||||
u32 NumObjects() const;
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
|
||||
virtual const char* HashableTypeName() const
|
||||
{
|
||||
return (Game() <= eEchoes ? "AnimationSet" : "CharacterAnimationSet");
|
||||
return (Game() <= EGame::Echoes ? "AnimationSet" : "CharacterAnimationSet");
|
||||
}
|
||||
|
||||
virtual CAnimationParameters GetSerializationDefaultValue()
|
||||
|
||||
@@ -109,11 +109,6 @@ public:
|
||||
{
|
||||
TTypedProperty::Serialize(rArc);
|
||||
rArc << SerialParameter("ItemArchetype", mpItemArchetype);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
mpItemArchetype->SetPropertyFlags( EPropertyFlag::IsArrayArchetype );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
|
||||
@@ -42,9 +42,6 @@ class TEnumPropertyBase : public TSerializeableTypedProperty<s32, TypeEnum>
|
||||
};
|
||||
std::vector<SEnumValue> mValues;
|
||||
|
||||
/** XML template file that this enum originated from; for archetypes */
|
||||
TString mSourceFile;
|
||||
|
||||
protected:
|
||||
/** Constructor */
|
||||
TEnumPropertyBase(EGame Game)
|
||||
@@ -66,7 +63,7 @@ public:
|
||||
TTypedProperty::Serialize(rArc);
|
||||
|
||||
TEnumPropertyBase* pArchetype = static_cast<TEnumPropertyBase*>(mpArchetype);
|
||||
u32 DefaultValueFlags = SH_HexDisplay | (pArchetype || Game() <= ePrime ? SH_Optional : 0);
|
||||
u32 DefaultValueFlags = SH_HexDisplay | (pArchetype || Game() <= EGame::Prime ? SH_Optional : 0);
|
||||
rArc << SerialParameter("DefaultValue", mDefaultValue, DefaultValueFlags, pArchetype ? pArchetype->mDefaultValue : 0);
|
||||
|
||||
if (!pArchetype || !rArc.CanSkipParameters() || mValues != pArchetype->mValues)
|
||||
@@ -87,12 +84,6 @@ public:
|
||||
mValues = pOtherEnum->mValues;
|
||||
}
|
||||
|
||||
virtual TString GetTemplateFileName()
|
||||
{
|
||||
ASSERT(IsArchetype() || mpArchetype);
|
||||
return IsArchetype() ? mSourceFile : mpArchetype->GetTemplateFileName();
|
||||
}
|
||||
|
||||
void AddValue(TString ValueName, u32 ValueID)
|
||||
{
|
||||
mValues.push_back( SEnumValue(ValueName, ValueID) );
|
||||
|
||||
@@ -37,12 +37,6 @@ void CFlagsProperty::InitFromArchetype(IProperty* pOther)
|
||||
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.
|
||||
|
||||
@@ -35,9 +35,6 @@ class CFlagsProperty : public TSerializeableTypedProperty<u32, EPropertyType::Fl
|
||||
std::vector<SBitFlag> mBitFlags;
|
||||
u32 mAllFlags;
|
||||
|
||||
/** XML template file that this enum originated from; for archetypes */
|
||||
TString mSourceFile;
|
||||
|
||||
CFlagsProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
, mAllFlags(0)
|
||||
@@ -65,7 +62,6 @@ public:
|
||||
virtual void PostInitialize();
|
||||
virtual void SerializeValue(void* pData, IArchive& rArc) const;
|
||||
virtual void InitFromArchetype(IProperty* pOther);
|
||||
virtual TString GetTemplateFileName();
|
||||
|
||||
/**
|
||||
* Checks whether there are any unrecognized bits toggled on in the property value.
|
||||
|
||||
@@ -149,6 +149,8 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
|
||||
FullHash.Hash( *rkParams.TypeNames[TypeIdx] );
|
||||
u32 PropertyID = FullHash.Digest();
|
||||
|
||||
//@FIXME
|
||||
#if 0
|
||||
// Check if this hash is a property ID - it's valid if there are any XMLs using this ID
|
||||
SGeneratedPropertyName PropertyName;
|
||||
CGameTemplate::XMLsUsingID(PropertyID, PropertyName.XmlList);
|
||||
@@ -202,6 +204,7 @@ void CPropertyNameGenerator::Generate(const SPropertyNameGenerationParameters& r
|
||||
Log::Write(LogMsg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Every 250 tests, check with the progress notifier. Update the progress
|
||||
|
||||
@@ -6,6 +6,14 @@ EPropertyType CStructProperty::Type() const
|
||||
return EPropertyType::Struct;
|
||||
}
|
||||
|
||||
void CStructProperty::PostInitialize()
|
||||
{
|
||||
IProperty::PostInitialize();
|
||||
|
||||
// All structs should have an archetype.
|
||||
ASSERT( IsRootParent() || mpArchetype != nullptr );
|
||||
}
|
||||
|
||||
u32 CStructProperty::DataSize() const
|
||||
{
|
||||
if (!mChildren.empty())
|
||||
@@ -74,12 +82,9 @@ void CStructProperty::Serialize(IArchive& rArc)
|
||||
bool Atomic = IsAtomic();
|
||||
rArc << SerialParameter("Atomic", Atomic, SH_Optional, false);
|
||||
|
||||
if (rArc.IsReader())
|
||||
if (rArc.IsReader() && Atomic)
|
||||
{
|
||||
if (Atomic)
|
||||
mFlags.SetFlag(EPropertyFlag::IsAtomic);
|
||||
else
|
||||
mFlags.ClearFlag(EPropertyFlag::IsAtomic);
|
||||
mFlags.SetFlag(EPropertyFlag::IsAtomic);
|
||||
}
|
||||
|
||||
// Serialize archetype
|
||||
@@ -187,9 +192,3 @@ bool CStructProperty::ShouldSerialize() const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TString CStructProperty::GetTemplateFileName()
|
||||
{
|
||||
ASSERT(IsArchetype() || mpArchetype);
|
||||
return IsArchetype() ? mTemplateFileName : mpArchetype->GetTemplateFileName();
|
||||
}
|
||||
|
||||
@@ -13,15 +13,13 @@ public:
|
||||
typedef void* ValueType;
|
||||
|
||||
protected:
|
||||
/** For archetypes, the filename of the template XML file. */
|
||||
TString mTemplateFileName;
|
||||
|
||||
CStructProperty(EGame Game)
|
||||
: IProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual EPropertyType Type() const;
|
||||
virtual void PostInitialize();
|
||||
virtual u32 DataSize() const;
|
||||
virtual u32 DataAlignment() const;
|
||||
virtual void Construct(void* pData) const;
|
||||
@@ -33,7 +31,6 @@ public:
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const;
|
||||
virtual void InitFromArchetype(IProperty* pOther);
|
||||
virtual bool ShouldSerialize() const;
|
||||
virtual TString GetTemplateFileName();
|
||||
|
||||
inline static EPropertyType StaticType() { return EPropertyType::Struct; }
|
||||
};
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "Core/Resource/Script/CGameTemplate.h"
|
||||
#include "Core/Resource/Script/CScriptTemplate.h"
|
||||
#include "Core/Resource/Script/NGameList.h"
|
||||
#include "Core/Resource/Script/NPropertyMap.h"
|
||||
|
||||
/** IProperty */
|
||||
IProperty::IProperty(EGame Game)
|
||||
@@ -25,7 +27,15 @@ IProperty::IProperty(EGame Game)
|
||||
void IProperty::_ClearChildren()
|
||||
{
|
||||
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
|
||||
{
|
||||
// Unregister children from the name map. This has to be done before actually deleting them.
|
||||
if (mChildren[ChildIdx]->UsesNameMap())
|
||||
{
|
||||
NPropertyMap::UnregisterProperty(mChildren[ChildIdx]);
|
||||
}
|
||||
|
||||
delete mChildren[ChildIdx];
|
||||
}
|
||||
|
||||
mChildren.clear();
|
||||
}
|
||||
@@ -35,13 +45,17 @@ IProperty::~IProperty()
|
||||
// Remove from archetype
|
||||
if( mpArchetype != nullptr )
|
||||
{
|
||||
// If you crash here, it most likely means this property was not added to the archetype's sub-instances list.
|
||||
NBasics::VectorRemoveOne(mpArchetype->mSubInstances, this);
|
||||
}
|
||||
|
||||
// If this is an archetype, all our sub-instances should have destructed first.
|
||||
// If this is an archetype, make sure no sub-instances have a reference to us.
|
||||
if( IsArchetype() )
|
||||
{
|
||||
ASSERT(mSubInstances.empty());
|
||||
for( int SubIdx = 0; SubIdx < mSubInstances.size(); SubIdx++ )
|
||||
{
|
||||
mSubInstances[SubIdx]->mpArchetype = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete children
|
||||
@@ -72,7 +86,7 @@ void IProperty::Serialize(IArchive& rArc)
|
||||
|
||||
if (rArc.IsReader() && !ArchetypeName.IsEmpty())
|
||||
{
|
||||
CGameTemplate* pGame = CGameTemplate::GetGameTemplate( Game() );
|
||||
CGameTemplate* pGame = NGameList::GetGameTemplate( Game() );
|
||||
IProperty* pArchetype = pGame->FindPropertyArchetype(ArchetypeName);
|
||||
|
||||
// The archetype must exist, or else the template file is malformed.
|
||||
@@ -89,7 +103,7 @@ void IProperty::Serialize(IArchive& rArc)
|
||||
//
|
||||
// We can't currently tell if this property is atomic, as the flag hasn't been serialized and the parent
|
||||
// hasn't been set, but atomic sub-properties don't use hash IDs, so we can do a pseudo-check against the ID.
|
||||
if (rArc.Game() <= ePrime || IsRootParent() || IsArrayArchetype() || mID <= 0xFF)
|
||||
if (rArc.Game() <= EGame::Prime || IsRootParent() || IsArrayArchetype() || mID <= 0xFF)
|
||||
{
|
||||
rArc << SerialParameter("Name", mName, mpArchetype ? SH_Optional : 0, mpArchetype ? mpArchetype->mName : "");
|
||||
}
|
||||
@@ -107,6 +121,8 @@ void IProperty::InitFromArchetype(IProperty* pOther)
|
||||
{
|
||||
//@todo maybe somehow use Serialize for this instead?
|
||||
mpArchetype = pOther;
|
||||
mpArchetype->mSubInstances.push_back(this);
|
||||
|
||||
mFlags = pOther->mFlags & EPropertyFlag::ArchetypeCopyFlags;
|
||||
mName = pOther->mName;
|
||||
mDescription = pOther->mDescription;
|
||||
@@ -133,24 +149,6 @@ bool IProperty::ShouldSerialize() const
|
||||
mMaxVersion != mpArchetype->mMaxVersion;
|
||||
}
|
||||
|
||||
TString IProperty::GetTemplateFileName()
|
||||
{
|
||||
if (mpScriptTemplate)
|
||||
{
|
||||
return mpScriptTemplate->SourceFile();
|
||||
}
|
||||
else if (IsArchetype())
|
||||
{
|
||||
IProperty* pRootParent = RootParent();
|
||||
ASSERT(pRootParent != this);
|
||||
return pRootParent->GetTemplateFileName();
|
||||
}
|
||||
else
|
||||
{
|
||||
return mpArchetype->GetTemplateFileName();
|
||||
}
|
||||
}
|
||||
|
||||
void IProperty::Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u32 InOffset)
|
||||
{
|
||||
// Make sure we only get initialized once.
|
||||
@@ -161,12 +159,6 @@ void IProperty::Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u
|
||||
mOffset = InOffset;
|
||||
mpScriptTemplate = pInTemplate;
|
||||
|
||||
// Look up property name if needed.
|
||||
if (Game() >= eEchoesDemo && !IsRootParent() && !IsIntrinsic() && !mpParent->IsAtomic() && !IsArrayArchetype())
|
||||
{
|
||||
mName = CGameTemplate::PropertyName(mID);
|
||||
}
|
||||
|
||||
// Set any fields dependent on the parent...
|
||||
if (mpParent)
|
||||
{
|
||||
@@ -180,6 +172,21 @@ void IProperty::Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u
|
||||
{
|
||||
mpPointerParent = mpParent->mpPointerParent;
|
||||
}
|
||||
|
||||
if (mpParent->Type() == EPropertyType::Array)
|
||||
{
|
||||
mFlags |= EPropertyFlag::IsArrayArchetype;
|
||||
}
|
||||
}
|
||||
else if (!mpScriptTemplate)
|
||||
{
|
||||
mFlags |= EPropertyFlag::IsArchetype;
|
||||
}
|
||||
|
||||
// Register the property if needed.
|
||||
if (UsesNameMap())
|
||||
{
|
||||
NPropertyMap::RegisterProperty(this);
|
||||
}
|
||||
|
||||
// Allow subclasses to handle any initialization tasks
|
||||
@@ -259,7 +266,21 @@ IProperty* IProperty::ChildByIDString(const TIDString& rkIdString)
|
||||
}
|
||||
}
|
||||
|
||||
bool IProperty::ShouldCook(void*pPropertyData) const
|
||||
TString IProperty::GetTemplateFileName()
|
||||
{
|
||||
if (mpScriptTemplate)
|
||||
{
|
||||
return mpScriptTemplate->SourceFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
CGameTemplate* pGameTemplate = NGameList::GetGameTemplate(Game());
|
||||
IProperty* pTemplateRoot = (IsArchetype() ? RootParent() : mpArchetype);
|
||||
return pGameTemplate->GetPropertyArchetypeFilePath( pTemplateRoot->Name() );
|
||||
}
|
||||
}
|
||||
|
||||
bool IProperty::ShouldCook(void* pPropertyData) const
|
||||
{
|
||||
switch (mCookPreference)
|
||||
{
|
||||
@@ -270,7 +291,7 @@ bool IProperty::ShouldCook(void*pPropertyData) const
|
||||
return false;
|
||||
|
||||
default:
|
||||
return (Game() < eReturns ? true : !MatchesDefault(pPropertyData));
|
||||
return (Game() < EGame::DKCReturns ? true : !MatchesDefault(pPropertyData));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,28 +299,67 @@ void IProperty::SetName(const TString& rkNewName)
|
||||
{
|
||||
mName = rkNewName;
|
||||
mFlags.ClearFlag(EPropertyFlag::HasCachedNameCheck);
|
||||
|
||||
// in Echoes and on, since property names are referenced by ID, renaming a property
|
||||
// doesn't directly affect the serialized data, so it doesn't need to be flagged dirty
|
||||
if (mGame <= EGame::Prime)
|
||||
{
|
||||
MarkDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void IProperty::SetDescription(const TString& rkNewDescription)
|
||||
{
|
||||
mDescription = rkNewDescription;
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
void IProperty::SetSuffix(const TString& rkNewSuffix)
|
||||
{
|
||||
mSuffix = rkNewSuffix;
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
void IProperty::SetPropertyFlags(FPropertyFlags FlagsToSet)
|
||||
void IProperty::MarkDirty()
|
||||
{
|
||||
mFlags |= FlagsToSet;
|
||||
// This property is either part of a script template, or a property archetype.
|
||||
// Figure out which one, set the dirty flag as needed
|
||||
if (mpScriptTemplate)
|
||||
{
|
||||
mpScriptTemplate->MarkDirty();
|
||||
}
|
||||
else
|
||||
{
|
||||
RootParent()->mFlags |= EPropertyFlag::IsDirty;
|
||||
}
|
||||
}
|
||||
|
||||
void IProperty::ClearDirtyFlag()
|
||||
{
|
||||
if (!mpScriptTemplate)
|
||||
{
|
||||
RootParent()->mFlags &= ~EPropertyFlag::IsDirty;
|
||||
}
|
||||
}
|
||||
|
||||
bool IProperty::UsesNameMap()
|
||||
{
|
||||
return Game() >= EGame::EchoesDemo &&
|
||||
!IsRootParent() &&
|
||||
!IsIntrinsic() &&
|
||||
!mpParent->IsAtomic() && // Atomic properties can use the name map, but their children shouldn't
|
||||
!IsArrayArchetype();
|
||||
}
|
||||
|
||||
bool IProperty::HasAccurateName()
|
||||
{
|
||||
// Exceptions for the three hardcoded 4CC property IDs
|
||||
if (mID == FOURCC('XFRM') || mID == FOURCC('INAM') || mID == FOURCC('ACTV'))
|
||||
if (mID == FOURCC('XFRM') ||
|
||||
mID == FOURCC('INAM') ||
|
||||
mID == FOURCC('ACTV'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Children of atomic properties defer to parents. Intrinsic properties and array archetypes also defer to parents.
|
||||
if ( (mpParent && mpParent->IsAtomic()) || IsIntrinsic() || IsArrayArchetype() )
|
||||
@@ -374,7 +434,6 @@ IProperty* IProperty::CreateCopy(IProperty* pArchetype)
|
||||
{
|
||||
IProperty* pOut = Create(pArchetype->Type(), pArchetype->mGame);
|
||||
pOut->InitFromArchetype(pArchetype);
|
||||
pArchetype->mSubInstances.push_back(pOut);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ enum class EPropertyFlag : u32
|
||||
IsAtomic = 0x8,
|
||||
/** This is a property of a C++ class, not a script object */
|
||||
IsIntrinsic = 0x10,
|
||||
/** Property has been modified, and needs to be resaved. Only valid on archetypes */
|
||||
IsDirty = 0x20,
|
||||
/** We have cached whether the property name is correct */
|
||||
HasCachedNameCheck = 0x40000000,
|
||||
/** The name of the property is a match for the property ID hash */
|
||||
@@ -185,18 +187,20 @@ public:
|
||||
virtual void Serialize(IArchive& rArc);
|
||||
virtual void InitFromArchetype(IProperty* pOther);
|
||||
virtual bool ShouldSerialize() const;
|
||||
virtual TString GetTemplateFileName();
|
||||
|
||||
/** Utility methods */
|
||||
void Initialize(IProperty* pInParent, CScriptTemplate* pInTemplate, u32 InOffset);
|
||||
void* RawValuePtr(void* pData) const;
|
||||
IProperty* ChildByID(u32 ID) const;
|
||||
IProperty* ChildByIDString(const TIDString& rkIdString);
|
||||
TString GetTemplateFileName();
|
||||
bool ShouldCook(void* pPropertyData) const;
|
||||
void SetName(const TString& rkNewName);
|
||||
void SetDescription(const TString& rkNewDescription);
|
||||
void SetSuffix(const TString& rkNewSuffix);
|
||||
void SetPropertyFlags(FPropertyFlags FlagsToSet);
|
||||
void MarkDirty();
|
||||
void ClearDirtyFlag();
|
||||
bool UsesNameMap();
|
||||
bool HasAccurateName();
|
||||
|
||||
/** Accessors */
|
||||
@@ -219,6 +223,7 @@ public:
|
||||
inline bool IsArrayArchetype() const { return mFlags.HasFlag(EPropertyFlag::IsArrayArchetype); }
|
||||
inline bool IsAtomic() const { return mFlags.HasFlag(EPropertyFlag::IsAtomic); }
|
||||
inline bool IsIntrinsic() const { return mFlags.HasFlag(EPropertyFlag::IsIntrinsic); }
|
||||
inline bool IsDirty() const { return mFlags.HasFlag(EPropertyFlag::IsDirty); }
|
||||
inline bool IsRootParent() const { return mpParent == nullptr; }
|
||||
|
||||
/** Create */
|
||||
@@ -337,7 +342,7 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual EPropertyType Type() const { return PropEnum; }
|
||||
virtual EPropertyType Type() const { return PropEnum; }
|
||||
virtual u32 DataSize() const { return sizeof(PropType); }
|
||||
virtual u32 DataAlignment() const { return alignof(PropType); }
|
||||
virtual void Construct(void* pData) const { new(ValuePtr(pData)) PropType(mDefaultValue); }
|
||||
@@ -400,7 +405,7 @@ public:
|
||||
// on property types that don't have default values in the game executable.
|
||||
bool MakeOptional = false;
|
||||
|
||||
if (Game() <= ePrime || pArchetype != nullptr)
|
||||
if (Game() <= EGame::Prime || pArchetype != nullptr)
|
||||
{
|
||||
MakeOptional = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user