More fixes. Property/serialization changes are finally basically finished now. Serialized property templates now load & display correctly in the editor
This commit is contained in:
parent
33e915a638
commit
2118bbd0cd
|
@ -97,8 +97,13 @@ template<typename T> struct TIsContainer< std::set<T> > : std::true_type {};
|
|||
template<typename T, typename V> struct TIsContainer< std::map<T,V> > : std::true_type {};
|
||||
template<typename T, typename V> struct TIsContainer< std::unordered_map<T,V> > : std::true_type {};
|
||||
|
||||
/** Class that determines if the type is a smart pointer */
|
||||
template<typename> struct TIsSmartPointer : std::false_type {};
|
||||
template<typename T> struct TIsSmartPointer< std::shared_ptr<T> > : std::true_type {};
|
||||
template<typename T> struct TIsSmartPointer< std::unique_ptr<T> > : std::true_type {};
|
||||
|
||||
/** Helper macro that tells us whether the parameter supports default property values */
|
||||
#define SUPPORTS_DEFAULT_VALUES (!std::is_pointer_v<ValType> && std::is_copy_assignable_v<ValType> && THasEqualTo<ValType>::value && !TIsContainer<ValType>::value)
|
||||
#define SUPPORTS_DEFAULT_VALUES (!std::is_pointer_v<ValType> && std::is_copy_assignable_v<ValType> && THasEqualTo<ValType>::value && !TIsContainer<ValType>::value && !TIsSmartPointer<ValType>::value)
|
||||
|
||||
/** TSerialParameter - name/value pair for generic serial parameters */
|
||||
template<typename ValType>
|
||||
|
@ -241,14 +246,26 @@ struct SerialType
|
|||
None);
|
||||
};
|
||||
|
||||
/** Helper for determining the type used by a given abstract object class (i.e. the type returned by the Type() function) */
|
||||
#define ABSTRACT_TYPE decltype( std::declval<ValType>().Type() )
|
||||
|
||||
/** For abstract types, determine what kind of ArchiveConstructor the type has */
|
||||
template<typename ValType, class ArchiveType>
|
||||
struct ArchiveConstructorType
|
||||
{
|
||||
typedef ABSTRACT_TYPE ObjType;
|
||||
/** Figure out the type being used to represent the object type.
|
||||
* If there isn't a type function, then it doesn't matter; just substitute int.
|
||||
*/
|
||||
template<typename T>
|
||||
static constexpr auto HasTypeMethod(int) -> decltype( std::declval<T>().Type() )
|
||||
{
|
||||
return std::declval<T>().Type();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr int HasTypeMethod(...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
using ObjType = decltype(HasTypeMethod<ValType>(0));
|
||||
|
||||
enum { Basic, Advanced, None };
|
||||
|
||||
|
@ -340,7 +357,7 @@ public:
|
|||
mParmStack.reserve(16);
|
||||
}
|
||||
|
||||
virtual ~IArchive() {}
|
||||
virtual ~IArchive() { ASSERT(mParmStack.empty()); }
|
||||
|
||||
// Serialize archive version. Always call after opening a file.
|
||||
void SerializeVersion()
|
||||
|
|
|
@ -266,7 +266,6 @@ CGameProject* CGameProject::LoadProject(const TString& rkProjPath, IProgressNoti
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CTemplateLoader::LoadGameTemplates(pProj->mGame);
|
||||
pProj->mProjFileLock.Lock(ProjPath);
|
||||
pProj->mpGameInfo->LoadGameInfo(pProj->mGame);
|
||||
pProj->mpAudioManager->LoadAssets();
|
||||
|
|
|
@ -137,7 +137,7 @@ CStructPropertyNew* CLight::GetProperties() const
|
|||
if (!pProperties)
|
||||
{
|
||||
pProperties = (CStructPropertyNew*) IPropertyNew::CreateIntrinsic(EPropertyTypeNew::Struct,
|
||||
nullptr,
|
||||
ePrime,
|
||||
0,
|
||||
"Light");
|
||||
|
||||
|
|
|
@ -189,14 +189,14 @@ IPropertyNew* CTemplateLoader::LoadProperty(XMLElement* pElem, CScriptTemplate*
|
|||
// create property as a copy of the archetype
|
||||
if (pArchetype != nullptr)
|
||||
{
|
||||
pProp = IPropertyNew::CreateCopy(pArchetype, pParent);
|
||||
pProp = IPropertyNew::CreateCopy(pArchetype);
|
||||
}
|
||||
}
|
||||
|
||||
// no archetype, so do normal create
|
||||
if (!pProp)
|
||||
{
|
||||
pProp = IPropertyNew::Create(Type, pParent, mGame, pScript, false);
|
||||
pProp = IPropertyNew::Create(Type, mGame);
|
||||
}
|
||||
|
||||
// we need to have a valid property by this point
|
||||
|
@ -340,7 +340,7 @@ IPropertyNew* CTemplateLoader::LoadProperty(XMLElement* pElem, CScriptTemplate*
|
|||
}
|
||||
else
|
||||
{
|
||||
pArray->mpItemArchetype = IPropertyNew::Create(EPropertyTypeNew::Struct, pArray, mGame, pScript, false);
|
||||
pArray->mpItemArchetype = IPropertyNew::Create(EPropertyTypeNew::Struct, mGame);
|
||||
pStruct = TPropCast<CStructPropertyNew>(pArray->mpItemArchetype);
|
||||
pStruct->mFlags = EPropertyFlag::IsAtomic | EPropertyFlag::IsArrayArchetype;
|
||||
}
|
||||
|
@ -358,17 +358,16 @@ IPropertyNew* CTemplateLoader::LoadProperty(XMLElement* pElem, CScriptTemplate*
|
|||
{
|
||||
LoadProperties(pProperties, pScript, pStruct, rkTemplateName);
|
||||
}
|
||||
|
||||
if (Type == EPropertyTypeNew::Array)
|
||||
{
|
||||
pStruct->PostInitialize();
|
||||
}
|
||||
}
|
||||
|
||||
if (IsNewProperty)
|
||||
{
|
||||
CMasterTemplate::AddProperty(pProp, mMasterDir + rkTemplateName);
|
||||
|
||||
pProp->PostInitialize();
|
||||
if (pParent)
|
||||
pParent->mChildren.push_back(pProp);
|
||||
}
|
||||
|
||||
return pProp;
|
||||
}
|
||||
|
||||
|
@ -393,11 +392,7 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
|
|||
if (!Doc.Error())
|
||||
{
|
||||
pArchetype = TPropCast<CStructPropertyNew>(
|
||||
IPropertyNew::Create(EPropertyTypeNew::Struct,
|
||||
nullptr,
|
||||
mGame,
|
||||
nullptr,
|
||||
false)
|
||||
IPropertyNew::Create(EPropertyTypeNew::Struct, mGame)
|
||||
);
|
||||
ASSERT(pArchetype != nullptr);
|
||||
|
||||
|
@ -438,7 +433,7 @@ CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTempla
|
|||
ASSERT(pSubPropsElem);
|
||||
|
||||
LoadProperties(pSubPropsElem, nullptr, pArchetype, rkTemplateFileName);
|
||||
pArchetype->PostInitialize();
|
||||
pArchetype->Initialize(nullptr, nullptr, 0);
|
||||
|
||||
mpMaster->mPropertyTemplates.emplace(
|
||||
std::make_pair(
|
||||
|
@ -474,11 +469,7 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
|
|||
{
|
||||
// use static_cast so this code works for both enum and choice
|
||||
pArchetype = static_cast<CEnumProperty*>(
|
||||
IPropertyNew::Create(bIsChoice ? EPropertyTypeNew::Choice : EPropertyTypeNew::Enum,
|
||||
nullptr,
|
||||
mGame,
|
||||
nullptr,
|
||||
false)
|
||||
IPropertyNew::Create(bIsChoice ? EPropertyTypeNew::Choice : EPropertyTypeNew::Enum, mGame)
|
||||
);
|
||||
ASSERT(pArchetype != nullptr);
|
||||
|
||||
|
@ -493,7 +484,7 @@ CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileN
|
|||
ASSERT(pEnumers);
|
||||
|
||||
LoadEnumerators(pEnumers, pArchetype, rkTemplateFileName);
|
||||
pArchetype->PostInitialize();
|
||||
pArchetype->Initialize(nullptr, nullptr, 0);
|
||||
|
||||
mpMaster->mPropertyTemplates.emplace(
|
||||
std::make_pair(
|
||||
|
@ -528,11 +519,7 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
|
|||
if (!Doc.Error())
|
||||
{
|
||||
pArchetype = TPropCast<CFlagsProperty>(
|
||||
IPropertyNew::Create(EPropertyTypeNew::Flags,
|
||||
nullptr,
|
||||
mGame,
|
||||
nullptr,
|
||||
false)
|
||||
IPropertyNew::Create(EPropertyTypeNew::Flags, mGame)
|
||||
);
|
||||
ASSERT(pArchetype != nullptr);
|
||||
|
||||
|
@ -547,7 +534,7 @@ CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFil
|
|||
ASSERT(pFlags);
|
||||
|
||||
LoadBitFlags(pFlags, pArchetype, rkTemplateFileName);
|
||||
pArchetype->PostInitialize();
|
||||
pArchetype->Initialize(nullptr, nullptr, 0);
|
||||
|
||||
mpMaster->mPropertyTemplates.emplace(
|
||||
std::make_pair(
|
||||
|
@ -645,7 +632,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
|
|||
pScript->mObjectID = ObjectID;
|
||||
pScript->mSourceFile = rkTemplateName;
|
||||
|
||||
IPropertyNew* pBaseStruct = IPropertyNew::Create(EPropertyTypeNew::Struct, nullptr, mGame, pScript);
|
||||
IPropertyNew* pBaseStruct = IPropertyNew::Create(EPropertyTypeNew::Struct, mGame);
|
||||
pScript->mpProperties = std::make_unique<CStructPropertyNew>( *TPropCast<CStructPropertyNew>(pBaseStruct) );
|
||||
|
||||
XMLElement *pRoot = pDoc->FirstChildElement("ScriptTemplate");
|
||||
|
@ -1139,7 +1126,7 @@ TString CTemplateLoader::ErrorName(XMLError Error)
|
|||
}
|
||||
|
||||
// ************ PUBLIC ************
|
||||
#define USE_NEW_TEMPLATES 0
|
||||
#define USE_NEW_TEMPLATES 1
|
||||
|
||||
void CTemplateLoader::LoadGameList()
|
||||
{
|
||||
|
@ -1193,7 +1180,7 @@ void CTemplateLoader::LoadGameList()
|
|||
for (auto Iter = MasterList.begin(); Iter != MasterList.end(); Iter++)
|
||||
{
|
||||
CMasterTemplate* pMaster = *Iter;
|
||||
const TString kMasterPath = kTemplatesDir + pMaster->GetDirectory() + "Game.xml";
|
||||
const TString kMasterPath = pMaster->GetGameDirectory(true) + "Game.xml";
|
||||
|
||||
CXMLReader Reader(kMasterPath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
@ -1354,7 +1341,7 @@ void CTemplateLoader::SaveGameList()
|
|||
SGameInfo Info;
|
||||
Info.Game = pMaster->Game();
|
||||
Info.Name = pMaster->GameName();
|
||||
Info.MasterPath = pMaster->GetDirectory() + "Game.xml";
|
||||
Info.MasterPath = pMaster->GetGameDirectory() + "Game.xml";
|
||||
Writer << SerialParameter("Game", Info);
|
||||
}
|
||||
Writer.ParamEnd();
|
||||
|
@ -1373,7 +1360,7 @@ void CTemplateLoader::SaveGameList()
|
|||
for (auto Iter = MasterList.begin(); Iter != MasterList.end(); Iter++)
|
||||
{
|
||||
CMasterTemplate* pMasterTemplate = *Iter;
|
||||
TString MasterFilePath = kTemplatesDir + pMasterTemplate->GetDirectory() + "Game.xml";
|
||||
TString MasterFilePath = pMasterTemplate->GetGameDirectory(true) + "Game.xml";
|
||||
FileUtil::MakeDirectory( MasterFilePath.GetFileDirectory() );
|
||||
|
||||
CXMLWriter Writer(MasterFilePath, "Game", 0, pMasterTemplate->Game());
|
||||
|
|
|
@ -17,17 +17,52 @@ void CMasterTemplate::Serialize(IArchive& Arc)
|
|||
|
||||
void CMasterTemplate::LoadSubTemplates()
|
||||
{
|
||||
//todo
|
||||
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 CMasterTemplate::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);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
Path.pTemplate = std::make_shared<CScriptTemplate>(this, Path.ID.ID, Path.Path);
|
||||
Path.pTemplate->Serialize(Reader);
|
||||
Path.pTemplate->PostLoad();
|
||||
}
|
||||
|
||||
void CMasterTemplate::Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path)
|
||||
{
|
||||
if (Path.pTemplate != nullptr) // don't load twice
|
||||
return;
|
||||
|
||||
const TString kGameDir = GetGameDirectory(true);
|
||||
const TString kTemplateFilePath = kGameDir + Path.Path;
|
||||
CXMLReader Reader(kTemplateFilePath);
|
||||
ASSERT(Reader.IsValid());
|
||||
|
||||
Reader << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
ASSERT(Path.pTemplate != nullptr);
|
||||
|
||||
Path.pTemplate->SetPropertyFlags( EPropertyFlag::IsArchetype );
|
||||
Path.pTemplate->Initialize(nullptr, nullptr, 0);
|
||||
}
|
||||
|
||||
void CMasterTemplate::SaveSubTemplates()
|
||||
{
|
||||
TString GameDir = "../templates_new/" + GetDirectory();
|
||||
const TString kGameDir = GetGameDirectory(true);
|
||||
|
||||
for (auto Iter = mScriptTemplates.begin(); Iter != mScriptTemplates.end(); Iter++)
|
||||
{
|
||||
SScriptTemplatePath& Path = Iter->second;
|
||||
TString OutPath = GameDir + Path.Path;
|
||||
TString OutPath = kGameDir + Path.Path;
|
||||
|
||||
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
|
||||
CXMLWriter Writer(OutPath, "ScriptObject", 0, Game());
|
||||
|
@ -37,11 +72,11 @@ void CMasterTemplate::SaveSubTemplates()
|
|||
for (auto Iter = mPropertyTemplates.begin(); Iter != mPropertyTemplates.end(); Iter++)
|
||||
{
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
TString OutPath = GameDir + Path.Path;
|
||||
TString OutPath = kGameDir + Path.Path;
|
||||
|
||||
FileUtil::MakeDirectory( OutPath.GetFileDirectory() );
|
||||
CXMLWriter Writer(OutPath, "PropertyArchetype", 0, Game());
|
||||
Path.pTemplate->Serialize(Writer);
|
||||
CXMLWriter Writer(OutPath, "PropertyTemplate", 0, Game());
|
||||
Writer << SerialParameter("PropertyArchetype", Path.pTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,10 +150,34 @@ SMessage CMasterTemplate::MessageByIndex(u32 Index)
|
|||
return SMessage(Iter->first, Iter->second);
|
||||
}
|
||||
|
||||
IPropertyNew* CMasterTemplate::FindPropertyArchetype(const TString& kTypeName) const
|
||||
IPropertyNew* CMasterTemplate::FindPropertyArchetype(const TString& kTypeName)
|
||||
{
|
||||
auto Iter = mPropertyTemplates.find(kTypeName);
|
||||
return (Iter != mPropertyTemplates.end()) ? Iter->second.pTemplate.get() : nullptr;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// If the template isn't loaded yet, then load it.
|
||||
// This has to be done here to allow recursion while loading other property archetypes, because some properties may
|
||||
// request archetypes of other properties that haven't been loaded yet during their load.
|
||||
SPropertyTemplatePath& Path = Iter->second;
|
||||
if (!Path.pTemplate)
|
||||
{
|
||||
Internal_LoadPropertyTemplate(Path);
|
||||
ASSERT(Path.pTemplate != nullptr); // Load failed; missing or malformed template
|
||||
}
|
||||
|
||||
return Path.pTemplate.get();
|
||||
}
|
||||
|
||||
TString CMasterTemplate::GetGameDirectory(bool Absolute) const
|
||||
{
|
||||
TString Out = mSourceFile.GetFileDirectory();
|
||||
return Absolute ? "../templates_new/" + Out : Out;
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
|
|
|
@ -124,6 +124,9 @@ class CMasterTemplate
|
|||
static std::map<u32, TString> smPropertyNames;
|
||||
static u32 smGameListVersion;
|
||||
|
||||
void Internal_LoadScriptTemplate(SScriptTemplatePath& Path);
|
||||
void Internal_LoadPropertyTemplate(SPropertyTemplatePath& Path);
|
||||
|
||||
public:
|
||||
CMasterTemplate();
|
||||
void Serialize(IArchive& Arc);
|
||||
|
@ -139,7 +142,8 @@ public:
|
|||
SMessage MessageByID(u32 MessageID);
|
||||
SMessage MessageByID(const CFourCC& MessageID);
|
||||
SMessage MessageByIndex(u32 Index);
|
||||
IPropertyNew* FindPropertyArchetype(const TString& kTypeName) const;
|
||||
IPropertyNew* FindPropertyArchetype(const TString& kTypeName);
|
||||
TString GetGameDirectory(bool Absolute = false) const;
|
||||
|
||||
// Inline Accessors
|
||||
inline EGame Game() const { return mGame; }
|
||||
|
@ -148,7 +152,6 @@ public:
|
|||
inline u32 NumStates() const { return mStates.size(); }
|
||||
inline u32 NumMessages() const { return mMessages.size(); }
|
||||
inline bool IsLoadedSuccessfully() { return mFullyLoaded; }
|
||||
inline TString GetDirectory() const { return mSourceFile.GetFileDirectory(); }
|
||||
|
||||
// Static
|
||||
static CMasterTemplate* MasterForGame(EGame Game);
|
||||
|
|
|
@ -79,6 +79,8 @@ void CScriptTemplate::Serialize(IArchive& Arc)
|
|||
|
||||
void CScriptTemplate::PostLoad()
|
||||
{
|
||||
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) );
|
||||
|
|
|
@ -130,6 +130,8 @@ private:
|
|||
bool mVisible;
|
||||
|
||||
public:
|
||||
// Default constructor. Don't use. This is only here so the serializer doesn't complain
|
||||
CScriptTemplate() { ASSERT(false); }
|
||||
// Old constructor
|
||||
CScriptTemplate(CMasterTemplate *pMaster);
|
||||
// New constructor
|
||||
|
|
|
@ -9,10 +9,12 @@
|
|||
#include "Core/Resource/Script/CScriptTemplate.h"
|
||||
|
||||
/** IPropertyNew */
|
||||
IPropertyNew::IPropertyNew()
|
||||
IPropertyNew::IPropertyNew(EGame Game)
|
||||
: mpParent( nullptr )
|
||||
, mpPointerParent( nullptr )
|
||||
, mpArchetype( nullptr )
|
||||
, mGame( Game )
|
||||
, mpScriptTemplate( nullptr )
|
||||
, mOffset( -1 )
|
||||
, mID( -1 )
|
||||
, mCookPreference( ECookPreferenceNew::Default )
|
||||
|
@ -20,41 +22,6 @@ IPropertyNew::IPropertyNew()
|
|||
, mMaxVersion( FLT_MAX )
|
||||
{}
|
||||
|
||||
void IPropertyNew::_CalcOffset()
|
||||
{
|
||||
// For standard properties, append to the end of the parent.
|
||||
bool IsRootArrayArchetype = (IsArrayArchetype() && TPropCast<CArrayProperty>(mpParent) != nullptr);
|
||||
|
||||
if (mpParent && !IsRootArrayArchetype)
|
||||
{
|
||||
// When we have a parent, our data is usually located inside the parent's property data. So we want to
|
||||
// position ourself at the end of the parent's existing children so we don't overlap any other properties.
|
||||
IPropertyNew* pLastChild = (mpParent->mChildren.empty() ? nullptr : mpParent->mChildren.back());
|
||||
|
||||
if (pLastChild)
|
||||
{
|
||||
mOffset = pLastChild->mOffset + pLastChild->DataSize();
|
||||
}
|
||||
else if (mpParent != mpPointerParent)
|
||||
{
|
||||
mOffset = mpParent->mOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
mOffset = 0;
|
||||
}
|
||||
|
||||
mOffset = ALIGN(mOffset, DataAlignment());
|
||||
}
|
||||
// Array archetypes are accessed differently because they have no way of knowing
|
||||
// which array index is meant to be accessed. So the offset is 0 and the caller
|
||||
// is responsible for passing in a pointer to the correct array item.
|
||||
else
|
||||
{
|
||||
mOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IPropertyNew::_ClearChildren()
|
||||
{
|
||||
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
|
||||
|
@ -109,7 +76,6 @@ void IPropertyNew::Serialize(IArchive& rArc)
|
|||
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);
|
||||
|
@ -118,7 +84,12 @@ void IPropertyNew::Serialize(IArchive& rArc)
|
|||
|
||||
// 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())
|
||||
// Exceptions: Properties that are not in the name map still need to serialize their names.
|
||||
// This includes root-level properties, and properties of atomic structs.
|
||||
//
|
||||
// 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() || mID <= 0xFF)
|
||||
{
|
||||
rArc << SerialParameter("Name", mName, mpArchetype ? SH_Optional : 0, mpArchetype ? mpArchetype->mName : "");
|
||||
}
|
||||
|
@ -137,7 +108,6 @@ void IPropertyNew::InitFromArchetype(IPropertyNew* pOther)
|
|||
//@todo maybe somehow use Serialize for this instead?
|
||||
mpArchetype = pOther;
|
||||
mFlags = pOther->mFlags & EPropertyFlag::ArchetypeCopyFlags;
|
||||
mID = pOther->mID;
|
||||
mName = pOther->mName;
|
||||
mDescription = pOther->mDescription;
|
||||
mSuffix = pOther->mSuffix;
|
||||
|
@ -145,12 +115,10 @@ void IPropertyNew::InitFromArchetype(IPropertyNew* pOther)
|
|||
mMinVersion = pOther->mMinVersion;
|
||||
mMaxVersion = pOther->mMaxVersion;
|
||||
|
||||
// Copy children
|
||||
_ClearChildren();
|
||||
|
||||
for (u32 ChildIdx = 0; ChildIdx < pOther->mChildren.size(); ChildIdx++)
|
||||
// Copy ID only if our existing ID is not valid.
|
||||
if (mID == 0xFFFFFFFF)
|
||||
{
|
||||
CreateCopy( pOther->mChildren[ChildIdx], this );
|
||||
mID = pOther->mID;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,6 +151,62 @@ TString IPropertyNew::GetTemplateFileName()
|
|||
}
|
||||
}
|
||||
|
||||
void IPropertyNew::Initialize(IPropertyNew* pInParent, CScriptTemplate* pInTemplate, u32 InOffset)
|
||||
{
|
||||
// Make sure we only get initialized once.
|
||||
ASSERT( (mFlags & EPropertyFlag::IsInitialized) == 0 );
|
||||
mFlags |= EPropertyFlag::IsInitialized;
|
||||
|
||||
mpParent = pInParent;
|
||||
mOffset = InOffset;
|
||||
mpScriptTemplate = pInTemplate;
|
||||
|
||||
// Look up property name if needed.
|
||||
if (Game() >= eEchoesDemo && !IsRootParent() && !IsIntrinsic() && !mpParent->IsAtomic())
|
||||
{
|
||||
mName = CMasterTemplate::PropertyName(mID);
|
||||
}
|
||||
|
||||
// Set any fields dependent on the parent...
|
||||
if (mpParent)
|
||||
{
|
||||
mFlags |= mpParent->mFlags & EPropertyFlag::InheritableFlags;
|
||||
|
||||
if (mpParent->IsPointerType())
|
||||
{
|
||||
mpPointerParent = mpParent;
|
||||
}
|
||||
else
|
||||
{
|
||||
mpPointerParent = mpParent->mpPointerParent;
|
||||
}
|
||||
}
|
||||
|
||||
// Allow subclasses to handle any initialization tasks
|
||||
PostInitialize();
|
||||
|
||||
// Now, route initialization to any child properties...
|
||||
u32 ChildOffset = mOffset;
|
||||
|
||||
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
|
||||
{
|
||||
IPropertyNew* pChild = mChildren[ChildIdx];
|
||||
|
||||
// update offset and round up to the child's alignment
|
||||
if (ChildIdx > 0)
|
||||
{
|
||||
ChildOffset += mChildren[ChildIdx-1]->DataSize();
|
||||
}
|
||||
ChildOffset = ALIGN(ChildOffset, pChild->DataAlignment());
|
||||
|
||||
// Don't call Initialize on intrinsic children as they have already been initialized.
|
||||
if (!pChild->IsIntrinsic())
|
||||
{
|
||||
pChild->Initialize(this, pInTemplate, ChildOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* IPropertyNew::RawValuePtr(void* pData) const
|
||||
{
|
||||
// For array archetypes, the caller needs to provide the pointer to the correct array item
|
||||
|
@ -266,8 +290,27 @@ void IPropertyNew::SetSuffix(const TString& rkNewSuffix)
|
|||
mSuffix = rkNewSuffix;
|
||||
}
|
||||
|
||||
void IPropertyNew::SetPropertyFlags(FPropertyFlags FlagsToSet)
|
||||
{
|
||||
mFlags |= FlagsToSet;
|
||||
}
|
||||
|
||||
bool IPropertyNew::HasAccurateName()
|
||||
{
|
||||
// Exceptions for the three hardcoded 4CC property IDs
|
||||
if (mID == FOURCC('XFRM') || mID == FOURCC('INAM') || mID == FOURCC('ACTV'))
|
||||
return true;
|
||||
|
||||
// Children of atomic properties defer to parents. Intrinsic properties also defer to parents.
|
||||
if ( (mpParent && mpParent->IsAtomic()) || IsIntrinsic() )
|
||||
{
|
||||
if (mpParent)
|
||||
return mpParent->HasAccurateName();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// For everything else, hash the property name and check if it is a match for the property ID
|
||||
if (!mFlags.HasFlag(EPropertyFlag::HasCachedNameCheck))
|
||||
{
|
||||
CCRC32 Hash;
|
||||
|
@ -293,114 +336,79 @@ EGame IPropertyNew::Game() const
|
|||
}
|
||||
|
||||
IPropertyNew* IPropertyNew::Create(EPropertyTypeNew Type,
|
||||
IPropertyNew* pParent,
|
||||
EGame Game,
|
||||
CScriptTemplate* pScript,
|
||||
bool CallPostInit /*= true*/)
|
||||
EGame Game)
|
||||
{
|
||||
IPropertyNew* pOut = nullptr;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case EPropertyTypeNew::Bool: pOut = new CBoolProperty; break;
|
||||
case EPropertyTypeNew::Byte: pOut = new CByteProperty; break;
|
||||
case EPropertyTypeNew::Short: pOut = new CShortProperty; break;
|
||||
case EPropertyTypeNew::Int: pOut = new CIntProperty; break;
|
||||
case EPropertyTypeNew::Float: pOut = new CFloatProperty; break;
|
||||
case EPropertyTypeNew::Choice: pOut = new CChoiceProperty; break;
|
||||
case EPropertyTypeNew::Enum: pOut = new CEnumProperty; break;
|
||||
case EPropertyTypeNew::Flags: pOut = new CFlagsProperty; break;
|
||||
case EPropertyTypeNew::String: pOut = new CStringProperty; break;
|
||||
case EPropertyTypeNew::Vector: pOut = new CVectorProperty; break;
|
||||
case EPropertyTypeNew::Color: pOut = new CColorProperty; break;
|
||||
case EPropertyTypeNew::Asset: pOut = new CAssetProperty; break;
|
||||
case EPropertyTypeNew::Sound: pOut = new CSoundProperty; break;
|
||||
case EPropertyTypeNew::Animation: pOut = new CAnimationProperty; break;
|
||||
case EPropertyTypeNew::AnimationSet: pOut = new CAnimationSetProperty; break;
|
||||
case EPropertyTypeNew::Sequence: pOut = new CSequenceProperty; break;
|
||||
case EPropertyTypeNew::Spline: pOut = new CSplineProperty; break;
|
||||
case EPropertyTypeNew::Guid: pOut = new CGuidProperty; break;
|
||||
case EPropertyTypeNew::Pointer: pOut = new CPointerProperty; break;
|
||||
case EPropertyTypeNew::Struct: pOut = new CStructPropertyNew; break;
|
||||
case EPropertyTypeNew::Array: pOut = new CArrayProperty; break;
|
||||
}
|
||||
|
||||
if (!pOut)
|
||||
{
|
||||
// this shouldn't be possible! unhandled type! someone fucked up!
|
||||
ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Set parent and offset
|
||||
pOut->mpParent = pParent;
|
||||
|
||||
if (pParent)
|
||||
{
|
||||
pOut->mFlags = pParent->mFlags & EPropertyFlag::InheritableFlags;
|
||||
|
||||
if (pParent->IsPointerType())
|
||||
{
|
||||
pOut->mpPointerParent = pParent;
|
||||
}
|
||||
else
|
||||
{
|
||||
pOut->mpPointerParent = pParent->mpPointerParent;
|
||||
}
|
||||
}
|
||||
|
||||
// Set other metadata
|
||||
pOut->mGame = Game;
|
||||
pOut->mpScriptTemplate = pScript;
|
||||
pOut->_CalcOffset();
|
||||
|
||||
// Add to the parent's array. This needs to be done -after- we calculate offset, as adding a child to
|
||||
// the parent property will change the offset that gets calculated.
|
||||
if (pParent)
|
||||
{
|
||||
pParent->mChildren.push_back(pOut);
|
||||
}
|
||||
|
||||
if (CallPostInit)
|
||||
{
|
||||
pOut->PostInitialize();
|
||||
case EPropertyTypeNew::Bool: pOut = new CBoolProperty(Game); break;
|
||||
case EPropertyTypeNew::Byte: pOut = new CByteProperty(Game); break;
|
||||
case EPropertyTypeNew::Short: pOut = new CShortProperty(Game); break;
|
||||
case EPropertyTypeNew::Int: pOut = new CIntProperty(Game); break;
|
||||
case EPropertyTypeNew::Float: pOut = new CFloatProperty(Game); break;
|
||||
case EPropertyTypeNew::Choice: pOut = new CChoiceProperty(Game); break;
|
||||
case EPropertyTypeNew::Enum: pOut = new CEnumProperty(Game); break;
|
||||
case EPropertyTypeNew::Flags: pOut = new CFlagsProperty(Game); break;
|
||||
case EPropertyTypeNew::String: pOut = new CStringProperty(Game); break;
|
||||
case EPropertyTypeNew::Vector: pOut = new CVectorProperty(Game); break;
|
||||
case EPropertyTypeNew::Color: pOut = new CColorProperty(Game); break;
|
||||
case EPropertyTypeNew::Asset: pOut = new CAssetProperty(Game); break;
|
||||
case EPropertyTypeNew::Sound: pOut = new CSoundProperty(Game); break;
|
||||
case EPropertyTypeNew::Animation: pOut = new CAnimationProperty(Game); break;
|
||||
case EPropertyTypeNew::AnimationSet: pOut = new CAnimationSetProperty(Game); break;
|
||||
case EPropertyTypeNew::Sequence: pOut = new CSequenceProperty(Game); break;
|
||||
case EPropertyTypeNew::Spline: pOut = new CSplineProperty(Game); break;
|
||||
case EPropertyTypeNew::Guid: pOut = new CGuidProperty(Game); break;
|
||||
case EPropertyTypeNew::Pointer: pOut = new CPointerProperty(Game); break;
|
||||
case EPropertyTypeNew::Struct: pOut = new CStructPropertyNew(Game); break;
|
||||
case EPropertyTypeNew::Array: pOut = new CArrayProperty(Game); break;
|
||||
}
|
||||
|
||||
// If this assertion fails, then there is an unhandled type!
|
||||
ASSERT(pOut != nullptr);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype,
|
||||
IPropertyNew* pParent)
|
||||
IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype)
|
||||
{
|
||||
// Note this is mainly going to be used to create copies from struct/enum/flag archetype properties.
|
||||
// Properties that have archetypes will never be the root property of a script template, and there
|
||||
// is no case where we will be creating archetypes outside this context. As such, pParent should
|
||||
// always be valid.
|
||||
ASSERT(pParent != nullptr);
|
||||
|
||||
IPropertyNew* pOut = Create(pArchetype->Type(), pParent, pParent->mGame, pParent->mpScriptTemplate, false);
|
||||
IPropertyNew* pOut = Create(pArchetype->Type(), pArchetype->mGame);
|
||||
pOut->InitFromArchetype(pArchetype);
|
||||
pArchetype->mSubInstances.push_back(pOut);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
IPropertyNew* IPropertyNew::CreateIntrinsic(EPropertyTypeNew Type,
|
||||
EGame Game,
|
||||
u32 Offset,
|
||||
const TString& rkName)
|
||||
{
|
||||
IPropertyNew* pOut = Create(Type, Game);
|
||||
pOut->mFlags |= EPropertyFlag::IsIntrinsic;
|
||||
pOut->SetName(rkName);
|
||||
pOut->Initialize(nullptr, nullptr, Offset);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
IPropertyNew* IPropertyNew::CreateIntrinsic(EPropertyTypeNew Type,
|
||||
IPropertyNew* pParent,
|
||||
u32 Offset,
|
||||
const TString& rkName)
|
||||
{
|
||||
IPropertyNew* pOut = Create(Type, pParent, pParent ? pParent->mGame : eUnknownGame, nullptr, false);
|
||||
pOut->mOffset = Offset;
|
||||
// pParent should always be valid.
|
||||
// If you are creating a root property, call the other overload takes an EGame instead of a parent.
|
||||
ASSERT(pParent != nullptr);
|
||||
|
||||
IPropertyNew* pOut = Create(Type, pParent->mGame);
|
||||
pOut->mFlags |= EPropertyFlag::IsIntrinsic;
|
||||
pOut->SetName(rkName);
|
||||
pOut->PostInitialize();
|
||||
pOut->Initialize(pParent, nullptr, Offset);
|
||||
pParent->mChildren.push_back(pOut);
|
||||
return pOut;
|
||||
}
|
||||
|
||||
IPropertyNew* IPropertyNew::ArchiveConstructor(EPropertyTypeNew Type,
|
||||
const IArchive& Arc)
|
||||
{
|
||||
IPropertyNew* pParent = Arc.FindParentObject<IPropertyNew>();
|
||||
CScriptTemplate* pTemplate = (pParent ? pParent->ScriptTemplate() : Arc.FindParentObject<CScriptTemplate>());
|
||||
EGame Game = Arc.Game();
|
||||
return Create(Type, pParent, Game, pTemplate);
|
||||
return Create(Type, Arc.Game());
|
||||
}
|
||||
|
|
|
@ -19,12 +19,16 @@ typedef TString TIDString;
|
|||
/** Property flags */
|
||||
enum class EPropertyFlag : u32
|
||||
{
|
||||
/** Property has been fully initialized and has had PostLoad called */
|
||||
IsInitialized = 0x1,
|
||||
/** Property is an archetype (a template for other properties to copy from) */
|
||||
IsArchetype = 0x1,
|
||||
IsArchetype = 0x2,
|
||||
/** Property is an array archetype (a template for elements of an array property) */
|
||||
IsArrayArchetype = 0x2,
|
||||
IsArrayArchetype = 0x4,
|
||||
/** This property and all its children are a single unit and do not have individual property IDs, sizes, etc. */
|
||||
IsAtomic = 0x4,
|
||||
IsAtomic = 0x8,
|
||||
/** This is a property of a C++ class, not a script object */
|
||||
IsIntrinsic = 0x10,
|
||||
/** We have cached whether the property name is correct */
|
||||
HasCachedNameCheck = 0x40000000,
|
||||
/** The name of the property is a match for the property ID hash */
|
||||
|
@ -122,8 +126,8 @@ protected:
|
|||
/** Archetype property; source property that we copied metadata from */
|
||||
IPropertyNew* mpArchetype;
|
||||
|
||||
/** Sub-instances of archetype properties. For non-archetypes, will be empty. @todo better
|
||||
* method of storing this? maybe a linked list? */
|
||||
/** Sub-instances of archetype properties. For non-archetypes, will be empty.
|
||||
* @todo this really oughta be a linked list */
|
||||
std::vector<IPropertyNew*> mSubInstances;
|
||||
|
||||
/** Child properties; these appear underneath this property on the UI */
|
||||
|
@ -155,13 +159,9 @@ protected:
|
|||
float mMaxVersion;
|
||||
|
||||
/** Private constructor - use static methods to instantiate */
|
||||
IPropertyNew();
|
||||
void _CalcOffset();
|
||||
IPropertyNew(EGame Game);
|
||||
void _ClearChildren();
|
||||
|
||||
/** Called after property is created and fully initialized */
|
||||
virtual void PostInitialize() {}
|
||||
|
||||
public:
|
||||
virtual ~IPropertyNew();
|
||||
|
||||
|
@ -175,11 +175,11 @@ public:
|
|||
virtual void RevertToDefault(void* pData) const = 0;
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const = 0;
|
||||
|
||||
virtual void PostInitialize() {}
|
||||
virtual void PropertyValueChanged(void* pPropertyData) {}
|
||||
virtual bool IsNumericalType() const { return false; }
|
||||
virtual bool IsPointerType() const { return false; }
|
||||
virtual TString ValueAsString(void* pData) const { return ""; }
|
||||
|
||||
virtual const char* HashableTypeName() const;
|
||||
virtual void* GetChildDataPointer(void* pPropertyData) const;
|
||||
virtual void Serialize(IArchive& rArc);
|
||||
|
@ -188,6 +188,7 @@ public:
|
|||
virtual TString GetTemplateFileName();
|
||||
|
||||
/** Utility methods */
|
||||
void Initialize(IPropertyNew* pInParent, CScriptTemplate* pInTemplate, u32 InOffset);
|
||||
void* RawValuePtr(void* pData) const;
|
||||
IPropertyNew* ChildByID(u32 ID) const;
|
||||
IPropertyNew* ChildByIDString(const TIDString& rkIdString);
|
||||
|
@ -195,6 +196,7 @@ public:
|
|||
void SetName(const TString& rkNewName);
|
||||
void SetDescription(const TString& rkNewDescription);
|
||||
void SetSuffix(const TString& rkNewSuffix);
|
||||
void SetPropertyFlags(FPropertyFlags FlagsToSet);
|
||||
bool HasAccurateName();
|
||||
|
||||
/** Accessors */
|
||||
|
@ -216,17 +218,19 @@ 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 IsIntrinsic() const { return mFlags.HasFlag(EPropertyFlag::IsIntrinsic); }
|
||||
inline bool IsRootParent() const { return mpParent == nullptr; }
|
||||
|
||||
/** Create */
|
||||
static IPropertyNew* Create(EPropertyTypeNew Type,
|
||||
IPropertyNew* pParent,
|
||||
EGame Game,
|
||||
CScriptTemplate* pScript,
|
||||
bool CallPostInit = true);
|
||||
EGame Game);
|
||||
|
||||
static IPropertyNew* CreateCopy(IPropertyNew* pArchetype,
|
||||
IPropertyNew* pParent);
|
||||
static IPropertyNew* CreateCopy(IPropertyNew* pArchetype);
|
||||
|
||||
static IPropertyNew* CreateIntrinsic(EPropertyTypeNew Type,
|
||||
EGame Game,
|
||||
u32 Offset,
|
||||
const TString& rkName);
|
||||
|
||||
static IPropertyNew* CreateIntrinsic(EPropertyTypeNew Type,
|
||||
IPropertyNew* pParent,
|
||||
|
@ -326,8 +330,8 @@ public:
|
|||
protected:
|
||||
PropType mDefaultValue;
|
||||
|
||||
TTypedPropertyNew()
|
||||
: IPropertyNew()
|
||||
TTypedPropertyNew(EGame Game)
|
||||
: IPropertyNew(Game)
|
||||
{
|
||||
memset(&mDefaultValue, 0, sizeof(PropType));
|
||||
}
|
||||
|
@ -369,6 +373,11 @@ public:
|
|||
return mDefaultValue;
|
||||
}
|
||||
|
||||
inline void SetDefaultValue(const PropType& kInDefaultValue)
|
||||
{
|
||||
mDefaultValue = kInDefaultValue;
|
||||
}
|
||||
|
||||
inline static EPropertyTypeNew StaticType() { return PropEnum; }
|
||||
};
|
||||
|
||||
|
@ -376,8 +385,8 @@ template<typename PropType, EPropertyTypeNew PropEnum>
|
|||
class TSerializeableTypedProperty : public TTypedPropertyNew<PropType, PropEnum>
|
||||
{
|
||||
protected:
|
||||
TSerializeableTypedProperty()
|
||||
: TTypedPropertyNew()
|
||||
TSerializeableTypedProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
@ -443,8 +452,8 @@ protected:
|
|||
PropType mMinValue;
|
||||
PropType mMaxValue;
|
||||
|
||||
TNumericalPropertyNew()
|
||||
: TSerializeableTypedProperty()
|
||||
TNumericalPropertyNew(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
, mMinValue( -1 )
|
||||
, mMaxValue( -1 )
|
||||
{}
|
||||
|
|
|
@ -8,8 +8,8 @@ class CAnimationProperty : public TSerializeableTypedProperty< u32, EPropertyTyp
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CAnimationProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CAnimationProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,16 +8,13 @@ class CAnimationSetProperty : public TSerializeableTypedProperty< CAnimationPara
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CAnimationSetProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void PostInitialize()
|
||||
CAnimationSetProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{
|
||||
mDefaultValue.SetGame(Game());
|
||||
mDefaultValue.SetGame(Game);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
{
|
||||
Value(pData).Serialize(Arc);
|
||||
|
|
|
@ -45,8 +45,8 @@ class CArrayProperty : public TTypedPropertyNew<u32, EPropertyTypeNew::Array>
|
|||
}
|
||||
|
||||
protected:
|
||||
CArrayProperty()
|
||||
: TTypedPropertyNew()
|
||||
CArrayProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
, mpItemArchetype(nullptr)
|
||||
{}
|
||||
|
||||
|
@ -109,6 +109,11 @@ public:
|
|||
{
|
||||
TTypedPropertyNew::Serialize(rArc);
|
||||
rArc << SerialParameter("ItemArchetype", mpItemArchetype);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
mpItemArchetype->SetPropertyFlags( EPropertyFlag::IsArrayArchetype );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
|
@ -134,7 +139,13 @@ public:
|
|||
{
|
||||
TTypedPropertyNew::InitFromArchetype(pOther);
|
||||
CArrayProperty* pOtherArray = static_cast<CArrayProperty*>(pOther);
|
||||
mpItemArchetype = IPropertyNew::CreateCopy(pOtherArray->mpItemArchetype, this);
|
||||
mpItemArchetype = IPropertyNew::CreateCopy(pOtherArray->mpItemArchetype);
|
||||
}
|
||||
|
||||
virtual void PostInitialize()
|
||||
{
|
||||
TTypedPropertyNew::PostInitialize();
|
||||
mpItemArchetype->Initialize(this, mpScriptTemplate, 0);
|
||||
}
|
||||
|
||||
u32 ArrayCount(void* pPropertyData) const
|
||||
|
|
|
@ -7,18 +7,18 @@
|
|||
class CAssetProperty : public TSerializeableTypedProperty<CAssetID, EPropertyTypeNew::Asset>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class IPropertyNew;
|
||||
|
||||
CResTypeFilter mTypeFilter;
|
||||
|
||||
public:
|
||||
virtual void PostInitialize()
|
||||
{
|
||||
// Init default value to an invalid ID depending on the game
|
||||
if (!mDefaultValue.IsValid())
|
||||
protected:
|
||||
CAssetProperty::CAssetProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{
|
||||
mDefaultValue = CAssetID::InvalidID( mGame );
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void Serialize(IArchive& rArc)
|
||||
{
|
||||
TSerializeableTypedProperty::Serialize(rArc);
|
||||
|
|
|
@ -8,8 +8,8 @@ class CBoolProperty : public TSerializeableTypedProperty< bool, EPropertyTypeNew
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CBoolProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CBoolProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CByteProperty : public TNumericalPropertyNew< s8, EPropertyTypeNew::Byte >
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CByteProperty()
|
||||
: TNumericalPropertyNew()
|
||||
CByteProperty(EGame Game)
|
||||
: TNumericalPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -2,27 +2,25 @@
|
|||
#define CCOLORPROPERTY_H
|
||||
|
||||
#include "../IPropertyNew.h"
|
||||
#include "CFloatProperty.h"
|
||||
|
||||
class CColorProperty : public TSerializeableTypedProperty< CColor, EPropertyTypeNew::Color >
|
||||
{
|
||||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CColorProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CColorProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void PostInitialize()
|
||||
{
|
||||
IPropertyNew* pR = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
IPropertyNew* pG = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
IPropertyNew* pB = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
IPropertyNew* pA = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
pR->SetName("R");
|
||||
pG->SetName("G");
|
||||
pB->SetName("B");
|
||||
pA->SetName("A");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 0, "R");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 4, "G");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 8, "B");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 12, "A");
|
||||
TPropCast<CFloatProperty>( mChildren.back() )->SetDefaultValue(1.0f);
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
|
|
|
@ -14,6 +14,8 @@ template<EPropertyTypeNew TypeEnum>
|
|||
class TEnumPropertyBase : public TSerializeableTypedProperty<s32, TypeEnum>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class IPropertyNew;
|
||||
|
||||
struct SEnumValue
|
||||
{
|
||||
TString Name;
|
||||
|
@ -43,6 +45,12 @@ class TEnumPropertyBase : public TSerializeableTypedProperty<s32, TypeEnum>
|
|||
/** XML template file that this enum originated from; for archetypes */
|
||||
TString mSourceFile;
|
||||
|
||||
protected:
|
||||
/** Constructor */
|
||||
TEnumPropertyBase(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual const char* GetHashableTypeName() const
|
||||
{
|
||||
|
|
|
@ -38,8 +38,8 @@ class CFlagsProperty : public TSerializeableTypedProperty<u32, EPropertyTypeNew:
|
|||
/** XML template file that this enum originated from; for archetypes */
|
||||
TString mSourceFile;
|
||||
|
||||
CFlagsProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CFlagsProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
, mAllFlags(0)
|
||||
{}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ class CFloatProperty : public TNumericalPropertyNew< float, EPropertyTypeNew::Fl
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CFloatProperty()
|
||||
: TNumericalPropertyNew()
|
||||
CFloatProperty(EGame Game)
|
||||
: TNumericalPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CGuidProperty : public TTypedPropertyNew< std::vector<char>, EPropertyType
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CGuidProperty()
|
||||
: TTypedPropertyNew()
|
||||
CGuidProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CIntProperty : public TNumericalPropertyNew< s32, EPropertyTypeNew::Int >
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CIntProperty()
|
||||
: TNumericalPropertyNew()
|
||||
CIntProperty(EGame Game)
|
||||
: TNumericalPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
class CPointerProperty : public TTypedPropertyNew<void*, EPropertyTypeNew::Pointer>
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class IPropertyNew;
|
||||
|
||||
CPointerProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual bool IsPointerType() const
|
||||
{
|
||||
|
|
|
@ -8,8 +8,8 @@ class CSequenceProperty : public TTypedPropertyNew< s32, EPropertyTypeNew::Seque
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CSequenceProperty()
|
||||
: TTypedPropertyNew()
|
||||
CSequenceProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
{}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& rArc) const
|
||||
|
|
|
@ -8,8 +8,8 @@ class CShortProperty : public TNumericalPropertyNew< s16, EPropertyTypeNew::Shor
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CShortProperty()
|
||||
: TNumericalPropertyNew()
|
||||
CShortProperty(EGame Game)
|
||||
: TNumericalPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CSoundProperty : public TSerializeableTypedProperty< s32, EPropertyTypeNew
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CSoundProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CSoundProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CSplineProperty : public TTypedPropertyNew< std::vector<char>, EPropertyTy
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CSplineProperty()
|
||||
: TTypedPropertyNew()
|
||||
CSplineProperty(EGame Game)
|
||||
: TTypedPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -8,8 +8,8 @@ class CStringProperty : public TSerializeableTypedProperty< TString, EPropertyTy
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CStringProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CStringProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
|
|
|
@ -21,12 +21,8 @@ u32 CStructPropertyNew::DataSize() const
|
|||
|
||||
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());
|
||||
// Structs are aligned to the first child property.
|
||||
return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment());
|
||||
}
|
||||
|
||||
void CStructPropertyNew::Construct(void* pData) const
|
||||
|
@ -67,16 +63,25 @@ void CStructPropertyNew::RevertToDefault(void* pData) const
|
|||
|
||||
const char* CStructPropertyNew::HashableTypeName() const
|
||||
{
|
||||
if (IsArchetype() || !mpArchetype)
|
||||
return *mName;
|
||||
else
|
||||
return mpArchetype->HashableTypeName();
|
||||
return mpArchetype ? mpArchetype->HashableTypeName() : *mName;
|
||||
}
|
||||
|
||||
void CStructPropertyNew::Serialize(IArchive& rArc)
|
||||
{
|
||||
IPropertyNew::Serialize(rArc);
|
||||
|
||||
// Serialize atomic flag
|
||||
bool Atomic = IsAtomic();
|
||||
rArc << SerialParameter("Atomic", Atomic, SH_Optional, false);
|
||||
|
||||
if (rArc.IsReader())
|
||||
{
|
||||
if (Atomic)
|
||||
mFlags.SetFlag(EPropertyFlag::IsAtomic);
|
||||
else
|
||||
mFlags.ClearFlag(EPropertyFlag::IsAtomic);
|
||||
}
|
||||
|
||||
// Serialize archetype
|
||||
if (mpArchetype)
|
||||
{
|
||||
|
@ -96,13 +101,13 @@ void CStructPropertyNew::Serialize(IArchive& rArc)
|
|||
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
|
||||
// We don't really need the type, but it's a good sanity check, and it's also good practice
|
||||
// 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);
|
||||
<< SerialParameter("ID", ChildID, SH_Attribute | SH_HexDisplay );
|
||||
|
||||
IPropertyNew* pChild = ChildByID(ChildID);
|
||||
ASSERT(pChild != nullptr && pChild->Type() == ChildType);
|
||||
|
@ -154,6 +159,21 @@ void CStructPropertyNew::SerializeValue(void* pData, IArchive& Arc) const
|
|||
}
|
||||
}
|
||||
|
||||
void CStructPropertyNew::InitFromArchetype(IPropertyNew* pOther)
|
||||
{
|
||||
IPropertyNew::InitFromArchetype(pOther);
|
||||
|
||||
// Copy children
|
||||
_ClearChildren();
|
||||
mChildren.reserve( pOther->NumChildren() );
|
||||
|
||||
for (u32 ChildIdx = 0; ChildIdx < pOther->NumChildren(); ChildIdx++)
|
||||
{
|
||||
IPropertyNew* pChild = CreateCopy( pOther->ChildByIndex(ChildIdx) );
|
||||
mChildren.push_back( pChild );
|
||||
}
|
||||
}
|
||||
|
||||
bool CStructPropertyNew::ShouldSerialize() const
|
||||
{
|
||||
if (IPropertyNew::ShouldSerialize())
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
class CStructPropertyNew : public IPropertyNew
|
||||
{
|
||||
friend class CTemplateLoader;
|
||||
friend class IPropertyNew;
|
||||
|
||||
public:
|
||||
// Must be a valid type for TPropertyRef
|
||||
|
@ -15,6 +16,10 @@ protected:
|
|||
/** For archetypes, the filename of the template XML file. */
|
||||
TString mTemplateFileName;
|
||||
|
||||
CStructPropertyNew(EGame Game)
|
||||
: IPropertyNew(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual EPropertyTypeNew Type() const;
|
||||
virtual u32 DataSize() const;
|
||||
|
@ -26,6 +31,7 @@ public:
|
|||
virtual const char* HashableTypeName() const;
|
||||
virtual void Serialize(IArchive& rArc);
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const;
|
||||
virtual void InitFromArchetype(IPropertyNew* pOther);
|
||||
virtual bool ShouldSerialize() const;
|
||||
virtual TString GetTemplateFileName();
|
||||
|
||||
|
|
|
@ -8,19 +8,16 @@ class CVectorProperty : public TSerializeableTypedProperty< CVector3f, EProperty
|
|||
friend class IPropertyNew;
|
||||
|
||||
protected:
|
||||
CVectorProperty()
|
||||
: TSerializeableTypedProperty()
|
||||
CVectorProperty(EGame Game)
|
||||
: TSerializeableTypedProperty(Game)
|
||||
{}
|
||||
|
||||
public:
|
||||
virtual void PostInitialize()
|
||||
virtual void PostInitialize() override
|
||||
{
|
||||
IPropertyNew* pX = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
IPropertyNew* pY = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
IPropertyNew* pZ = Create(EPropertyTypeNew::Float, this, mGame, mpScriptTemplate);
|
||||
pX->SetName("X");
|
||||
pY->SetName("Y");
|
||||
pZ->SetName("Z");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 0, "X");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 4, "Y");
|
||||
CreateIntrinsic(EPropertyTypeNew::Float, this, mOffset + 8, "Z");
|
||||
}
|
||||
|
||||
virtual void SerializeValue(void* pData, IArchive& Arc) const
|
||||
|
|
|
@ -235,7 +235,11 @@ void CPropertyView::CreateContextMenu(const QPoint& rkPos)
|
|||
mpMenuProperty = pProp;
|
||||
|
||||
QMenu Menu;
|
||||
|
||||
if (!pProp->IsIntrinsic())
|
||||
{
|
||||
Menu.addAction(mpEditTemplateAction);
|
||||
}
|
||||
|
||||
if (mpEditor->CurrentGame() >= eEchoesDemo)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue