Massive overhaul of property system done over the last few months. There is unfinished/broken stuff still, but it compiles now.

This commit is contained in:
Aruki 2018-06-22 15:24:04 -06:00
parent 7099b97529
commit ce3dfdc397
174 changed files with 4570 additions and 2050 deletions

View File

@ -1,8 +1,13 @@
# CONFIG += PUBLIC_RELEASE
win32: {
QMAKE_CXXFLAGS += /WX \ # Treat warnings as errors
/wd4267 # Disable C4267: conversion from 'size_t' to 'type', possible loss of data
QMAKE_CXXFLAGS += /WX \ # Treat warnings as errors
/wd4267 \ # Disable C4267: conversion from 'size_t' to 'type', possible loss of data
/wd4100 \ # Disable C4100: unreferenced formal parameter
/wd4101 \ # Disable C4101: unreferenced local variable
/wd4189 # Disable C4189: local variable is initialized but not referenced
QMAKE_CXXFLAGS_WARN_ON -= -w34100 -w34189 # Override C4100 and C4189 being set to w3 in Qt's default .qmake.conf file
}
BUILD_DIR = $$PWD/../build

View File

@ -1,6 +1,7 @@
#ifndef COMMON_H
#define COMMON_H
#include "types.h"
#include "AssertMacro.h"
#include "CAssetID.h"
#include "CColor.h"
@ -15,10 +16,13 @@
#include "Flags.h"
#include "Log.h"
#include "TString.h"
#include "types.h"
#include "Hash/CCRC32.h"
#include "Hash/CFNV1A.h"
#include "Serialization/Binary.h"
#include "Serialization/XML.h"
#include "NBasics.h"
// temporary home for ALIGN macro, moving later
#define ALIGN(Val, Align) ((Val + (Align-1)) & ~(Align-1))
#endif // COMMON_H

View File

@ -84,7 +84,8 @@ HEADERS += \
FileIO\CFileLock.h \
FileIO.h \
Common.h \
Hash/CCRC32.h
Hash/CCRC32.h \
NBasics.h
# Source Files
SOURCES += \

View File

@ -1,10 +1,10 @@
#include "CVectorOutStream.h"
#include "Common/Common.h"
CVectorOutStream::CVectorOutStream()
: mpVector(new std::vector<char>)
, mOwnsVector(true)
, mPos(0)
, mUsed(0)
{
mDataEndianness = IOUtil::eBigEndian;
}
@ -13,7 +13,6 @@ CVectorOutStream::CVectorOutStream(IOUtil::EEndianness DataEndianness)
: mpVector(new std::vector<char>)
, mOwnsVector(true)
, mPos(0)
, mUsed(0)
{
mDataEndianness = DataEndianness;
}
@ -22,7 +21,6 @@ CVectorOutStream::CVectorOutStream(u32 InitialSize, IOUtil::EEndianness DataEndi
: mpVector(new std::vector<char>(InitialSize))
, mOwnsVector(true)
, mPos(0)
, mUsed(0)
{
mDataEndianness = DataEndianness;
}
@ -31,7 +29,6 @@ CVectorOutStream::CVectorOutStream(std::vector<char> *pVector, IOUtil::EEndianne
: mpVector(pVector)
, mOwnsVector(false)
, mPos(0)
, mUsed(0)
{
mDataEndianness = DataEndianness;
}
@ -45,12 +42,18 @@ void CVectorOutStream::WriteBytes(const void *pkSrc, u32 Count)
{
if (!IsValid()) return;
if ((mPos + Count) > mpVector->size())
mpVector->resize(mPos + Count);
u32 NewSize = mPos + Count;
if (NewSize > mpVector->size())
{
if (NewSize > mpVector->capacity())
mpVector->reserve( ALIGN(mPos + Count, skAllocSize) );
mpVector->resize(NewSize);
}
memcpy(mpVector->data() + mPos, pkSrc, Count);
mPos += Count;
if (mPos > mUsed) mUsed = mPos;
}
bool CVectorOutStream::Seek(s32 Offset, u32 Origin)
@ -68,7 +71,7 @@ bool CVectorOutStream::Seek(s32 Offset, u32 Origin)
break;
case SEEK_END:
mPos = mUsed - Offset;
mPos = mpVector->size() - Offset;
break;
default:
@ -81,9 +84,6 @@ bool CVectorOutStream::Seek(s32 Offset, u32 Origin)
return false;
}
if (mPos > mUsed)
mUsed = mPos;
if (mPos > mpVector->size())
mpVector->resize(mPos);
@ -107,20 +107,19 @@ bool CVectorOutStream::IsValid() const
u32 CVectorOutStream::Size() const
{
return mUsed;
}
u32 CVectorOutStream::SizeRemaining() const
{
return mpVector->size() - mPos;
return mPos;
}
void CVectorOutStream::SetVector(std::vector<char> *pVector)
{
if (mOwnsVector) delete mpVector;
if (mOwnsVector)
{
delete mpVector;
mOwnsVector = false;
}
mpVector = pVector;
mPos = 0;
mUsed = 0;
}
void* CVectorOutStream::Data()
@ -133,24 +132,8 @@ void* CVectorOutStream::DataAtPosition()
return mpVector->data() + mPos;
}
void CVectorOutStream::Expand(u32 Amount)
{
mpVector->resize(mpVector->size() + Amount);
}
void CVectorOutStream::Shrink()
{
mpVector->resize(mUsed);
}
void CVectorOutStream::Reset()
{
mPos = 0;
mUsed = 0;
}
void CVectorOutStream::Clear()
{
mPos = 0;
mpVector->clear();
Reset();
}

View File

@ -6,10 +6,11 @@
class CVectorOutStream : public IOutputStream
{
static const u32 skAllocSize = 1024; // must be power of 2
std::vector<char> *mpVector;
bool mOwnsVector;
u32 mPos;
u32 mUsed;
public:
CVectorOutStream();
@ -24,13 +25,9 @@ public:
bool EoF() const;
bool IsValid() const;
u32 Size() const;
u32 SizeRemaining() const;
void SetVector(std::vector<char> *pVector);
void *Data();
void *DataAtPosition();
void Expand(u32 Amount);
void Shrink();
void Reset();
void Clear();
};

View File

@ -13,7 +13,7 @@ public:
TFlags() : mValue(0) {}
TFlags(int Val) : mValue(Val) {}
TFlags(u32 Val) : mValue(Val) {}
TFlags(FlagEnum Val) : mValue(Val) {}
TFlags(FlagEnum Val) : mValue((u32) Val) {}
inline operator int() const { return mValue; }
inline bool operator!() const { return !mValue; }
@ -22,25 +22,41 @@ public:
inline void operator&=(int Mask) { mValue &= Mask; }
inline void operator&=(u32 Mask) { mValue &= Mask; }
inline void operator|=(TFlags Flags) { mValue |= Flags.mValue; }
inline void operator|=(FlagEnum Flag) { mValue |= Flag; }
inline void operator|=(FlagEnum Flag) { mValue |= (u32) Flag; }
inline TFlags operator|(TFlags Flags) const { return TFlags(FlagEnum(mValue | Flags.mValue)); }
inline TFlags operator|(FlagEnum Flag) const { return TFlags(FlagEnum(mValue | Flag)); }
inline TFlags operator|(FlagEnum Flag) const { return TFlags(FlagEnum(mValue | (u32) Flag)); }
inline TFlags operator&(int Mask) const { return TFlags(FlagEnum(mValue & Mask)); }
inline TFlags operator&(u32 Mask) const { return TFlags(FlagEnum(mValue & Mask)); }
inline TFlags operator&(FlagEnum Flag) const { return TFlags(FlagEnum(mValue & Flag)); }
inline TFlags operator&(FlagEnum Flag) const { return TFlags(FlagEnum(mValue & (u32) Flag)); }
inline bool HasFlag(FlagEnum Flag) const { return ((mValue & Flag) != 0); }
inline bool HasFlag(FlagEnum Flag) const { return ((mValue & (u32) Flag) != 0); }
inline bool HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); }
inline bool HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); }
inline void SetFlag(FlagEnum Flag) { mValue |= Flag; }
inline void SetFlag(FlagEnum Flag) { mValue |= (u32) Flag; }
inline void SetFlag(TFlags Flags) { mValue |= Flags; }
inline void ClearFlag(FlagEnum Flag) { mValue &= ~Flag; }
inline void ClearFlag(FlagEnum Flag) { mValue &= ~((u32) Flag); }
inline void ClearFlag(TFlags Flags) { mValue &= ~Flags; }
inline void Serialize(IArchive& rArc) { rArc.SerializeHexPrimitive(mValue); }
};
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;
// Alternate version for enum class flags
#define DECLARE_FLAGS_ENUMCLASS(Enum, FlagTypeName) \
DECLARE_FLAGS(Enum, FlagTypeName) \
inline int operator|(Enum Left, Enum Right) \
{ \
return (int) Left | (int) Right; \
} \
inline int operator&(Enum Left, Enum Right) \
{ \
return (int) Left & (int) Right; \
} \
inline int operator~(Enum Value) \
{ \
return ~((int) Value); \
} \
#endif // FLAGS_H

45
src/Common/NBasics.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef NBASICS_H
#define NBASICS_H
#include "types.h"
#include <vector>
namespace NBasics
{
/** Remove an element from a vector */
template<typename T>
bool VectorRemoveOne(std::vector<T>& rVector, const T& rkElement)
{
for (auto Iter = rVector.begin(); Iter != rVector.end(); Iter++)
{
if (*Iter == rkElement)
{
rVector.erase(Iter);
return true;
}
}
return false;
}
/** Remove all occurrences of an element from a vector. Returns the number of elements that were removed. */
template<typename T>
int VectorRemoveAll(std::vector<T>& rVector, const T& rkElement)
{
int NumRemoved = 0;
for (auto Iter = rVector.begin(); Iter != rVector.end(); Iter++)
{
if (*Iter == rkElement)
{
Iter = rVector.erase(Iter);
NumRemoved++;
}
}
return NumRemoved;
}
}
#endif // NBASICS_H

View File

@ -40,6 +40,15 @@ public:
SetVersion(rkVersion);
}
CBasicBinaryReader(void *pData, u32 DataSize, const CSerialVersion& rkVersion, IOUtil::EEndianness Endian = IOUtil::kSystemEndianness)
: IArchive(true, false)
, mMagicValid(true)
, mOwnsStream(true)
{
mpStream = new CMemoryInStream(pData, DataSize, Endian);
SetVersion(rkVersion);
}
~CBasicBinaryReader()
{
if (mOwnsStream) delete mpStream;
@ -74,6 +83,8 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); }
virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); }
virtual void BulkSerialize(void* pData, u32 Size) { mpStream->ReadBytes(pData, Size); }
};
#endif // CBASICBINARYREADER

View File

@ -88,6 +88,8 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); }
virtual void SerializeHexPrimitive(u32& rValue) { mpStream->WriteLong(rValue); }
virtual void SerializeHexPrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); }
virtual void BulkSerialize(void* pData, u32 Size) { mpStream->WriteBytes(pData, Size); }
};
#endif // CBASICBINARYWRITER

View File

@ -177,6 +177,8 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); }
virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); }
virtual void BulkSerialize(void* pData, u32 Size) { mpStream->ReadBytes(pData, Size); }
};
#endif // CBINARYREADER

View File

@ -164,6 +164,8 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { mpStream->WriteShort(rValue); }
virtual void SerializeHexPrimitive(u32& rValue) { mpStream->WriteLong(rValue); }
virtual void SerializeHexPrimitive(u64& rValue) { mpStream->WriteLongLong(rValue); }
virtual void BulkSerialize(void* pData, u32 Size) { mpStream->WriteBytes(pData, Size); }
};
#endif // CBINARYWRITER

View File

@ -135,6 +135,19 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = (u32) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u64& rValue) { rValue = (u64) ReadParam().ToInt32(16); }
virtual void BulkSerialize(void* pData, u32 Size)
{
char* pCharData = (char*) pData;
TString StringData = ReadParam();
ASSERT(StringData.Size() == Size*2);
for (u32 ByteIdx = 0; ByteIdx < Size; ByteIdx++)
{
*pCharData = (char) StringData.SubString(ByteIdx*2, 2).ToInt32(16);
pCharData++;
}
}
};
#endif // CXMLREADER

View File

@ -122,6 +122,17 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); }
virtual void SerializeHexPrimitive(u32& rValue) { WriteParam(*TString::HexString(rValue, 8)); }
virtual void SerializeHexPrimitive(u64& rValue) { WriteParam(*TString::HexString((u32) rValue, 16)); }
virtual void BulkSerialize(void* pData, u32 Size)
{
char* pCharData = (char*) pData;
TString OutString(Size*2);
for (u32 ByteIdx = 0; ByteIdx < Size; ByteIdx++)
itoa(pCharData[ByteIdx], &OutString[ByteIdx*2], 16);
WriteParam(*OutString);
}
};
#endif // CXMLWRITER

View File

@ -404,6 +404,21 @@ public:
virtual void SerializeHexPrimitive(u32& rValue) = 0;
virtual void SerializeHexPrimitive(u64& rValue) = 0;
virtual void BulkSerialize(void* pData, u32 DataSize) = 0;
void SerializeBulkData(std::vector<char>& InArray)
{
u32 Size = InArray.size();
SerializeContainerSize(Size, "Size");
if (IsReader())
{
InArray.resize(Size);
}
BulkSerialize(InArray.data(), Size);
}
// Accessors
inline u16 ArchiveVersion() const { return mArchiveVersion; }
inline u16 FileVersion() const { return mFileVersion; }

View File

@ -1,4 +1,5 @@
#include "TString.h"
#include "Hash/CCRC32.h"
#include "Hash/CFNV1A.h"
#include <FileIO/IOUtil.h>
#include <codecvt>
@ -7,13 +8,14 @@
// ************ TString ************
u32 TString::Hash32() const
{
CFNV1A Hash(CFNV1A::e32Bit);
Hash.HashString(*this);
return Hash.GetHash32();
CCRC32 Hash;
Hash.Hash(**this);
return Hash.Digest();
}
u64 TString::Hash64() const
{
// todo: replace with MD5
CFNV1A Hash(CFNV1A::e64Bit);
Hash.HashString(*this);
return Hash.GetHash64();

View File

@ -932,46 +932,7 @@ public:
static _TString FromFloat(float Value, int MinDecimals = 1)
{
// Initial float -> string conversion
std::basic_stringstream<CharType> SStream;
if (MinDecimals > 0) SStream.setf(std::ios_base::showpoint);
SStream.setf(std::ios_base::fixed, std::ios_base::floatfield);
SStream << Value;
_TString Out = SStream.str();
// Make sure we have the right number of decimals
int DecIdx = Out.IndexOf(CHAR_LITERAL('.'));
if (DecIdx == -1 && MinDecimals > 0)
{
DecIdx = Out.Size();
Out.Append(CHAR_LITERAL('.'));
}
int NumZeroes = (DecIdx == -1 ? 0 : Out.Size() - (DecIdx + 1));
// Add extra zeroes to meet the minimum decimal count
if (NumZeroes < MinDecimals)
{
for (int iDec = 0; iDec < (MinDecimals - NumZeroes); iDec++)
Out.Append(CHAR_LITERAL('.'));
}
// Remove unnecessary trailing zeroes from the end of the string
else if (NumZeroes > MinDecimals)
{
while (Out.Back() == CHAR_LITERAL('0') && NumZeroes > MinDecimals && NumZeroes > 0)
{
Out = Out.ChopBack(1);
NumZeroes--;
}
// Remove decimal point
if (NumZeroes == 0)
Out = Out.ChopBack(1);
}
return Out;
return Format("%f.*", Value, MinDecimals);
}
static _TString FileSizeString(u64 Size, u32 NumDecimals = 2)

View File

@ -13,48 +13,30 @@ CAreaAttributes::~CAreaAttributes()
void CAreaAttributes::SetObject(CScriptObject *pObj)
{
mpObj = pObj;
mGame = pObj->Template()->MasterTemplate()->Game();
CScriptTemplate* pTemplate = pObj->Template();
CStructPropertyNew* pProperties = pTemplate->Properties();
mpObject = pObj;
mGame = pTemplate->MasterTemplate()->Game();
mNeedSky = CBoolRef(pObj, pProperties->ChildByIndex(1));
if (mGame == ePrime)
mOverrideSky = CAssetRef(pObj, pProperties->ChildByIndex(7));
else if (mGame > ePrime)
mOverrideSky = CAssetRef(pObj, pProperties->ChildByID(0xD208C9FA));
}
bool CAreaAttributes::IsLayerEnabled() const
{
return mpObj->Layer()->IsActive();
return mpObject->Layer()->IsActive();
}
bool CAreaAttributes::IsSkyEnabled() const
{
CPropertyStruct *pBaseStruct = mpObj->Properties();
switch (mGame)
{
case ePrime:
case eEchoesDemo:
case eEchoes:
case eCorruptionProto:
case eCorruption:
case eReturns:
return static_cast<TBoolProperty*>(pBaseStruct->PropertyByIndex(1))->Get();
default:
return false;
}
return mNeedSky.IsValid() ? mNeedSky.Get() : false;
}
CModel* CAreaAttributes::SkyModel() const
{
CPropertyStruct *pBaseStruct = mpObj->Properties();
switch (mGame)
{
case ePrime:
return gpResourceStore->LoadResource<CModel>( static_cast<TAssetProperty*>(pBaseStruct->PropertyByIndex(7))->Get() );
case eEchoesDemo:
case eEchoes:
case eCorruptionProto:
case eCorruption:
case eReturns:
return gpResourceStore->LoadResource<CModel>( static_cast<TAssetProperty*>(pBaseStruct->PropertyByID(0xD208C9FA))->Get() );
default:
return nullptr;
}
return mOverrideSky.IsValid() ? gpResourceStore->LoadResource<CModel>(mOverrideSky.Get()) : nullptr;
}

View File

@ -2,11 +2,15 @@
#define CAREAATTRIBUTES_H
#include "Core/Resource/Script/CScriptObject.h"
#include "Core/Resource/Script/Property/Properties.h"
class CAreaAttributes
{
CScriptObject* mpObject;
EGame mGame;
CScriptObject *mpObj;
CBoolRef mNeedSky;
CAssetRef mOverrideSky;
public:
CAreaAttributes(CScriptObject *pObj);
@ -16,7 +20,7 @@ public:
bool IsSkyEnabled() const;
CModel* SkyModel() const;
inline CScriptObject* Instance() const { return mpObj; }
inline CScriptObject* Instance() const { return mpObject; }
};
#endif // CAREAATTRIBUTES_H

View File

@ -2,7 +2,7 @@
#define CLIGHTPARAMETERS_H
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Script/IProperty.h"
#include "Core/Resource/Script/Property/Properties.h"
enum EWorldLightingOptions
{
@ -14,48 +14,35 @@ enum EWorldLightingOptions
class CLightParameters
{
CPropertyStruct *mpStruct;
EGame mGame;
TLongProperty *mpLightLayer;
TEnumProperty *mpWorldLightingOptions;
CIntRef mLightLayer;
TEnumRef<EWorldLightingOptions> mWorldLightingOptions;
public:
CLightParameters(CPropertyStruct *pStruct, EGame Game)
: mpStruct(pStruct)
, mGame(Game)
, mpLightLayer(nullptr)
, mpWorldLightingOptions(nullptr)
CLightParameters(CStructRef InStruct, EGame Game)
{
if (mpStruct)
if (InStruct.IsValid())
{
if (mGame <= ePrime)
if (Game <= ePrime)
{
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByIndex(0x7));
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByIndex(0xD));
mWorldLightingOptions = TEnumRef<EWorldLightingOptions>(InStruct.Object(), InStruct.Property()->ChildByIndex(0x7));
mLightLayer = CIntRef(InStruct.Object(), InStruct.Property()->ChildByIndex(0xD));
}
else
{
mpWorldLightingOptions = TPropCast<TEnumProperty>(mpStruct->PropertyByID(0x6B5E7509));
mpLightLayer = TPropCast<TLongProperty>(mpStruct->PropertyByID(0x1F715FD3));
mWorldLightingOptions = TEnumRef<EWorldLightingOptions>(InStruct.Object(), InStruct.Property()->ChildByID(0x6B5E7509));
mLightLayer = CIntRef(InStruct.Object(), InStruct.Property()->ChildByID(0x1F715FD3));
}
}
}
inline int LightLayerIndex() const
{
if (!mpLightLayer)
return 0;
else
return mpLightLayer->Get();
return mLightLayer.IsValid() ? mLightLayer.Get() : 0;
}
inline EWorldLightingOptions WorldLightingOptions() const
{
if (mpWorldLightingOptions)
return (EWorldLightingOptions) mpWorldLightingOptions->Get();
else
return eNormalLighting;
return mWorldLightingOptions.IsValid() ? mWorldLightingOptions.Get() : eNormalLighting;
}
};

View File

@ -232,7 +232,31 @@ HEADERS += \
IUIRelay.h \
Resource/CResTypeFilter.h \
GameProject/COpeningBanner.h \
Resource/Script/CPropertyNameGenerator.h
Resource/Script/CPropertyNameGenerator.h \
Resource/Script/IPropertyNew.h \
Resource/Script/TPropertyProxy.h \
Resource/Script/Property/CEnumProperty.h \
Resource/Script/Property/CFlagsProperty.h \
Resource/Script/Property/CAssetProperty.h \
Resource/Script/Property/CPointerProperty.h \
Resource/Script/Property/CArrayProperty.h \
Resource/Script/Property/Properties.h \
Resource/Script/Property/TPropertyRef.h \
Resource/Script/Property/CBoolProperty.h \
Resource/Script/Property/CByteProperty.h \
Resource/Script/Property/CShortProperty.h \
Resource/Script/Property/CIntProperty.h \
Resource/Script/Property/CFloatProperty.h \
Resource/Script/Property/CStringProperty.h \
Resource/Script/Property/CSoundProperty.h \
Resource/Script/Property/CAnimationProperty.h \
Resource/Script/Property/CSequenceProperty.h \
Resource/Script/Property/CSplineProperty.h \
Resource/Script/Property/CAnimationSetProperty.h \
Resource/Script/Property/CVectorProperty.h \
Resource/Script/Property/CColorProperty.h \
Resource/Script/Property/CStructProperty.h \
Resource/Script/Property/CGuidProperty.h
# Source Files
SOURCES += \
@ -342,4 +366,5 @@ SOURCES += \
IUIRelay.cpp \
GameProject\COpeningBanner.cpp \
IProgressNotifier.cpp \
Resource/Script/CPropertyNameGenerator.cpp
Resource/Script/CPropertyNameGenerator.cpp \
Resource/Script/IPropertyNew.cpp

View File

@ -283,7 +283,8 @@ void GenerateAssetNames(CGameProject *pProj)
for (u32 iInst = 0; iInst < pLayer->NumInstances(); iInst++)
{
CScriptObject *pInst = pLayer->InstanceByIndex(iInst);
CScriptObject* pInst = pLayer->InstanceByIndex(iInst);
CStructPropertyNew* pProperties = pInst->Template()->Properties();
if (pInst->ObjectTypeID() == 0x42 || pInst->ObjectTypeID() == FOURCC('POIN'))
{
@ -292,12 +293,12 @@ void GenerateAssetNames(CGameProject *pProj)
if (Name.StartsWith("POI_", false))
{
TIDString ScanIDString = (pProj->Game() <= ePrime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7");
TAssetProperty *pScanProperty = TPropCast<TAssetProperty>(pInst->PropertyByIDString(ScanIDString));
CAssetProperty *pScanProperty = TPropCast<CAssetProperty>(pProperties->ChildByIDString(ScanIDString));
ASSERT(pScanProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pScanProperty)
{
CAssetID ScanID = pScanProperty->Get();
CAssetID ScanID = pScanProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(ScanID);
if (pEntry && !pEntry->IsNamed())
@ -327,12 +328,12 @@ void GenerateAssetNames(CGameProject *pProj)
if (Name.EndsWith(".STRG", false))
{
u32 StringPropID = (pProj->Game() <= ePrime ? 0x4 : 0x9182250C);
TAssetProperty *pStringProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(StringPropID));
CAssetProperty *pStringProperty = TPropCast<CAssetProperty>(pProperties->ChildByID(StringPropID));
ASSERT(pStringProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pStringProperty)
{
CAssetID StringID = pStringProperty->Get();
CAssetID StringID = pStringProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(StringID);
if (pEntry && !pEntry->IsNamed())
@ -353,12 +354,12 @@ void GenerateAssetNames(CGameProject *pProj)
pInst->ObjectTypeID() == 0x8 || pInst->ObjectTypeID() == FOURCC('PLAT'))
{
u32 ModelPropID = (pProj->Game() <= ePrime ? (pInst->ObjectTypeID() == 0x0 ? 0xA : 0x6) : 0xC27FFA8F);
TAssetProperty *pModelProperty = TPropCast<TAssetProperty>(pInst->Properties()->PropertyByID(ModelPropID));
CAssetProperty *pModelProperty = TPropCast<CAssetProperty>(pProperties->ChildByID(ModelPropID));
ASSERT(pModelProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pModelProperty)
{
CAssetID ModelID = pModelProperty->Get();
CAssetID ModelID = pModelProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(ModelID);
if (pEntry && !pEntry->IsCategorized())

View File

@ -132,28 +132,32 @@ CScriptInstanceDependency* CScriptInstanceDependency::BuildTree(CScriptObject *p
{
CScriptInstanceDependency *pInst = new CScriptInstanceDependency();
pInst->mObjectType = pInstance->ObjectTypeID();
ParseStructDependencies(pInst, pInstance->Properties());
ParseStructDependencies(pInst, pInstance, pInstance->Template()->Properties());
return pInst;
}
void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependency *pInst, CPropertyStruct *pStruct)
void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependency* pInst, CScriptObject* pInstance, CStructPropertyNew *pStruct)
{
// Recursive function for parsing script dependencies and loading them into the script instance dependency
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
void* pPropertyData = pInstance->PropertyData();
for (u32 PropertyIdx = 0; PropertyIdx < pStruct->NumChildren(); PropertyIdx++)
{
IProperty *pProp = pStruct->PropertyByIndex(iProp);
EPropertyType Type = pProp->Type();
IPropertyNew *pProp = pStruct->ChildByIndex(PropertyIdx);
EPropertyTypeNew Type = pProp->Type();
if (Type == eStructProperty || Type == eArrayProperty)
ParseStructDependencies(pInst, static_cast<CPropertyStruct*>(pProp));
// Technically we aren't parsing array children, but it's not really worth refactoring this function
// to support it when there aren't any array properties that contain any asset references anyway...
if (Type == EPropertyTypeNew::Struct)
ParseStructDependencies(pInst, pInstance, TPropCast<CStructPropertyNew>(pProp));
else if (Type == eSoundProperty)
else if (Type == EPropertyTypeNew::Sound)
{
u32 SoundID = static_cast<TSoundProperty*>(pProp)->Get();
u32 SoundID = TPropCast<CSoundProperty>(pProp)->Value(pPropertyData);
if (SoundID != -1)
{
CGameProject *pProj = pStruct->Instance()->Area()->Entry()->Project();
CGameProject *pProj = pInstance->Area()->Entry()->Project();
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
if (Info.pAudioGroup)
@ -164,9 +168,9 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
}
}
else if (Type == eAssetProperty)
else if (Type == EPropertyTypeNew::Asset)
{
CAssetID ID = static_cast<TAssetProperty*>(pProp)->Get();
CAssetID ID = TPropCast<CAssetProperty>(pProp)->Value(pPropertyData);
if (ID.IsValid())
{
@ -175,16 +179,15 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc
}
}
else if (Type == eCharacterProperty)
else if (Type == EPropertyTypeNew::AnimationSet)
{
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
CAnimationParameters Params = pChar->Get();
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(pPropertyData);
CAssetID ID = Params.ID();
if (ID.IsValid())
{
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier
if (pStruct->Instance()->Area()->Game() <= eEchoes)
if (pStruct->Game() <= eEchoes)
{
CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex());
pInst->mChildren.push_back(pDep);

View File

@ -8,7 +8,7 @@
class CScriptLayer;
class CScriptObject;
class CPropertyStruct;
class CStructPropertyNew;
class CAnimSet;
class CAnimationParameters;
struct SSetCharacter;
@ -142,7 +142,7 @@ public:
// Static
static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance);
protected:
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CPropertyStruct *pStruct);
static void ParseStructDependencies(CScriptInstanceDependency *pTree, CScriptObject* pInstance, CStructPropertyNew *pStruct);
};
// Node representing an animset character. Indicates what index the character is within the animset.

View File

@ -136,6 +136,25 @@ void CAnimationParameters::Write(IOutputStream& rSCLY)
}
}
void CAnimationParameters::Serialize(IArchive& rArc)
{
if (rArc.IsReader())
mGame = rArc.Game();
rArc << SERIAL("AnimationSetAsset", mCharacterID);
if (mGame <= eEchoes)
rArc << SERIAL("CharacterID", mCharIndex);
rArc << SERIAL("AnimationID", mAnimIndex);
if (mGame >= eReturns)
{
rArc << SERIAL("Unknown0", mUnknown2)
<< SERIAL("Unknown1", mUnknown3);
}
}
const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(s32 NodeIndex /*= -1*/)
{
CAnimSet *pSet = AnimSet();

View File

@ -20,6 +20,7 @@ public:
CAnimationParameters(EGame Game);
CAnimationParameters(IInputStream& rSCLY, EGame Game);
void Write(IOutputStream& rSCLY);
void Serialize(IArchive& rArc);
const SSetCharacter* GetCurrentSetCharacter(s32 NodeIndex = -1);
CModel* GetCurrentModel(s32 NodeIndex = -1);

View File

@ -47,6 +47,12 @@ public:
SetAcceptedTypes(Game, rkString.Split(","));
}
void Serialize(IArchive& rArc)
{
if (rArc.IsReader()) mGame = rArc.Game();
rArc << SERIAL_CONTAINER("AcceptedTypes", mAcceptedTypes, "Type");
}
inline bool Accepts(EResType Type) const
{
return mAcceptedTypes.find(Type) != mAcceptedTypes.end();

View File

@ -4,9 +4,10 @@
std::unordered_map<EResType, CResTypeInfo*> CResTypeInfo::smTypeMap;
CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName)
CResTypeInfo::CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension)
: mType(Type)
, mTypeName(rkTypeName)
, mRetroExtension(rkRetroExtension)
, mCanBeSerialized(false)
, mCanHaveDependencies(true)
{
@ -122,6 +123,27 @@ void Serialize(IArchive& rArc, CResTypeInfo*& rpType)
}
}
void Serialize(IArchive& rArc, EResType& rType)
{
CFourCC Extension;
if (rArc.IsWriter())
{
CResTypeInfo* pTypeInfo = CResTypeInfo::FindTypeInfo(rType);
ASSERT(pTypeInfo != nullptr);
Extension = pTypeInfo->CookedExtension(rArc.Game());
}
rArc.SerializePrimitive(Extension);
if (rArc.IsReader())
{
CResTypeInfo* pTypeInfo = CResTypeInfo::TypeForCookedExtension(rArc.Game(), Extension);
ASSERT(pTypeInfo != nullptr);
rType = pTypeInfo->Type();
}
}
// ************ CREATION ************
CResTypeInfo::CResTypeInfoFactory CResTypeInfo::smTypeInfoFactory;
@ -153,235 +175,235 @@ void CResTypeInfo::CResTypeInfoFactory::AddExtension(CResTypeInfo *pType, CFourC
void CResTypeInfo::CResTypeInfoFactory::InitTypes()
{
{
CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation");
CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation", "ani");
AddExtension(pType, "ANIM", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eAnimCollisionPrimData, "Animation Collision Primitive Data");
CResTypeInfo *pType = new CResTypeInfo(eAnimCollisionPrimData, "Animation Collision Primitive Data", "?");
AddExtension(pType, "CPRM", eReturns, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eAnimEventData, "Animation Event Data");
CResTypeInfo *pType = new CResTypeInfo(eAnimEventData, "Animation Event Data", "evnt");
AddExtension(pType, "EVNT", ePrimeDemo, ePrime);
}
{
CResTypeInfo *pType = new CResTypeInfo(eAnimSet, "Animation Character Set");
CResTypeInfo *pType = new CResTypeInfo(eAnimSet, "Animation Character Set", "acs");
AddExtension(pType, "ANCS", ePrimeDemo, eEchoes);
}
{
CResTypeInfo *pType = new CResTypeInfo(eArea, "Area");
CResTypeInfo *pType = new CResTypeInfo(eArea, "Area", "mrea");
AddExtension(pType, "MREA", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eAudioAmplitudeData, "Audio Amplitude Data");
CResTypeInfo *pType = new CResTypeInfo(eAudioAmplitudeData, "Audio Amplitude Data", "?");
AddExtension(pType, "CAAD", eCorruption, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eAudioGroup, "Audio Group");
CResTypeInfo *pType = new CResTypeInfo(eAudioGroup, "Audio Group", "agsc");
AddExtension(pType, "AGSC", ePrimeDemo, eEchoes);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro");
CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro", "caud");
AddExtension(pType, "CAUD", eCorruptionProto, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eAudioSample, "Audio Sample");
CResTypeInfo *pType = new CResTypeInfo(eAudioSample, "Audio Sample", "csmp");
AddExtension(pType, "CSMP", eCorruptionProto, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eAudioLookupTable, "Audio Lookup Table");
CResTypeInfo *pType = new CResTypeInfo(eAudioLookupTable, "Audio Lookup Table", "atbl");
AddExtension(pType, "ATBL", ePrimeDemo, eCorruption);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data");
CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data", "dat");
AddExtension(pType, "DUMB", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eBurstFireData, "Burst Fire Data");
CResTypeInfo *pType = new CResTypeInfo(eBurstFireData, "Burst Fire Data", "bfre.bfrc");
AddExtension(pType, "BFRC", eCorruptionProto, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character");
CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character", "char");
AddExtension(pType, "CHAR", eCorruptionProto, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group");
CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group", "?");
AddExtension(pType, "DGRP", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eDynamicCollision, "Dynamic Collision");
CResTypeInfo *pType = new CResTypeInfo(eDynamicCollision, "Dynamic Collision", "dcln");
AddExtension(pType, "DCLN", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eFont, "Font");
CResTypeInfo *pType = new CResTypeInfo(eFont, "Font", "rpff");
AddExtension(pType, "FONT", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eGuiFrame, "Gui Frame");
CResTypeInfo *pType = new CResTypeInfo(eGuiFrame, "Gui Frame", "frme");
AddExtension(pType, "FRME", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe");
CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe", "?");
AddExtension(pType, "KFAM", ePrimeDemo, ePrimeDemo);
}
{
CResTypeInfo *pType = new CResTypeInfo(eHintSystem, "Hint System Data");
CResTypeInfo *pType = new CResTypeInfo(eHintSystem, "Hint System Data", "hint");
AddExtension(pType, "HINT", ePrime, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eMapArea, "Area Map");
CResTypeInfo *pType = new CResTypeInfo(eMapArea, "Area Map", "mapa");
AddExtension(pType, "MAPA", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eMapWorld, "World Map");
CResTypeInfo *pType = new CResTypeInfo(eMapWorld, "World Map", "mapw");
AddExtension(pType, "MAPW", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eMapUniverse, "Universe Map");
CResTypeInfo *pType = new CResTypeInfo(eMapUniverse, "Universe Map", "mapu");
AddExtension(pType, "MAPU", ePrimeDemo, eEchoes);
}
{
CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI");
CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI", "?");
AddExtension(pType, "CSNG", ePrimeDemo, eEchoes);
}
{
CResTypeInfo *pType = new CResTypeInfo(eModel, "Model");
CResTypeInfo *pType = new CResTypeInfo(eModel, "Model", "cmdl");
AddExtension(pType, "CMDL", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticle, "Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticle, "Particle System", "gpsm.part");
AddExtension(pType, "PART", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleCollisionResponse, "Collision Response Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleCollisionResponse, "Collision Response Particle System", "crsm.crsc");
AddExtension(pType, "CRSC", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleDecal, "Decal Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleDecal, "Decal Particle System", "dpsm.dpsc");
AddExtension(pType, "DPSC", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleElectric, "Electric Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleElectric, "Electric Particle System", "elsm.elsc");
AddExtension(pType, "ELSC", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleSorted, "Sorted Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleSorted, "Sorted Particle System", "srsm.srsc");
AddExtension(pType, "SRSC", eEchoesDemo, eEchoes);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleSpawn, "Spawn Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleSpawn, "Spawn Particle System", "spsm.spsc");
AddExtension(pType, "SPSC", eEchoesDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleSwoosh, "Swoosh Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleSwoosh, "Swoosh Particle System", "swsh.swhc");
AddExtension(pType, "SWHC", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleTransform, "Transform Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleTransform, "Transform Particle System", "xfsm.xfsc");
AddExtension(pType, "XFSC", eReturns, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eParticleWeapon, "Weapon Particle System");
CResTypeInfo *pType = new CResTypeInfo(eParticleWeapon, "Weapon Particle System", "wpsm.wpsc");
AddExtension(pType, "WPSC", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(ePathfinding, "Pathfinding Mesh");
CResTypeInfo *pType = new CResTypeInfo(ePathfinding, "Pathfinding Mesh", "path");
AddExtension(pType, "PATH", ePrimeDemo, eCorruption);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area");
CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area", "?");
AddExtension(pType, "PTLA", eEchoesDemo, eCorruption);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set");
CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set", "rule");
AddExtension(pType, "RULE", eEchoesDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eSaveArea, "Area Save Info");
CResTypeInfo *pType = new CResTypeInfo(eSaveArea, "Area Save Info", "sava");
AddExtension(pType, "SAVA", eCorruptionProto, eCorruption);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eSaveWorld, "World Save Info");
CResTypeInfo *pType = new CResTypeInfo(eSaveWorld, "World Save Info", "savw");
AddExtension(pType, "SAVW", ePrime, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan");
CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan", "scan");
AddExtension(pType, "SCAN", ePrimeDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton");
CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton", "cin");
AddExtension(pType, "CINF", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin");
CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin", "cskr");
AddExtension(pType, "CSKR", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data");
CResTypeInfo *pType = new CResTypeInfo(eSourceAnimData, "Source Animation Data", "sand");
AddExtension(pType, "SAND", eCorruptionProto, eCorruption);
pType->mCanHaveDependencies = false; // all dependencies are added to the CHAR dependency tree
}
{
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive");
CResTypeInfo *pType = new CResTypeInfo(eSpatialPrimitive, "Spatial Primitive", "?");
AddExtension(pType, "CSPP", eEchoesDemo, eEchoes);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eStateMachine, "State Machine");
CResTypeInfo *pType = new CResTypeInfo(eStateMachine, "State Machine", "afsm");
AddExtension(pType, "AFSM", ePrimeDemo, eEchoes);
AddExtension(pType, "FSM2", eCorruptionProto, eCorruption);
AddExtension(pType, "FSMC", eReturns, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eStateMachine2, "State Machine 2");
CResTypeInfo *pType = new CResTypeInfo(eStateMachine2, "State Machine 2", "fsm2");
AddExtension(pType, "FSM2", eEchoesDemo, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eStaticGeometryMap, "Static Scan Map");
CResTypeInfo *pType = new CResTypeInfo(eStaticGeometryMap, "Static Scan Map", "egmc");
AddExtension(pType, "EGMC", eEchoesDemo, eCorruption);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio");
CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio", "?");
AddExtension(pType, "STRM", eCorruptionProto, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List");
CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List", "stlc");
AddExtension(pType, "STLC", eEchoesDemo, eCorruptionProto);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table");
CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table", "strg");
AddExtension(pType, "STRG", ePrimeDemo, eReturns);
}
{
CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture");
CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture", "txtr");
AddExtension(pType, "TXTR", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data");
CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data", "ctwk");
AddExtension(pType, "CTWK", ePrimeDemo, ePrime);
pType->mCanHaveDependencies = false;
}
{
CResTypeInfo *pType = new CResTypeInfo(eUserEvaluatorData, "User Evaluator Data");
CResTypeInfo *pType = new CResTypeInfo(eUserEvaluatorData, "User Evaluator Data", "user.usrc");
AddExtension(pType, "USRC", eCorruptionProto, eCorruption);
}
{
CResTypeInfo *pType = new CResTypeInfo(eWorld, "World");
CResTypeInfo *pType = new CResTypeInfo(eWorld, "World", "mwld");
AddExtension(pType, "MLVL", ePrimeDemo, eReturns);
pType->mCanBeSerialized = true;
}

View File

@ -20,13 +20,14 @@ class CResTypeInfo
EResType mType;
TString mTypeName;
std::vector<SGameExtension> mCookedExtensions;
TString mRetroExtension; // File extension in Retro's directory tree. We don't use it directly but it is needed for generating asset ID hashes
bool mCanBeSerialized;
bool mCanHaveDependencies;
static std::unordered_map<EResType, CResTypeInfo*> smTypeMap;
// Private Methods
CResTypeInfo(EResType Type, const TString& rkTypeName);
CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension);
~CResTypeInfo();
// Public Methods

View File

@ -1,118 +1,146 @@
#include "CScriptCooker.h"
#include "Core/Resource/Script/CLink.h"
#include <Core/Resource/Script/Property/CArrayProperty.h>
#include <Core/Resource/Script/Property/CAssetProperty.h>
#include <Core/Resource/Script/Property/CEnumProperty.h>
#include <Core/Resource/Script/Property/CFlagsProperty.h>
void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct)
void CScriptCooker::WriteProperty(IOutputStream& rOut, IPropertyNew* pProperty, bool InAtomicStruct)
{
u32 SizeOffset = 0, PropStart = 0;
void* pData = (mpArrayItemData ? mpArrayItemData : mpObject->PropertyData());
if (mGame >= eEchoesDemo && !InSingleStruct)
if (mGame >= eEchoesDemo && !InAtomicStruct)
{
rOut.WriteLong(pProp->ID());
rOut.WriteLong(pProperty->ID());
SizeOffset = rOut.Tell();
rOut.WriteShort(0x0);
PropStart = rOut.Tell();
}
switch (pProp->Type())
switch (pProperty->Type())
{
case eBoolProperty:
case EPropertyTypeNew::Bool:
{
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
rOut.WriteBool(pBoolCast->Get());
CBoolProperty* pBool = TPropCast<CBoolProperty>(pProperty);
rOut.WriteBool( pBool->Value(pData) );
break;
}
case eByteProperty:
case EPropertyTypeNew::Byte:
{
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
rOut.WriteByte(pByteCast->Get());
CByteProperty* pByte = TPropCast<CByteProperty>(pProperty);
rOut.WriteByte( pByte->Value(pData) );
break;
}
case eShortProperty:
case EPropertyTypeNew::Short:
{
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
rOut.WriteShort(pShortCast->Get());
CShortProperty* pShort = TPropCast<CShortProperty>(pProperty);
rOut.WriteShort( pShort->Value(pData) );
break;
}
case eLongProperty:
case EPropertyTypeNew::Int:
{
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
rOut.WriteLong(pLongCast->Get());
CIntProperty* pInt = TPropCast<CIntProperty>(pProperty);
rOut.WriteLong( pInt->Value(pData) );
break;
}
case eEnumProperty:
case EPropertyTypeNew::Float:
{
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
rOut.WriteLong(pEnumCast->Get());
CFloatProperty* pFloat = TPropCast<CFloatProperty>(pProperty);
rOut.WriteFloat( pFloat->Value(pData) );
break;
}
case eBitfieldProperty:
case EPropertyTypeNew::Choice:
{
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
rOut.WriteLong(pBitfieldCast->Get());
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProperty);
rOut.WriteLong( pChoice->Value(pData) );
break;
}
case eFloatProperty:
case EPropertyTypeNew::Enum:
{
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
rOut.WriteFloat(pFloatCast->Get());
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProperty);
rOut.WriteLong( pEnum->Value(pData) );
break;
}
case eStringProperty:
case EPropertyTypeNew::Flags:
{
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
rOut.WriteString(pStringCast->Get());
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProperty);
rOut.WriteLong( pFlags->Value(pData) );
break;
}
case eVector3Property:
case EPropertyTypeNew::String:
{
TVector3Property *pVectorCast = static_cast<TVector3Property*>(pProp);
pVectorCast->Get().Write(rOut);
CStringProperty* pString = TPropCast<CStringProperty>(pProperty);
rOut.WriteString( pString->Value(pData) );
break;
}
case eColorProperty:
case EPropertyTypeNew::Vector:
{
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
pColorCast->Get().Write(rOut, false);
CVectorProperty* pVector = TPropCast<CVectorProperty>(pProperty);
pVector->ValueRef(pData).Write(rOut);
break;
}
case eSoundProperty:
case EPropertyTypeNew::Color:
{
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
rOut.WriteLong(pSoundCast->Get());
CColorProperty* pColor = TPropCast<CColorProperty>(pProperty);
pColor->ValueRef(pData).Write(rOut);
break;
}
case eAssetProperty:
case EPropertyTypeNew::Asset:
{
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
pAssetCast->Get().Write(rOut);
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProperty);
pAsset->ValueRef(pData).Write(rOut);
break;
}
case eCharacterProperty:
case EPropertyTypeNew::Sound:
{
TCharacterProperty *pCharCast = static_cast<TCharacterProperty*>(pProp);
pCharCast->Get().Write(rOut);
CSoundProperty* pSound = TPropCast<CSoundProperty>(pProperty);
rOut.WriteLong( pSound->Value(pData) );
break;
}
case eMayaSplineProperty:
case EPropertyTypeNew::Animation:
{
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
std::vector<u8> Buffer = pSplineCast->Get();
if (!Buffer.empty()) rOut.WriteBytes(Buffer.data(), Buffer.size());
CAnimationProperty* pAnim = TPropCast<CAnimationProperty>(pProperty);
rOut.WriteLong( pAnim->Value(pData) );
break;
}
case EPropertyTypeNew::AnimationSet:
{
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProperty);
pAnimSet->ValueRef(pData).Write(rOut);
break;
}
case EPropertyTypeNew::Sequence:
{
// TODO
break;
}
case EPropertyTypeNew::Spline:
{
CSplineProperty* pSpline = TPropCast<CSplineProperty>(pProperty);
std::vector<char>& rBuffer = pSpline->ValueRef(pData);
if (!rBuffer.empty())
{
rOut.WriteBytes( rBuffer.data(), rBuffer.size() );
}
else
{
if (mGame < eReturns)
@ -132,26 +160,35 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InS
rOut.WriteByte(1);
}
}
break;
}
case eStructProperty:
case EPropertyTypeNew::Guid:
{
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
CStructTemplate *pTemp = static_cast<CStructTemplate*>(pStruct->Template());
CGuidProperty* pGuid = TPropCast<CGuidProperty>(pProperty);
std::vector<char>& rBuffer = pGuid->ValueRef(pData);
std::vector<IProperty*> PropertiesToWrite;
if (rBuffer.empty())
rBuffer.resize(16, 0);
for (u32 iProp = 0; iProp < pStruct->Count(); iProp++)
rOut.WriteBytes( rBuffer.data(), rBuffer.size() );
break;
}
case EPropertyTypeNew::Struct:
{
CStructPropertyNew* pStruct = TPropCast<CStructPropertyNew>(pProperty);
std::vector<IPropertyNew*> PropertiesToWrite;
for (u32 ChildIdx = 0; ChildIdx < pStruct->NumChildren(); ChildIdx++)
{
IProperty *pSubProp = pStruct->PropertyByIndex(iProp);\
IPropertyNew *pChild = pStruct->ChildByIndex(ChildIdx);
if (pTemp->IsSingleProperty() || pSubProp->ShouldCook())
PropertiesToWrite.push_back(pSubProp);
if (pStruct->IsAtomic() || pChild->ShouldCook(pData))
PropertiesToWrite.push_back(pChild);
}
if (!pTemp->IsSingleProperty())
if (!pStruct->IsAtomic())
{
if (mGame <= ePrime)
rOut.WriteLong(PropertiesToWrite.size());
@ -159,20 +196,27 @@ void CScriptCooker::WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InS
rOut.WriteShort((u16) PropertiesToWrite.size());
}
for (u32 iProp = 0; iProp < PropertiesToWrite.size(); iProp++)
WriteProperty(rOut, PropertiesToWrite[iProp], pTemp->IsSingleProperty());
for (u32 PropertyIdx = 0; PropertyIdx < PropertiesToWrite.size(); PropertyIdx++)
WriteProperty(rOut, PropertiesToWrite[PropertyIdx], pStruct->IsAtomic());
break;
}
case eArrayProperty:
case EPropertyTypeNew::Array:
{
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
rOut.WriteLong(pArray->Count());
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
u32 Count = pArray->ArrayCount(pData);
rOut.WriteLong(Count);
for (u32 iProp = 0; iProp < pArray->Count(); iProp++)
WriteProperty(rOut, pArray->PropertyByIndex(iProp), true);
void* pOldItemData = mpArrayItemData;
for (u32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(pData); ElementIdx++)
{
mpArrayItemData = pArray->ItemPointer(pData, ElementIdx);
WriteProperty(rOut, pArray->ArchetypeProperty(), true);
}
mpArrayItemData = pOldItemData;
break;
}
@ -209,15 +253,16 @@ void CScriptCooker::WriteInstance(IOutputStream& rOut, CScriptObject *pInstance)
u32 NumLinks = pInstance->NumLinks(eOutgoing);
IsPrime1 ? rOut.WriteLong(NumLinks) : rOut.WriteShort((u16) NumLinks);
for (u32 iLink = 0; iLink < pInstance->NumLinks(eOutgoing); iLink++)
for (u32 LinkIdx = 0; LinkIdx < NumLinks; LinkIdx++)
{
CLink *pLink = pInstance->Link(eOutgoing, iLink);
CLink *pLink = pInstance->Link(eOutgoing, LinkIdx);
rOut.WriteLong(pLink->State());
rOut.WriteLong(pLink->Message());
rOut.WriteLong(pLink->ReceiverID());
}
WriteProperty(rOut, pInstance->Properties(), false);
mpObject = pInstance;
WriteProperty(rOut, pInstance->Template()->Properties(), false);
u32 InstanceEnd = rOut.Tell();
rOut.Seek(SizeOffset, SEEK_SET);
@ -302,6 +347,6 @@ void CScriptCooker::WriteGeneratedLayer(IOutputStream& rOut)
rOut.WriteByte(1); // Version
rOut.WriteLong(mGeneratedObjects.size());
for (u32 InstIdx = 0; InstIdx < mGeneratedObjects.size(); InstIdx++)
WriteInstance(rOut, mGeneratedObjects[InstIdx]);
for (u32 ObjectIdx = 0; ObjectIdx < mGeneratedObjects.size(); ObjectIdx++)
WriteInstance(rOut, mGeneratedObjects[ObjectIdx]);
}

View File

@ -10,14 +10,18 @@
class CScriptCooker
{
EGame mGame;
CScriptObject* mpObject;
void* mpArrayItemData;
std::vector<CScriptObject*> mGeneratedObjects;
bool mWriteGeneratedSeparately;
void WriteProperty(IOutputStream& rOut,IProperty *pProp, bool InSingleStruct);
void WriteProperty(IOutputStream& rOut, IPropertyNew* pProperty, bool InAtomicStruct);
public:
CScriptCooker(EGame Game, bool WriteGeneratedObjectsSeparately = true)
: mGame(Game)
, mpObject(nullptr)
, mpArrayItemData(nullptr)
, mWriteGeneratedSeparately(WriteGeneratedObjectsSeparately && mGame >= eEchoesDemo)
{}

View File

@ -1,9 +1,11 @@
#include "CTemplateWriter.h"
#include "CAreaCooker.h"
#include <Common/FileUtil.h>
#include <Core/Resource/Script/IPropertyTemplate.h>
#include <tinyxml2.h>
#if 0
using namespace tinyxml2;
TString CTemplateWriter::smTemplatesDir = "../templates/";
@ -802,9 +804,9 @@ void CTemplateWriter::SavePropertyOverrides(XMLDocument *pDoc, XMLElement *pPare
// Struct/array-specific parameters
else if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty)
{
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp);
CStructTemplate *pChildStruct = static_cast<CStructTemplate*>(pProp);
CStructTemplate *pSourceStruct = static_cast<CStructTemplate*>(pSource);
SavePropertyOverrides(pDoc, pElem, pStruct, pSourceStruct);
SavePropertyOverrides(pDoc, pElem, pChildStruct, pSourceStruct);
}
}
}
@ -839,3 +841,4 @@ void CTemplateWriter::SaveBitFlags(XMLDocument *pDoc, XMLElement *pParent, CBitf
pFlags->LinkEndChild(pElem);
}
}
#endif

View File

@ -5,6 +5,7 @@
#include "Core/Resource/Script/CScriptTemplate.h"
#include <tinyxml2.h>
#if 0
class CTemplateWriter
{
CTemplateWriter();
@ -24,5 +25,6 @@ public:
static void SaveEnumerators(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CEnumTemplate *pTemp);
static void SaveBitFlags(tinyxml2::XMLDocument *pDoc, tinyxml2::XMLElement *pParent, CBitfieldTemplate *pTemp);
};
#endif
#endif // CTEMPLATEWRITER_H

View File

@ -74,5 +74,8 @@ enum EResType
eInvalidResType = -1
};
// Defined in CResTypeInfo.cpp
void Serialize(IArchive& rArc, EResType& rType);
#endif // ERESTYPE

View File

@ -2,256 +2,294 @@
#include "CTemplateLoader.h"
#include "Core/GameProject/CResourceStore.h"
#include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/Property/CArrayProperty.h"
#include "Core/Resource/Script/Property/CAssetProperty.h"
#include "Core/Resource/Script/Property/CEnumProperty.h"
#include "Core/Resource/Script/Property/CFlagsProperty.h"
#include <Common/Log.h>
#include <iostream>
#include <sstream>
// Whether to ensure the values of enum/flag properties are valid
#define VALIDATE_PROPERTY_VALUES 1
CScriptLoader::CScriptLoader()
: mpObj(nullptr)
, mpArrayItemData(nullptr)
{
}
void CScriptLoader::ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY)
void CScriptLoader::ReadProperty(IPropertyNew *pProp, u32 Size, IInputStream& rSCLY)
{
IPropertyTemplate *pTemp = pProp->Template();
void* pData = (mpArrayItemData ? mpArrayItemData : mpObj->mPropertyData.data());
switch (pTemp->Type())
switch (pProp->Type())
{
case eBoolProperty:
case EPropertyTypeNew::Bool:
{
TBoolProperty *pBoolCast = static_cast<TBoolProperty*>(pProp);
pBoolCast->Set( (rSCLY.ReadByte() != 0) );
CBoolProperty* pBool = TPropCast<CBoolProperty>(pProp);
pBool->ValueRef(pData) = rSCLY.ReadBool();
break;
}
case eByteProperty:
case EPropertyTypeNew::Byte:
{
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp);
pByteCast->Set(rSCLY.ReadByte());
CByteProperty* pByte = TPropCast<CByteProperty>(pProp);
pByte->ValueRef(pData) = rSCLY.ReadByte();
break;
}
case eShortProperty:
case EPropertyTypeNew::Short:
{
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp);
pShortCast->Set(rSCLY.ReadShort());
CShortProperty* pShort = TPropCast<CShortProperty>(pProp);
pShort->ValueRef(pData) = rSCLY.ReadShort();
break;
}
case eLongProperty:
case EPropertyTypeNew::Int:
{
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp);
pLongCast->Set(rSCLY.ReadLong());
CIntProperty* pInt = TPropCast<CIntProperty>(pProp);
pInt->ValueRef(pData) = rSCLY.ReadLong();
break;
}
case eBitfieldProperty:
case EPropertyTypeNew::Float:
{
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp);
pBitfieldCast->Set(rSCLY.ReadLong());
// Validate
u32 Mask = 0;
CBitfieldTemplate *pBitfieldTemp = static_cast<CBitfieldTemplate*>(pTemp);
for (u32 iMask = 0; iMask < pBitfieldTemp->NumFlags(); iMask++)
Mask |= pBitfieldTemp->FlagMask(iMask);
u32 Check = pBitfieldCast->Get() & ~Mask;
if (Check != 0)
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Bitfield property \"" + pBitfieldTemp->FullName() + "\" + (" + pBitfieldTemp->IDString(true) + ") has flags set that aren't in the template: " + TString::HexString(Check));
CFloatProperty* pFloat = TPropCast<CFloatProperty>(pProp);
pFloat->ValueRef(pData) = rSCLY.ReadFloat();
break;
}
case eEnumProperty:
case EPropertyTypeNew::Choice:
{
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp);
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pTemp);
u32 ID = rSCLY.ReadLong();
CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProp);
pChoice->ValueRef(pData) = rSCLY.ReadLong();
// Validate
u32 Index = pEnumTemp->EnumeratorIndex(ID);
if (Index == -1) Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnumTemp->FullName() + "\" (" + pEnumTemp->IDString(true) + ") has invalid enumerator value: " + TString::HexString(ID));
pEnumCast->Set(ID);
#if VALIDATE_PROPERTY_VALUES
if (!pChoice->HasValidValue(pData))
{
u32 Value = pChoice->ValueRef(pData);
Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Choice property \"" + pChoice->Name() + "\" (" + pChoice->IDString(true) + ") has unrecognized value: " + TString::HexString(Value));
}
#endif
break;
}
case eFloatProperty:
case EPropertyTypeNew::Enum:
{
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp);
pFloatCast->Set(rSCLY.ReadFloat());
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
pEnum->ValueRef(pData) = rSCLY.ReadLong();
#if VALIDATE_PROPERTY_VALUES
if (!pEnum->HasValidValue(pData))
{
u32 Value = pEnum->ValueRef(pData);
Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnum->Name() + "\" (" + pEnum->IDString(true) + ") has unrecognized value: " + TString::HexString(Value));
}
#endif
break;
}
case eStringProperty:
case EPropertyTypeNew::Flags:
{
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp);
pStringCast->Set(rSCLY.ReadString());
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
pFlags->ValueRef(pData) = rSCLY.ReadLong();
#if VALIDATE_PROPERTY_VALUES
u32 InvalidBits = pFlags->HasValidValue(pData);
if (InvalidBits)
{
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Flags property \"" + pFlags->Name() + "\" + (" + pFlags->IDString(true) + ") has unrecognized flags set: " + TString::HexString(InvalidBits));
}
#endif
break;
}
case eVector3Property:
case EPropertyTypeNew::String:
{
TVector3Property *pVector3Cast = static_cast<TVector3Property*>(pProp);
pVector3Cast->Set(CVector3f(rSCLY));
CStringProperty* pString = TPropCast<CStringProperty>(pProp);
pString->ValueRef(pData) = rSCLY.ReadString();
break;
}
case eColorProperty:
case EPropertyTypeNew::Vector:
{
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp);
pColorCast->Set(CColor(rSCLY));
CVectorProperty* pVector = TPropCast<CVectorProperty>(pProp);
pVector->ValueRef(pData) = CVector3f(rSCLY);
break;
}
case eSoundProperty:
case EPropertyTypeNew::Color:
{
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp);
pSoundCast->Set(rSCLY.ReadLong());
CColorProperty* pColor = TPropCast<CColorProperty>(pProp);
pColor->ValueRef(pData) = CColor(rSCLY);
break;
}
case eAssetProperty:
case EPropertyTypeNew::Asset:
{
TAssetProperty *pAssetCast = static_cast<TAssetProperty*>(pProp);
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
pAsset->ValueRef(pData) = CAssetID(rSCLY, mpMaster->Game());
// quick hacky fix - all games set version to DKCR for copy/paste
CAssetID ID;
if (mVersion == eReturns)
ID = CAssetID(rSCLY, (EIDLength) Size);
else
ID = CAssetID(rSCLY, mVersion);
#if VALIDATE_PROPERTY_VALUES
CAssetID ID = pAsset->ValueRef(pData);
pAssetCast->Set(ID);
// Verify this is a valid resource type for this property
if (ID.IsValid())
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
if (pEntry)
{
const CResTypeFilter& rkFilter = static_cast<CAssetTemplate*>(pTemp)->TypeFilter();
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
bool Valid = rkFilter.Accepts(pEntry->ResourceType());
if (!Valid)
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pTemp->FullName() + "\" (" + pTemp->IDString(true) + ") has a reference to an illegal asset type: " + pEntry->CookedExtension());
Log::FileWarning(rSCLY.GetSourceString(), rSCLY.Tell() - ID.Length(), "Asset property \"" + pAsset->Name() + "\" (" + pAsset->IDString(true) + ") has a reference to an illegal asset type: " + pEntry->CookedExtension());
}
}
#endif
break;
}
case eStructProperty:
case EPropertyTypeNew::Sound:
{
CPropertyStruct *pStructCast = static_cast<CPropertyStruct*>(pProp);
CSoundProperty* pSound = TPropCast<CSoundProperty>(pProp);
pSound->ValueRef(pData) = rSCLY.ReadLong();
break;
}
case EPropertyTypeNew::Animation:
{
CAnimationProperty* pAnim = TPropCast<CAnimationProperty>(pProp);
pAnim->ValueRef(pData) = rSCLY.ReadLong();
break;
}
case EPropertyTypeNew::AnimationSet:
{
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
pAnimSet->ValueRef(pData) = CAnimationParameters(rSCLY, mpMaster->Game());
break;
}
case EPropertyTypeNew::Sequence:
{
// TODO
break;
}
case EPropertyTypeNew::Spline:
{
CSplineProperty* pSpline = TPropCast<CSplineProperty>(pProp);
std::vector<char>& Buffer = pSpline->ValueRef(pData);
Buffer.resize(Size);
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
break;
}
case EPropertyTypeNew::Guid:
{
ASSERT(Size == 16);
CGuidProperty* pGuid = TPropCast<CGuidProperty>(pProp);
pGuid->ValueRef(pData).resize(16);
rSCLY.ReadBytes(pGuid->ValueRef(pData).data(), 16);
break;
}
case EPropertyTypeNew::Struct:
{
CStructPropertyNew* pStruct = TPropCast<CStructPropertyNew>(pProp);
if (mVersion < eEchoesDemo)
LoadStructMP1(rSCLY, pStructCast, static_cast<CStructTemplate*>(pStructCast->Template()));
LoadStructMP1(rSCLY, pStruct);
else
LoadStructMP2(rSCLY, pStructCast, static_cast<CStructTemplate*>(pTemp));
LoadStructMP2(rSCLY, pStruct);
break;
}
case eArrayProperty:
case EPropertyTypeNew::Array:
{
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp);
CArrayProperty *pArray = TPropCast<CArrayProperty>(pProp);
int Count = rSCLY.ReadLong();
pArrayCast->Resize(Count);
pArray->Resize(pData, Count);
void* pOldArrayItemData = mpArrayItemData;
for (int iElem = 0; iElem < Count; iElem++)
// Make sure the array archetype is atomic... non-atomic array archetypes is not supported
// because arrays can only have one possible archetype so having property IDs here wouldn't make sense
ASSERT(pArray->ArchetypeProperty()->IsAtomic());
for (int ElementIdx = 0; ElementIdx < Count; ElementIdx++)
{
if (mVersion < eEchoesDemo)
LoadStructMP1(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
else
LoadStructMP2(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate());
/**
* so this is kind of annoying, there isn't really any good way to cleanly integrate arrays into the property system
* because calculating the pointer to an item requires knowing the array index, which the property itself can't store
* because the same property object is used for every array element; and we can't dynamically add children to the array
* based on its size either, because the same array property is shared between multiple script instances. so, instead,
* we determine the item pointer ourselves and the array archetype property will respect it.
*
* arrays are an edge case anyway - they only really appear in Prime 1 and there are only a couple array properties in
* the game. the only situation where an array property appears in other games is SequenceTimer, and that's going to be
* migrated to Sequence properties eventually, so there isn't really any good reason to spend a lot of effort refactoring
* things to make this cleaner
*/
mpArrayItemData = pArray->ItemPointer(pData, ElementIdx);
ReadProperty(pArray->ArchetypeProperty(), 0, rSCLY);
}
mpArrayItemData = pOldArrayItemData;
break;
}
case eCharacterProperty:
{
TCharacterProperty *pAnimCast = static_cast<TCharacterProperty*>(pProp);
pAnimCast->Set(CAnimationParameters(rSCLY, mpMaster->Game()));
break;
}
case eMayaSplineProperty:
{
TMayaSplineProperty *pSplineCast = static_cast<TMayaSplineProperty*>(pProp);
std::vector<u8> Buffer(Size);
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
pSplineCast->Set(Buffer);
break;
}
case eUnknownProperty:
{
TUnknownProperty *pUnknownCast = static_cast<TUnknownProperty*>(pProp);
std::vector<u8> Buffer(Size);
rSCLY.ReadBytes(Buffer.data(), Buffer.size());
pUnknownCast->Set(Buffer);
break;
}
}
}
void CScriptLoader::LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp)
void CScriptLoader::LoadStructMP1(IInputStream& rSCLY, CStructPropertyNew* pStruct)
{
u32 StructStart = rSCLY.Tell();
// Verify property count
u32 PropCount = pTemp->Count();
u32 PropertyCount = pStruct->NumChildren();
u32 Version = 0;
if (!pTemp->IsSingleProperty())
if (!pStruct->IsAtomic())
{
u32 FilePropCount = rSCLY.ReadLong();
Version = pTemp->VersionForPropertyCount(FilePropCount);
if (Version == -1)
{
TIDString IDString = pTemp->IDString(true);
if (!IDString.IsEmpty()) IDString = " (" + IDString + ")";
Log::FileWarning(rSCLY.GetSourceString(), StructStart, "Struct \"" + pTemp->FullName() + "\" (" + IDString + ") template prop count doesn't match file; template is " + TString::HexString(PropCount, 2) + ", file is " + TString::HexString(FilePropCount, 2));
Version = 0;
}
//@todo version checking
}
// Parse properties
for (u32 iProp = 0; iProp < PropCount; iProp++)
for (u32 ChildIndex = 0; ChildIndex < PropertyCount; ChildIndex++)
{
IPropertyTemplate *pPropTemp = pTemp->PropertyByIndex(iProp);
IProperty *pProp = pStruct->PropertyByIndex(iProp);
IPropertyNew *pProperty = pStruct->ChildByIndex(ChildIndex);
if (pPropTemp->CookPreference() != eNeverCook && pPropTemp->IsInVersion(Version))
ReadProperty(pProp, 0, rSCLY);
//@todo version check
if (pProperty->CookPreference() != ECookPreferenceNew::Never)
ReadProperty(pProperty, 0, rSCLY);
}
}
CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
{
u32 ObjStart = rSCLY.Tell();
u32 StartOffset = rSCLY.Tell();
u8 Type = rSCLY.ReadByte();
u32 Size = rSCLY.ReadLong();
u32 End = rSCLY.Tell() + Size;
CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type);
if (!pTemp)
CScriptTemplate *pTemplate = mpMaster->TemplateByID((u32) Type);
if (!pTemplate)
{
// No valid template for this object; can't load
Log::FileError(rSCLY.GetSourceString(), ObjStart, "Unknown object ID encountered: " + TString::HexString(Type, 2));
Log::FileError(rSCLY.GetSourceString(), StartOffset, "Unknown object ID encountered: " + TString::HexString(Type, 2));
rSCLY.Seek(End, SEEK_SET);
return nullptr;
}
u32 InstanceID = rSCLY.ReadLong() & 0x03FFFFFF;
if (InstanceID == 0x03FFFFFF) InstanceID = mpArea->FindUnusedInstanceID();
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp);
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate);
// Load connections
u32 NumLinks = rSCLY.ReadLong();
@ -268,8 +306,8 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
}
// Load object...
CPropertyStruct *pBase = mpObj->mpProperties;
LoadStructMP1(rSCLY, pBase, static_cast<CStructTemplate*>(pBase->Template()));
CStructPropertyNew* pProperties = pTemplate->Properties();
LoadStructMP1(rSCLY, pProperties);
// Cleanup and return
rSCLY.Seek(End, SEEK_SET);
@ -288,11 +326,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++)
for (u32 ObjectIndex = 0; ObjectIndex < NumObjects; ObjectIndex++)
{
CScriptObject *pObj = LoadObjectMP1(rSCLY);
if (pObj)
mpLayer->AddInstance(pObj);
CScriptObject *pObject = LoadObjectMP1(rSCLY);
if (pObject)
mpLayer->AddInstance(pObject);
}
// Layer sizes are always a multiple of 32 - skip end padding before returning
@ -301,46 +339,39 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
return mpLayer;
}
void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp)
void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CStructPropertyNew* pStruct)
{
// Verify property count
u32 StructStart = rSCLY.Tell();
StructStart += 0;
u32 PropCount = pTemp->Count();
u32 ChildCount = pStruct->NumChildren();
if (!pTemp->IsSingleProperty())
PropCount = rSCLY.ReadShort();
if (!pStruct->IsAtomic())
ChildCount = rSCLY.ReadShort();
// Parse properties
for (u32 iProp = 0; iProp < PropCount; iProp++)
for (u32 ChildIdx = 0; ChildIdx < ChildCount; ChildIdx++)
{
IProperty *pProp;
IPropertyTemplate *pPropTemp;
IPropertyNew* pProperty = nullptr;
u32 PropertyStart = rSCLY.Tell();
u32 PropertyID = -1;
u16 PropertyLength = 0;
u16 PropertySize = 0;
u32 NextProperty = 0;
if (pTemp->IsSingleProperty())
if (pStruct->IsAtomic())
{
pProp = pStruct->PropertyByIndex(iProp);
pPropTemp = pTemp->PropertyByIndex(iProp);
pProperty = pStruct->ChildByIndex(ChildIdx);
}
else
{
PropertyID = rSCLY.ReadLong();
PropertyLength = rSCLY.ReadShort();
NextProperty = rSCLY.Tell() + PropertyLength;
pProp = pStruct->PropertyByID(PropertyID);
pPropTemp = pTemp->PropertyByID(PropertyID);
PropertySize = rSCLY.ReadShort();
NextProperty = rSCLY.Tell() + PropertySize;
pProperty = pStruct->ChildByID(PropertyID);
}
if (!pPropTemp)
if (!pProperty)
Log::FileError(rSCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping");
else
ReadProperty(pProp, PropertyLength, rSCLY);
ReadProperty(pProperty, PropertySize, rSCLY);
if (NextProperty > 0)
rSCLY.Seek(NextProperty, SEEK_SET);
@ -354,7 +385,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
u16 ObjectSize = rSCLY.ReadShort();
u32 ObjEnd = rSCLY.Tell() + ObjectSize;
CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID);
CScriptTemplate* pTemplate = mpMaster->TemplateByID(ObjectID);
if (!pTemplate)
{
@ -371,19 +402,19 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
u32 NumConnections = rSCLY.ReadShort();
mpObj->mOutLinks.reserve(NumConnections);
for (u32 iCon = 0; iCon < NumConnections; iCon++)
for (u32 LinkIdx = 0; LinkIdx < NumConnections; LinkIdx++)
{
u32 State = rSCLY.ReadLong();
u32 Message = rSCLY.ReadLong();
u32 ReceiverID = rSCLY.ReadLong() & 0x03FFFFFF;
CLink *pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
CLink* pLink = new CLink(mpArea, State, Message, mpObj->mInstanceID, ReceiverID);
mpObj->mOutLinks.push_back(pLink);
}
// Load object
rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size
LoadStructMP2(rSCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct());
LoadStructMP2(rSCLY, pTemplate->Properties());
// Cleanup and return
rSCLY.Seek(ObjEnd, SEEK_SET);
@ -399,11 +430,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& rSCLY)
mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++)
for (u32 ObjectIdx = 0; ObjectIdx < NumObjects; ObjectIdx++)
{
CScriptObject *pObj = LoadObjectMP2(rSCLY);
if (pObj)
mpLayer->AddInstance(pObj);
CScriptObject* pObject = LoadObjectMP2(rSCLY);
if (pObject)
mpLayer->AddInstance(pObject);
}
return mpLayer;

View File

@ -10,19 +10,22 @@
class CScriptLoader
{
EGame mVersion;
CScriptObject *mpObj;
CScriptLayer *mpLayer;
CGameArea *mpArea;
CScriptObject* mpObj;
CScriptLayer* mpLayer;
CGameArea* mpArea;
CMasterTemplate *mpMaster;
CScriptLoader();
void ReadProperty(IProperty *pProp, u32 Size, IInputStream& rSCLY);
// Current array item pointer
void* mpArrayItemData;
void LoadStructMP1(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
CScriptLoader();
void ReadProperty(IPropertyNew* pProp, u32 Size, IInputStream& rSCLY);
void LoadStructMP1(IInputStream& rSCLY, CStructPropertyNew* pStruct);
CScriptObject* LoadObjectMP1(IInputStream& rSCLY);
CScriptLayer* LoadLayerMP1(IInputStream& rSCLY);
void LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp);
void LoadStructMP2(IInputStream& rSCLY, CStructPropertyNew* pStruct);
CScriptObject* LoadObjectMP2(IInputStream& rSCLY);
CScriptLayer* LoadLayerMP2(IInputStream& rSCLY);

View File

@ -1,6 +1,7 @@
#include "CTemplateLoader.h"
#include "CAreaLoader.h"
#include "Core/Resource/Script/IPropertyTemplate.h"
#include "Core/Resource/Script/Property/Properties.h"
#include <Common/FileUtil.h>
#include <Common/Log.h>
@ -9,7 +10,105 @@ const TString CTemplateLoader::mskGameListPath = CTemplateLoader::mskTemplatesDi
using namespace tinyxml2;
IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTemplate *pScript, CStructTemplate *pStruct, const TString& rkTemplateName)
// ugly macro because this is all temp code anyway so whatever
#define SET_MEMBER_CASES_NUMERICAL(MemberName, Param, LParam) \
case EPropertyTypeNew::Byte:\
TPropCast<CByteProperty>(pProp)->MemberName = (s8) LParam.ToInt32(10);\
break;\
\
case EPropertyTypeNew::Short:\
TPropCast<CShortProperty>(pProp)->MemberName = (s16) LParam.ToInt32(10);\
break;\
\
case EPropertyTypeNew::Int:\
TPropCast<CIntProperty>(pProp)->MemberName = (s32) LParam.ToInt32(10);\
break;\
\
case EPropertyTypeNew::Float:\
TPropCast<CFloatProperty>(pProp)->MemberName = LParam.ToFloat();\
break;\
\
#define SET_MEMBER_CASES_NON_NUMERICAL(MemberName, Param, LParam) \
case EPropertyTypeNew::Bool:\
TPropCast<CBoolProperty>(pProp)->MemberName = (LParam == "true");\
break;\
\
case EPropertyTypeNew::Choice:\
TPropCast<CChoiceProperty>(pProp)->MemberName = LParam.ToInt32( LParam.StartsWith("0x") ? 16 : 10 );\
break;\
\
case EPropertyTypeNew::Enum:\
TPropCast<CEnumProperty>(pProp)->MemberName = LParam.ToInt32( LParam.StartsWith("0x") ? 16 : 10 );\
break;\
\
case EPropertyTypeNew::Flags:\
TPropCast<CFlagsProperty>(pProp)->MemberName = LParam.ToInt32( LParam.StartsWith("0x") ? 16 : 10 );\
break;\
\
case EPropertyTypeNew::String:\
TPropCast<CStringProperty>(pProp)->MemberName = Param;\
break;\
\
case EPropertyTypeNew::Vector:\
{\
TStringList Components = Param.Split(", ");\
if (Components.size() != 3) {\
TPropCast<CVectorProperty>(pProp)->MemberName = CVector3f::skInfinite;\
break;\
}\
float* pPtr = &TPropCast<CVectorProperty>(pProp)->MemberName.X;\
for (auto it = Components.begin(); it != Components.end(); it++)\
{\
*pPtr = it->ToFloat();\
pPtr++;\
}\
break;\
}\
case EPropertyTypeNew::Color:\
{\
TStringList Components = Param.Split(", ");\
if (Components.size() < 3 || Components.size() > 4) {\
TPropCast<CColorProperty>(pProp)->MemberName = CColor::skTransparentBlack;\
break;\
}\
float* pPtr = &TPropCast<CColorProperty>(pProp)->MemberName.R;\
TPropCast<CColorProperty>(pProp)->MemberName.A = 1.0f;\
for (auto it = Components.begin(); it != Components.end(); it++) {\
*pPtr = it->ToFloat();\
pPtr++;\
}\
break;\
}\
case EPropertyTypeNew::Asset:\
TPropCast<CAssetProperty>(pProp)->MemberName = CAssetID::FromString(Param);\
break;\
\
case EPropertyTypeNew::Sound:\
TPropCast<CSoundProperty>(pProp)->MemberName = LParam.ToInt32(10);\
break;\
\
#define SET_MEMBER_FROM_STRING_TYPED(MemberName, Param, LParam)\
switch (Type)\
{\
SET_MEMBER_CASES_NON_NUMERICAL(MemberName, Param, LParam)\
SET_MEMBER_CASES_NUMERICAL(MemberName, Param, LParam)\
default:\
ASSERT(false);\
break;\
}\
#define SET_MEMBER_FROM_STRING_NUMERICAL(MemberName, Param, LParam)\
switch(Type)\
{\
SET_MEMBER_CASES_NUMERICAL(MemberName, Param, LParam)\
default:\
ASSERT(false);\
break;\
}\
IPropertyNew* CTemplateLoader::LoadProperty(XMLElement* pElem, CScriptTemplate* pScript, CStructPropertyNew* pParent, const TString& rkTemplateName)
{
TString NodeType = TString(pElem->Name()).ToLower();
TString IDAttr = TString(pElem->Attribute("ID")).ToLower();
@ -38,8 +137,8 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
}
// Does the property already exist (eg is this an override)?
IPropertyTemplate *pProp = pStruct->PropertyByID(ID);
EPropertyType Type;
IPropertyNew* pProp = pParent->ChildByID(ID);
EPropertyTypeNew Type;
bool IsNewProperty = false;
// If it doesn't, then we'll need to create it.
@ -50,7 +149,7 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
Type = PropStringToPropEnum(TypeStr);
IsNewProperty = true;
if (Type == eInvalidProperty)
if (Type == EPropertyTypeNew::Invalid)
{
if (TypeStr.IsEmpty())
Log::Error(rkTemplateName + ": Property " + TString::HexString(ID) + " doesn't have a type set");
@ -60,13 +159,56 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
return nullptr;
}
pProp = CreateProperty(ID, Type, Name, pScript, pStruct);
// Load archetype if required
bool bNeedsArchetype = ( Type == EPropertyTypeNew::Struct ||
Type == EPropertyTypeNew::Enum ||
Type == EPropertyTypeNew::Choice ||
Type == EPropertyTypeNew::Flags );
if (bNeedsArchetype)
{
IPropertyNew* pArchetype = nullptr;
//todo: struct archetypes are not supposed to be optional but apparently some still don't have them
if (!TemplateAttr.IsEmpty())
{
if (Type == EPropertyTypeNew::Struct)
{
pArchetype = LoadStructArchetype(TemplateAttr);
}
else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{
pArchetype = LoadEnumArchetype(TemplateAttr, Type == EPropertyTypeNew::Choice);
}
else if (Type == EPropertyTypeNew::Flags)
{
pArchetype = LoadFlagsArchetype(TemplateAttr);
}
}
// create property as a copy of the archetype
if (pArchetype != nullptr)
{
pProp = IPropertyNew::CreateCopy(pArchetype, pParent);
}
}
// no archetype, so do normal create
if (!pProp)
{
pProp = IPropertyNew::Create(Type, pParent, mpMaster, pScript, false);
}
// we need to have a valid property by this point
if (!pProp)
{
Log::Error(rkTemplateName + ": Property " + TString::HexString(ID) + " seems to be using a valid but unsupported property type? (" + TypeStr + ")");
return nullptr;
}
// Initialize parameters on the new property
pProp->mID = ID;
pProp->mName = Name;
}
else
Type = pProp->Type();
@ -79,6 +221,7 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
TString ParamName = TString(pParams->Name()).ToLower();
TString ParamVal = TString(pParams->GetText());
#if 0
// Load versions
if (ParamName == "versions")
{
@ -100,245 +243,284 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
// Otherwise, delegate it to the template to parse the parameter.
// (This is done because there's no common base class for typed properties, so it's tough to handle this in the template loader.)
else pProp->SetParam(ParamName, ParamVal);
else
Prop->SetParam(ParamName, ParamVal);
#endif
if (ParamName == "cook_pref")
{
TString lValue = ParamVal.ToLower();
if (lValue == "always")
pProp->mCookPreference = ECookPreferenceNew::Always;
else if (lValue == "never")
pProp->mCookPreference = ECookPreferenceNew::Never;
else
pProp->mCookPreference = ECookPreferenceNew::Default;
}
else if (ParamName == "description")
{
pProp->mDescription = ParamVal;
}
else if (ParamName == "default")
{
TString lValue = ParamVal.ToLower();
SET_MEMBER_FROM_STRING_TYPED(mDefaultValue, ParamVal, lValue);
}
else if (ParamName == "range")
{
TStringList Components = ParamVal.ToLower().Split(", ");
TString Min = Components.front();
TString Max = Components.back();
SET_MEMBER_FROM_STRING_NUMERICAL(mMinValue, Min, Min);
SET_MEMBER_FROM_STRING_NUMERICAL(mMaxValue, Max, Max);
}
else if (ParamName == "suffix")
{
pProp->SetSuffix(ParamVal);
}
pParams = pParams->NextSiblingElement();
}
// Asset-specific parameters
if (Type == eAssetProperty)
if (Type == EPropertyTypeNew::Asset)
{
TString ExtensionsAttr = pElem->Attribute("extensions");
if (!ExtensionsAttr.IsEmpty())
{
TStringList ExtensionsList = ExtensionsAttr.Split(", ");
CAssetTemplate *pAsset = static_cast<CAssetTemplate*>(pProp);
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
pAsset->SetTypeFilter(ExtensionsList);
}
}
// Enum-specific parameters
else if (Type == eEnumProperty)
else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{
CEnumTemplate *pEnum = static_cast<CEnumTemplate*>(pProp);
// Load template
if (!TemplateAttr.IsEmpty())
LoadEnumTemplate(TemplateAttr, pEnum);
// use static_cast so we can do both enum and choice with this code
CEnumProperty* pEnum = static_cast<CEnumProperty*>(pProp);
// Load embedded enumerators
XMLElement *pEnumerators = pElem->FirstChildElement("enumerators");
XMLElement* pEnumerators = pElem->FirstChildElement("enumerators");
if (pEnumerators)
LoadEnumerators(pEnumerators, pEnum, rkTemplateName);
}
// Bitfield-specific parameters
else if (Type == eBitfieldProperty)
else if (Type == EPropertyTypeNew::Flags)
{
CBitfieldTemplate *pBitfield = static_cast<CBitfieldTemplate*>(pProp);
// Load template
if (!TemplateAttr.IsEmpty())
LoadBitfieldTemplate(TemplateAttr, pBitfield);
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
// Load embedded flags
XMLElement *pFlags = pElem->FirstChildElement("flags");
XMLElement* pFlagsElem = pElem->FirstChildElement("flags");
if (pFlags)
LoadBitFlags(pFlags, pBitfield, rkTemplateName);
if (pFlagsElem)
LoadBitFlags(pFlagsElem, pFlags, rkTemplateName);
}
// Struct-specific parameters
else if ( (Type == eStructProperty) || (Type == eArrayProperty) )
else if ( (Type == EPropertyTypeNew::Struct) || (Type == EPropertyTypeNew::Array) )
{
CStructTemplate *pStruct = static_cast<CStructTemplate*>(pProp);
CStructPropertyNew* pStruct = nullptr;
// Load template or struct type
if (!TemplateAttr.IsEmpty())
LoadStructTemplate(TemplateAttr, pStruct);
if (Type == EPropertyTypeNew::Struct)
{
pStruct = TPropCast<CStructPropertyNew>(pProp);
}
else
{
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProp);
if (IsNewProperty && TemplateAttr.IsEmpty() && Type == eStructProperty)
pStruct->mIsSingleProperty = (TypeAttr == "single");
if (pArray->mpArchetype != nullptr)
{
ASSERT(pArray->mpArchetype->Type() == EPropertyTypeNew::Struct);
pStruct = TPropCast<CStructPropertyNew>(pArray->mpArchetype);
}
else
{
pArray->mpArchetype = IPropertyNew::Create(EPropertyTypeNew::Struct, pArray, mpMaster, pScript, false);
pStruct = TPropCast<CStructPropertyNew>(pArray->mpArchetype);
pStruct->mFlags = EPropertyFlag::IsAtomic | EPropertyFlag::IsArrayArchetype;
}
pStruct = TPropCast<CStructPropertyNew>(pArray->mpArchetype);
}
// Load sub-properties and parameter overrides
// Load parameter overrides
XMLElement *pProperties = pElem->FirstChildElement("properties");
if (pProperties)
{
LoadProperties(pProperties, pScript, pStruct, rkTemplateName);
}
if (Type == EPropertyTypeNew::Array)
{
pStruct->PostInitialize();
}
}
if (IsNewProperty)
CMasterTemplate::AddProperty(pProp, mMasterDir + rkTemplateName);
pProp->PostInitialize();
return pProp;
}
#define CREATE_PROP_TEMP(Class) new Class(ID, rkName, eNoCookPreference, pScript, mpMaster, pStruct)
IPropertyTemplate* CTemplateLoader::CreateProperty(u32 ID, EPropertyType Type, const TString& rkName, CScriptTemplate *pScript, CStructTemplate *pStruct)
{
IPropertyTemplate *pOut = pStruct->PropertyByID(ID);
switch (Type)
{
case eBoolProperty: pOut = CREATE_PROP_TEMP(TBoolTemplate); break;
case eByteProperty: pOut = CREATE_PROP_TEMP(TByteTemplate); break;
case eShortProperty: pOut = CREATE_PROP_TEMP(TShortTemplate); break;
case eLongProperty: pOut = CREATE_PROP_TEMP(TLongTemplate); break;
case eFloatProperty: pOut = CREATE_PROP_TEMP(TFloatTemplate); break;
case eStringProperty: pOut = CREATE_PROP_TEMP(TStringTemplate); break;
case eVector3Property: pOut = CREATE_PROP_TEMP(TVector3Template); break;
case eColorProperty: pOut = CREATE_PROP_TEMP(TColorTemplate); break;
case eSoundProperty: pOut = CREATE_PROP_TEMP(TSoundTemplate); break;
case eAssetProperty: pOut = CREATE_PROP_TEMP(CAssetTemplate); break;
case eCharacterProperty: pOut = CREATE_PROP_TEMP(TCharacterTemplate); break;
case eMayaSplineProperty: pOut = CREATE_PROP_TEMP(TMayaSplineTemplate); break;
case eEnumProperty: pOut = CREATE_PROP_TEMP(CEnumTemplate); break;
case eBitfieldProperty: pOut = CREATE_PROP_TEMP(CBitfieldTemplate); break;
case eArrayProperty: pOut = CREATE_PROP_TEMP(CArrayTemplate); break;
case eStructProperty: pOut = CREATE_PROP_TEMP(CStructTemplate); break;
}
if (pOut)
pStruct->mSubProperties.push_back(pOut);
return pOut;
}
void CTemplateLoader::LoadStructTemplate(const TString& rkTemplateFileName, CStructTemplate *pStruct)
CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTemplateFileName)
{
// Check whether this struct has already been read
auto it = mpMaster->mStructTemplates.find(rkTemplateFileName);
CStructTemplate *pSource = (it == mpMaster->mStructTemplates.end() ? nullptr : it->second);
CStructPropertyNew* pArchetype = (it == mpMaster->mStructTemplates.end() ? nullptr : it->second);
// If the source hasn't been read yet, then we read it and add it to master's list
if (!pSource)
// If the struct template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
{
XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!Doc.Error())
{
XMLElement *pRootElem;
pArchetype = TPropCast<CStructPropertyNew>(
IPropertyNew::Create(EPropertyTypeNew::Struct,
nullptr,
mpMaster,
nullptr, false)
);
ASSERT(pArchetype != nullptr);
if (pStruct->Type() == eStructProperty)
XMLElement* pRootElem = Doc.FirstChildElement("struct");
ASSERT(pRootElem);
TString TypeAttr = TString(pRootElem->Attribute("type")).ToLower();
ASSERT(!TypeAttr.IsEmpty())
if (TypeAttr == "single")
pArchetype->mFlags |= EPropertyFlag::IsAtomic;
pArchetype->mFlags |= EPropertyFlag::IsArchetype;
pArchetype->mTemplateFileName = rkTemplateFileName;
pArchetype->mName = rkTemplateFileName.GetFileName(false);
#if 0
if (pArchetype->mTypeName.Contains("Struct"))
{
pSource = new CStructTemplate(-1, nullptr, mpMaster);
pRootElem = Doc.FirstChildElement("struct");
if (!pRootElem)
{
Log::Error(rkTemplateFileName + ": There is no root \"struct\" element");
return;
}
TString TypeAttr = TString(pRootElem->Attribute("type")).ToLower();
if (TypeAttr.IsEmpty())
{
Log::Error(rkTemplateFileName + ": There is no struct type specified");
return;
}
pSource->mIsSingleProperty = (TypeAttr == "single" ? true : false);
pArchetype->mSourceFile = "Structs/" +
GetGameShortName(mGame) +
"-" +
pArchetype->mTypeName +
".xml";
pArchetype->mTypeName = pArchetype->mSourceFile.GetFileName(false);
}
#endif
else if (pStruct->Type() == eArrayProperty)
{
pSource = new CArrayTemplate(-1, nullptr, mpMaster);
pRootElem = Doc.FirstChildElement("array");
if (!pRootElem)
{
Log::Error(rkTemplateFileName + ": There is no root \"array\" element");
return;
}
}
pSource->mSourceFile = rkTemplateFileName;
pSource->mTypeName = pSource->mSourceFile.GetFileName(false);
// ignore struct name attribute - archetypes should always have the type name
#if 0
TString NameAttr = TString(pRootElem->Attribute("name"));
if (!NameAttr.IsEmpty())
pSource->mName = NameAttr;
pArchetype->mName = NameAttr;
#endif
// Read sub-properties
XMLElement *pSubPropsElem = pRootElem->FirstChildElement("properties");
XMLElement* pSubPropsElem = pRootElem->FirstChildElement("properties");
ASSERT(pSubPropsElem);
if (pSubPropsElem)
{
LoadProperties(pSubPropsElem, nullptr, pSource, rkTemplateFileName);
mpMaster->mStructTemplates[rkTemplateFileName] = pSource;
}
else
{
Log::Error(rkTemplateFileName + ": There is no \"properties\" block element");
delete pSource;
pSource = nullptr;
}
LoadProperties(pSubPropsElem, nullptr, pArchetype, rkTemplateFileName);
mpMaster->mStructTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
}
}
// Copy source to the new struct template
if (pSource)
pStruct->CopyStructData(pSource);
ASSERT(pArchetype != nullptr);
return pArchetype;
}
void CTemplateLoader::LoadEnumTemplate(const TString& rkTemplateFileName, CEnumTemplate *pEnum)
CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileName, bool bIsChoice)
{
XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
// Check whether this struct has already been read
auto it = mpMaster->mEnumTemplates.find(rkTemplateFileName);
CEnumProperty* pArchetype = (it == mpMaster->mEnumTemplates.end() ? nullptr : it->second);
if (!Doc.Error())
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
{
pEnum->mSourceFile = rkTemplateFileName;
XMLElement *pRootElem = Doc.FirstChildElement("enum");
XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!pRootElem)
if (!Doc.Error())
{
Log::Error(rkTemplateFileName + ": There is no root \"enum\" element");
return;
// use static_cast so this code works for both enum and choice
pArchetype = static_cast<CEnumProperty*>(
IPropertyNew::Create(bIsChoice ? EPropertyTypeNew::Choice : EPropertyTypeNew::Enum,
nullptr,
mpMaster,
nullptr,
false)
);
ASSERT(pArchetype != nullptr);
pArchetype->mFlags |= EPropertyFlag::IsArchetype;
pArchetype->mSourceFile = rkTemplateFileName;
XMLElement* pRootElem = Doc.FirstChildElement("enum");
ASSERT(pRootElem);
XMLElement *pEnumers = pRootElem->FirstChildElement("enumerators");
ASSERT(pEnumers);
LoadEnumerators(pEnumers, pArchetype, rkTemplateFileName);
mpMaster->mEnumTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
}
XMLElement *pEnumers = pRootElem->FirstChildElement("enumerators");
if (pEnumers)
LoadEnumerators(pEnumers, pEnum, rkTemplateFileName);
else
Log::Error(rkTemplateFileName + ": There is no \"enumerators\" block element");
}
ASSERT(pArchetype != nullptr);
return pArchetype;
}
void CTemplateLoader::LoadBitfieldTemplate(const TString& rkTemplateFileName, CBitfieldTemplate *pBitfield)
CFlagsProperty* CTemplateLoader::LoadFlagsArchetype(const TString& rkTemplateFileName)
{
XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
// Check whether this struct has already been read
auto it = mpMaster->mFlagsTemplates.find(rkTemplateFileName);
CFlagsProperty* pArchetype = (it == mpMaster->mFlagsTemplates.end() ? nullptr : it->second);
if (!Doc.Error())
// If the enum template hasn't been read yet, then we read it and add it to master's list
if (!pArchetype)
{
pBitfield->mSourceFile = rkTemplateFileName;
XMLElement *pRootElem = Doc.FirstChildElement("bitfield");
XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!pRootElem)
if (!Doc.Error())
{
Log::Error(rkTemplateFileName + ": There is no root \"bitfield\" element");
return;
pArchetype = TPropCast<CFlagsProperty>(
IPropertyNew::Create(EPropertyTypeNew::Flags,
nullptr,
mpMaster,
nullptr, false)
);
ASSERT(pArchetype != nullptr);
pArchetype->mFlags |= EPropertyFlag::IsArchetype;
pArchetype->mSourceFile = rkTemplateFileName;
XMLElement *pRootElem = Doc.FirstChildElement("bitfield");
ASSERT(pRootElem);
XMLElement *pFlags = pRootElem->FirstChildElement("flags");
ASSERT(pFlags);
LoadBitFlags(pFlags, pArchetype, rkTemplateFileName);
mpMaster->mFlagsTemplates[rkTemplateFileName] = pArchetype;
pArchetype->PostInitialize();
}
XMLElement *pFlags = pRootElem->FirstChildElement("flags");
if (pFlags)
LoadBitFlags(pFlags, pBitfield, rkTemplateFileName);
else
Log::Error(rkTemplateFileName + ": There is no \"flags\" block element");
}
ASSERT(pArchetype != nullptr);
return pArchetype;
}
void CTemplateLoader::LoadProperties(XMLElement *pPropertiesElem, CScriptTemplate *pScript, CStructTemplate *pStruct, const TString& rkTemplateName)
void CTemplateLoader::LoadProperties(XMLElement *pPropertiesElem, CScriptTemplate *pScript, CStructPropertyNew* pStruct, const TString& rkTemplateName)
{
XMLElement *pChild = pPropertiesElem->FirstChildElement();
@ -359,12 +541,9 @@ void CTemplateLoader::LoadProperties(XMLElement *pPropertiesElem, CScriptTemplat
pChild = pChild->NextSiblingElement();
}
pStruct->mVersionPropertyCounts.resize(mpMaster->NumGameVersions());
pStruct->DetermineVersionPropertyCounts();
}
void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumTemplate *pTemp, const TString& rkTemplateName)
void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumProperty* pEnum, const TString& rkTemplateName)
{
XMLElement *pChild = pEnumeratorsElem->FirstChildElement("enumerator");
@ -376,10 +555,7 @@ void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumTemplat
if (pkID && pkName)
{
u32 EnumeratorID = TString(pkID).ToInt32();
pTemp->mEnumerators.push_back(CEnumTemplate::SEnumerator(pkName, EnumeratorID));
if (EnumeratorID > 0xFF)
pTemp->mUsesHashes = true;
pEnum->mValues.push_back(CEnumProperty::SEnumValue(pkName, EnumeratorID));
}
else
@ -395,7 +571,7 @@ void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumTemplat
}
}
void CTemplateLoader::LoadBitFlags(XMLElement *pFlagsElem, CBitfieldTemplate *pTemp, const TString& templateName)
void CTemplateLoader::LoadBitFlags(XMLElement *pFlagsElem, CFlagsProperty* pFlags, const TString& kTemplateName)
{
XMLElement *pChild = pFlagsElem->FirstChildElement("flag");
@ -405,11 +581,11 @@ void CTemplateLoader::LoadBitFlags(XMLElement *pFlagsElem, CBitfieldTemplate *pT
const char *pkName = pChild->Attribute("name");
if (pkMask && pkName)
pTemp->mBitFlags.push_back(CBitfieldTemplate::SBitFlag(pkName, TString(pkMask).ToInt32()));
pFlags->mBitFlags.push_back(CFlagsProperty::SBitFlag(pkName, TString(pkMask).ToInt32()));
else
{
TString LogErrorBase = templateName + ": Couldn't parse bit flag; ";
TString LogErrorBase = kTemplateName + ": Couldn't parse bit flag; ";
if (!pkMask && pkName) Log::Error(LogErrorBase + "no mask (" + pkName + ")");
else if (pkMask && !pkName) Log::Error(LogErrorBase + "no name (mask " + pkMask + ")");
@ -420,24 +596,27 @@ void CTemplateLoader::LoadBitFlags(XMLElement *pFlagsElem, CBitfieldTemplate *pT
}
}
enum class ETest
{
ValueA = (true ? 0 : (u32) reinterpret_cast<u64>("ValueA"))
};
// ************ SCRIPT OBJECT ************
CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TString& rkTemplateName, u32 ObjectID)
{
CScriptTemplate *pScript = new CScriptTemplate(mpMaster);
pScript->mObjectID = ObjectID;
pScript->mpBaseStruct = new CStructTemplate(-1, pScript, mpMaster);
pScript->mSourceFile = rkTemplateName;
IPropertyNew* pBaseStruct = IPropertyNew::Create(EPropertyTypeNew::Struct, nullptr, mpMaster, pScript);
pScript->mpProperties = std::make_unique<CStructPropertyNew>( *TPropCast<CStructPropertyNew>(pBaseStruct) );
XMLElement *pRoot = pDoc->FirstChildElement("ScriptTemplate");
// Name
XMLElement *pNameElem = pRoot->FirstChildElement("name");
if (pNameElem)
{
pScript->mTemplateName = pNameElem->GetText();
pScript->mpBaseStruct->SetName(pScript->mTemplateName);
}
ASSERT(pNameElem);
pScript->mpProperties->mName = pNameElem->GetText();
// Modules
XMLElement *pModulesElem = pRoot->FirstChildElement("modules");
@ -457,7 +636,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
XMLElement *pPropsElem = pRoot->FirstChildElement("properties");
if (pPropsElem)
LoadProperties(pPropsElem, pScript, pScript->mpBaseStruct, rkTemplateName);
LoadProperties(pPropsElem, pScript, pScript->Properties(), rkTemplateName);
else
Log::Error(rkTemplateName + ": There is no \"properties\" block element");
@ -565,7 +744,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
// Validate property asset
if (Asset.AssetSource == CScriptTemplate::SEditorAsset::eProperty)
{
if (!pScript->mpBaseStruct->HasProperty(Asset.AssetLocation))
if (!pScript->mpProperties->ChildByIDString(Asset.AssetLocation))
{
Log::Error(rkTemplateName + ": Invalid property for " + Type + " asset: " + ID);
pAsset = pAsset->NextSiblingElement();
@ -609,12 +788,12 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
Attachment.AttachType = eAttach;
// Validate property
IPropertyTemplate *pProp = pScript->mpBaseStruct->PropertyByIDString(Attachment.AttachProperty);
IPropertyNew* pProp = pScript->mpProperties->ChildByIDString(Attachment.AttachProperty);
if (!pProp)
Log::Error(rkTemplateName + ": Invalid property for attachment " + TString::FromInt32(AttachIdx) + ": " + Attachment.AttachProperty);
else if (pProp->Type() != eCharacterProperty && (pProp->Type() != eAssetProperty || !static_cast<CAssetTemplate*>(pProp)->TypeFilter().Accepts(eModel)))
Log::Error(rkTemplateName + ": Property referred to by attachment " + TString::FromInt32(AttachIdx) + " is not an attachable asset! Must be a file property that accepts CMDLs, or a character property.");
else if (pProp->Type() != EPropertyTypeNew::AnimationSet && (pProp->Type() != EPropertyTypeNew::Asset || !TPropCast<CAssetProperty>(pProp)->GetTypeFilter().Accepts(eModel)))
Log::Error(rkTemplateName + ": Property referred to by attachment " + TString::FromInt32(AttachIdx) + " is not an attachable asset! Must be a file property that accepts CMDLs, or an animation set property.");
else
{
@ -746,6 +925,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
}
}
pScript->PostLoad();
return pScript;
}

View File

@ -3,6 +3,9 @@
#include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptTemplate.h"
#include "Core/Resource/Script/IPropertyNew.h"
#include "Core/Resource/Script/Property/CEnumProperty.h"
#include "Core/Resource/Script/Property/CFlagsProperty.h"
#include <tinyxml2.h>
class CTemplateLoader
@ -20,23 +23,23 @@ class CTemplateLoader
: mTemplatesDir(rkTemplatesDir) {}
// Load Property
IPropertyTemplate* LoadProperty(tinyxml2::XMLElement *pElem, CScriptTemplate *pScript, CStructTemplate *pParentStruct, const TString& rkTemplateName);
IPropertyTemplate* CreateProperty(u32 ID, EPropertyType Type, const TString& rkName, CScriptTemplate *pScript, CStructTemplate *pStruct);
IPropertyNew* LoadProperty(tinyxml2::XMLElement* pElem, CScriptTemplate* pScript, CStructPropertyNew* pParentStruct, const TString& rkTemplateName);
IPropertyNew* CreateProperty(u32 ID, EPropertyTypeNew Type, const TString& rkName, CScriptTemplate* pScript, CStructPropertyNew* pStruct);
void LoadStructTemplate(const TString& rkTemplateFileName, CStructTemplate *pStruct);
void LoadEnumTemplate(const TString& rkTemplateFileName, CEnumTemplate *pEnum);
void LoadBitfieldTemplate(const TString& rkTemplateFileName, CBitfieldTemplate *pBitfield);
CStructPropertyNew* LoadStructArchetype(const TString& rkTemplateFileName);
CEnumProperty* LoadEnumArchetype(const TString& rkTemplateFileName, bool bIsChoice);
CFlagsProperty* LoadFlagsArchetype(const TString& rkTemplateFileName);
void LoadProperties(tinyxml2::XMLElement *pPropertiesElem, CScriptTemplate *pScript, CStructTemplate *pStruct, const TString& rkTemplateName);
void LoadEnumerators(tinyxml2::XMLElement *pEnumeratorsElem, CEnumTemplate *pEnum, const TString& rkTemplateName);
void LoadBitFlags(tinyxml2::XMLElement *pFlagsElem, CBitfieldTemplate *pBitfield, const TString& rkTemplateName);
void LoadProperties(tinyxml2::XMLElement* pPropertiesElem, CScriptTemplate* pScript, CStructPropertyNew* pStruct, const TString& rkTemplateName);
void LoadEnumerators(tinyxml2::XMLElement* pEnumeratorsElem, CEnumProperty* pEnum, const TString& rkTemplateName);
void LoadBitFlags(tinyxml2::XMLElement* pFlagsElem, CFlagsProperty* pFlags, const TString& rkTemplateName);
// Load Script Object
CScriptTemplate* LoadScriptTemplate(tinyxml2::XMLDocument *pDoc, const TString& rkTemplateName, u32 ObjectID);
CScriptTemplate* LoadScriptTemplate(tinyxml2::XMLDocument* pDoc, const TString& rkTemplateName, u32 ObjectID);
// Load Master
CMasterTemplate* LoadGameInfo(tinyxml2::XMLNode *pNode);
void LoadMasterTemplate(tinyxml2::XMLDocument *pDoc, CMasterTemplate *pMaster);
CMasterTemplate* LoadGameInfo(tinyxml2::XMLNode* pNode);
void LoadMasterTemplate(tinyxml2::XMLDocument* pDoc, CMasterTemplate* pMaster);
// Utility
static void OpenXML(const TString& rkPath, tinyxml2::XMLDocument& rDoc);
@ -46,7 +49,7 @@ public:
static void LoadGameList();
static void LoadGameTemplates(EGame Game);
static void LoadAllGames();
static void LoadPropertyList(tinyxml2::XMLDocument *pDoc, const TString& rkListName);
static void LoadPropertyList(tinyxml2::XMLDocument* pDoc, const TString& rkListName);
};
#endif // CTEMPLATELOADER_H

View File

@ -88,7 +88,7 @@ SMessage CMasterTemplate::MessageByIndex(u32 Index)
return (std::next(it, Index))->second;
}
CStructTemplate* CMasterTemplate::StructAtSource(const TString& rkSource)
CStructPropertyNew* CMasterTemplate::StructAtSource(const TString& rkSource)
{
auto InfoIt = mStructTemplates.find(rkSource);
@ -149,38 +149,44 @@ TString CMasterTemplate::PropertyName(u32 PropertyID)
return "Unknown";
}
u32 CMasterTemplate::CreatePropertyID(IPropertyTemplate *pTemp)
// Removing these functions for now. I'm not sure of the best way to go about implementing them under the new system yet.
u32 CMasterTemplate::CreatePropertyID(IPropertyNew* 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).
TString IDString = pTemp->IDString(false);
TString Source;
CStructTemplate *pStruct = pTemp->Parent();
//
// 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();
while (pStruct)
{
Source = pStruct->SourceFile();
if (!Source.IsEmpty()) break;
IDString.Prepend(pStruct->IDString(false) + ":");
pStruct = pStruct->Parent();
}
return IDString.Hash32() * Source.Hash32();
CCRC32 Hash;
Hash.Hash(*IDString);
Hash.Hash(*TemplateFile);
return Hash.Digest();
}
void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTemplateName /*= ""*/)
void CMasterTemplate::AddProperty(IPropertyNew* pProp, const TString& rkTemplateName /*= ""*/)
{
u32 ID;
if (pTemp->Game() >= eEchoesDemo)
ID = pTemp->PropertyID();
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.
if (!pTemp->IsFromStructTemplate()) return;
else ID = CreatePropertyID(pTemp);
IPropertyNew* pArchetype = pProp->Archetype();
if (!pArchetype ||
pArchetype->ScriptTemplate() != nullptr ||
pArchetype->RootParent()->Type() != EPropertyTypeNew::Struct)
return;
ID = CreatePropertyID(pProp);
}
auto it = smIDMap.find(ID);
@ -189,7 +195,7 @@ void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTem
if (it != smIDMap.end())
{
SPropIDInfo& rInfo = it->second;
rInfo.PropertyList.push_back(pTemp);
rInfo.PropertyList.push_back(pProp);
if (!rkTemplateName.IsEmpty())
{
@ -214,15 +220,15 @@ void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTem
{
SPropIDInfo Info;
if (!rkTemplateName.IsEmpty()) Info.XMLList.push_back(rkTemplateName);
Info.PropertyList.push_back(pTemp);
Info.PropertyList.push_back(pProp);
smIDMap[ID] = Info;
}
}
void CMasterTemplate::RenameProperty(IPropertyTemplate *pTemp, const TString& rkNewName)
void CMasterTemplate::RenameProperty(IPropertyNew* pProp, const TString& rkNewName)
{
u32 ID = pTemp->PropertyID();
if (ID <= 0xFF) ID = CreatePropertyID(pTemp);
u32 ID = pProp->ID();
if (ID <= 0xFF) ID = CreatePropertyID(pProp);
RenameProperty(ID, rkNewName);
}
@ -245,10 +251,10 @@ void CMasterTemplate::RenameProperty(u32 ID, const TString& rkNewName)
{
const SPropIDInfo& rkInfo = InfoIt->second;
for (u32 iTemp = 0; iTemp < rkInfo.PropertyList.size(); iTemp++)
for (u32 PropertyIdx = 0; PropertyIdx < rkInfo.PropertyList.size(); PropertyIdx++)
{
if (Original.IsEmpty() || rkInfo.PropertyList[iTemp]->Name() == Original)
rkInfo.PropertyList[iTemp]->SetName(rkNewName);
if (Original.IsEmpty() || rkInfo.PropertyList[PropertyIdx]->Name() == Original)
rkInfo.PropertyList[PropertyIdx]->SetName(rkNewName);
}
}
}
@ -264,10 +270,10 @@ void CMasterTemplate::XMLsUsingID(u32 ID, std::vector<TString>& rOutList)
}
}
const std::vector<IPropertyTemplate*>* CMasterTemplate::TemplatesWithMatchingID(IPropertyTemplate *pTemp)
const std::vector<IPropertyNew*>* CMasterTemplate::TemplatesWithMatchingID(IPropertyNew* pProp)
{
u32 ID = pTemp->PropertyID();
if (ID <= 0xFF) ID = CreatePropertyID(pTemp);
u32 ID = pProp->ID();
if (ID <= 0xFF) ID = CreatePropertyID(pProp);
auto InfoIt = smIDMap.find(ID);

View File

@ -3,6 +3,7 @@
#include "CLink.h"
#include "CScriptTemplate.h"
#include "Core/Resource/Script/Property/Properties.h"
#include <Common/EGame.h>
#include <Common/types.h>
#include <map>
@ -19,7 +20,9 @@ class CMasterTemplate
bool mFullyLoaded;
std::vector<TString> mGameVersions;
std::map<TString, CStructTemplate*> mStructTemplates;
std::map<TString, CStructPropertyNew*> mStructTemplates;
std::map<TString, CEnumProperty*> mEnumTemplates;
std::map<TString, CFlagsProperty*> mFlagsTemplates;
std::map<u32, CScriptTemplate*> mTemplates;
std::map<u32, SState> mStates;
@ -28,7 +31,7 @@ class CMasterTemplate
struct SPropIDInfo
{
std::vector<TString> XMLList; // List of script/struct templates that use this ID
std::vector<IPropertyTemplate*> PropertyList; // List of all properties that use this ID
std::vector<IPropertyNew*> PropertyList; // List of all properties that use this ID
};
static std::map<u32, SPropIDInfo> smIDMap;
static std::map<EGame, CMasterTemplate*> smMasterMap;
@ -48,7 +51,7 @@ public:
SMessage MessageByID(u32 MessageID);
SMessage MessageByID(const CFourCC& MessageID);
SMessage MessageByIndex(u32 Index);
CStructTemplate* StructAtSource(const TString& rkSource);
CStructPropertyNew* StructAtSource(const TString& rkSource);
// Inline Accessors
inline EGame Game() const { return mGame; }
@ -66,12 +69,12 @@ public:
static TString FindGameName(EGame Game);
static EGame FindGameForName(const TString& rkName);
static TString PropertyName(u32 PropertyID);
static u32 CreatePropertyID(IPropertyTemplate *pTemp);
static void AddProperty(IPropertyTemplate *pTemp, const TString& rkTemplateName = "");
static void RenameProperty(IPropertyTemplate *pTemp, const TString& rkNewName);
static u32 CreatePropertyID(IPropertyNew *pTemp);
static void AddProperty(IPropertyNew *pTemp, const TString& rkTemplateName = "");
static void RenameProperty(IPropertyNew *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<IPropertyTemplate*>* TemplatesWithMatchingID(IPropertyTemplate *pTemp);
static const std::vector<IPropertyNew*>* TemplatesWithMatchingID(IPropertyNew *pTemp);
};
#endif // CMASTERTEMPLATE_H

View File

@ -13,19 +13,29 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa
, mIsCheckingNearVisibleActivation(false)
{
mpTemplate->AddObject(this);
mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(this, nullptr);
mpInstanceName = mpTemplate->FindInstanceName(mpProperties);
mpPosition = mpTemplate->FindPosition(mpProperties);
mpRotation = mpTemplate->FindRotation(mpProperties);
mpScale = mpTemplate->FindScale(mpProperties);
mpActive = mpTemplate->FindActive(mpProperties);
mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
// Init properties
CStructPropertyNew* pProperties = pTemplate->Properties();
u32 PropertiesSize = pProperties->DataSize();
mPropertyData.resize( PropertiesSize );
pProperties->Construct( mPropertyData.data() );
mInstanceName = CStringRef(this, pTemplate->NameProperty());
mPosition = CVectorRef(this, pTemplate->PositionProperty());
mRotation = CVectorRef(this, pTemplate->RotationProperty());
mScale = CVectorRef(this, pTemplate->ScaleProperty());
mActive = CBoolRef(this, pTemplate->ActiveProperty());
mLightParameters = CStructRef(this, pTemplate->LightParametersProperty());
}
CScriptObject::~CScriptObject()
{
if (mpProperties) delete mpProperties;
if (!mPropertyData.empty())
{
mpTemplate->Properties()->Destruct( mPropertyData.data() );
mPropertyData.clear();
}
mpTemplate->RemoveObject(this);
// Note: Incoming links will be deleted by the sender.
@ -34,6 +44,19 @@ CScriptObject::~CScriptObject()
}
// ************ DATA MANIPULATION ************
void CScriptObject::CopyProperties(CScriptObject* pObject)
{
ASSERT(pObject->Template() == Template());
CSerialVersion Version(0, IArchive::skCurrentArchiveVersion, Template()->Game());
CVectorOutStream DataStream;
CBasicBinaryWriter DataWriter(&DataStream, Version);
Template()->Properties()->SerializeValue( pObject->PropertyData(), DataWriter );
CBasicBinaryReader DataReader(DataStream.Data(), DataStream.Size(), Version);
Template()->Properties()->SerializeValue( PropertyData(), DataReader );
}
void CScriptObject::EvaluateProperties()
{
EvaluateDisplayAsset();
@ -43,12 +66,12 @@ CScriptObject::~CScriptObject()
void CScriptObject::EvaluateDisplayAsset()
{
mpDisplayAsset = mpTemplate->FindDisplayAsset(mpProperties, mActiveCharIndex, mActiveAnimIndex, mHasInGameModel);
mpDisplayAsset = mpTemplate->FindDisplayAsset(PropertyData(), mActiveCharIndex, mActiveAnimIndex, mHasInGameModel);
}
void CScriptObject::EvaluateCollisionModel()
{
mpCollision = mpTemplate->FindCollision(mpProperties);
mpCollision = mpTemplate->FindCollision(PropertyData());
}
void CScriptObject::EvaluateVolume()
@ -57,15 +80,15 @@ void CScriptObject::EvaluateVolume()
mVolumeScale = mpTemplate->VolumeScale(this);
}
bool CScriptObject::IsEditorProperty(IProperty *pProp)
bool CScriptObject::IsEditorProperty(IPropertyNew *pProp)
{
return ( (pProp == mpInstanceName) ||
(pProp == mpPosition) ||
(pProp == mpRotation) ||
(pProp == mpScale) ||
(pProp == mpActive) ||
(pProp == mpLightParameters) ||
(pProp->Parent() == mpLightParameters)
return ( (pProp == mInstanceName.Property()) ||
(pProp == mPosition.Property()) ||
(pProp == mRotation.Property()) ||
(pProp == mScale.Property()) ||
(pProp == mActive.Property()) ||
(pProp == mLightParameters.Property()) ||
(pProp->Parent() == mLightParameters.Property())
);
}

View File

@ -1,12 +1,11 @@
#ifndef CSCRIPTOBJECT_H
#define CSCRIPTOBJECT_H
#include "IProperty.h"
#include "IPropertyTemplate.h"
#include "CScriptTemplate.h"
#include "Core/Resource/Area/CGameArea.h"
#include "Core/Resource/Model/CModel.h"
#include "Core/Resource/CCollisionMeshGroup.h"
#include "Core/Resource/Script/Property/Properties.h"
class CScriptLayer;
class CLink;
@ -30,14 +29,15 @@ class CScriptObject
u32 mInstanceID;
std::vector<CLink*> mOutLinks;
std::vector<CLink*> mInLinks;
CPropertyStruct *mpProperties;
std::vector<char> mPropertyData;
CStringRef mInstanceName;
CVectorRef mPosition;
CVectorRef mRotation;
CVectorRef mScale;
CBoolRef mActive;
CStructRef mLightParameters;
TStringProperty *mpInstanceName;
TVector3Property *mpPosition;
TVector3Property *mpRotation;
TVector3Property *mpScale;
TBoolProperty *mpActive;
CPropertyStruct *mpLightParameters;
TResPtr<CResource> mpDisplayAsset;
TResPtr<CCollisionMeshGroup> mpCollision;
u32 mActiveCharIndex;
@ -54,11 +54,12 @@ public:
CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLayer, CScriptTemplate *pTemplate);
~CScriptObject();
void CopyProperties(CScriptObject* pObject);
void EvaluateProperties();
void EvaluateDisplayAsset();
void EvaluateCollisionModel();
void EvaluateVolume();
bool IsEditorProperty(IProperty *pProp);
bool IsEditorProperty(IPropertyNew *pProp);
void SetLayer(CScriptLayer *pLayer, u32 NewLayerIndex = -1);
u32 LayerIndex() const;
bool HasNearVisibleActivation() const;
@ -73,39 +74,37 @@ public:
CGameArea* Area() const { return mpArea; }
CScriptLayer* Layer() const { return mpLayer; }
u32 Version() const { return mVersion; }
CPropertyStruct* Properties() const { return mpProperties; }
u32 NumProperties() const { return mpProperties->Count(); }
IProperty* PropertyByIndex(u32 Index) const { return mpProperties->PropertyByIndex(Index); }
IProperty* PropertyByIDString(const TIDString& rkStr) const { return mpProperties->PropertyByIDString(rkStr); }
u32 ObjectTypeID() const { return mpTemplate->ObjectID(); }
u32 InstanceID() const { return mInstanceID; }
u32 NumLinks(ELinkType Type) const { return (Type == eIncoming ? mInLinks.size() : mOutLinks.size()); }
CLink* Link(ELinkType Type, u32 Index) const { return (Type == eIncoming ? mInLinks[Index] : mOutLinks[Index]); }
void* PropertyData() const { return (void*) mPropertyData.data(); }
CVector3f Position() const { return mpPosition ? mpPosition->Get() : CVector3f::skZero; }
CVector3f Rotation() const { return mpRotation ? mpRotation->Get() : CVector3f::skZero; }
CVector3f Scale() const { return mpScale ? mpScale->Get() : CVector3f::skOne; }
TString InstanceName() const { return mpInstanceName ? mpInstanceName->Get() : ""; }
bool IsActive() const { return mpActive ? mpActive->Get() : false; }
CVector3f Position() const { return mPosition.IsValid() ? mPosition.Get() : CVector3f::skZero; }
CVector3f Rotation() const { return mRotation.IsValid() ? mRotation.Get() : CVector3f::skZero; }
CVector3f Scale() const { return mScale.IsValid() ? mScale.Get() : CVector3f::skOne; }
TString InstanceName() const { return mInstanceName.IsValid() ? mInstanceName.Get() : ""; }
bool IsActive() const { return mActive.IsValid() ? mActive.Get() : false; }
bool HasInGameModel() const { return mHasInGameModel; }
CPropertyStruct* LightParameters() const { return mpLightParameters; }
CStructRef LightParameters() const { return mLightParameters; }
CResource* DisplayAsset() const { return mpDisplayAsset; }
u32 ActiveCharIndex() const { return mActiveCharIndex; }
u32 ActiveAnimIndex() const { return mActiveAnimIndex; }
CCollisionMeshGroup* Collision() const { return mpCollision; }
EVolumeShape VolumeShape() const { return mVolumeShape; }
float VolumeScale() const { return mVolumeScale; }
void SetPosition(const CVector3f& rkNewPos) { if (mpPosition) mpPosition->Set(rkNewPos); }
void SetRotation(const CVector3f& rkNewRot) { if (mpRotation) mpRotation->Set(rkNewRot); }
void SetScale(const CVector3f& rkNewScale) { if (mpScale) mpScale->Set(rkNewScale); }
void SetName(const TString& rkNewName) { if (mpInstanceName) mpInstanceName->Set(rkNewName); }
void SetActive(bool Active) { if (mpActive) mpActive->Set(Active); }
void SetPosition(const CVector3f& rkNewPos) { mPosition.Set(rkNewPos); }
void SetRotation(const CVector3f& rkNewRot) { mRotation.Set(rkNewRot); }
void SetScale(const CVector3f& rkNewScale) { mScale.Set(rkNewScale); }
void SetName(const TString& rkNewName) { mInstanceName.Set(rkNewName); }
void SetActive(bool Active) { mActive.Set(Active); }
TVector3Property* PositionProperty() const { return mpPosition; }
TVector3Property* RotationProperty() const { return mpRotation; }
TVector3Property* ScaleProperty() const { return mpScale; }
TStringProperty* InstanceNameProperty() const { return mpInstanceName; }
TBoolProperty* ActiveProperty() const { return mpActive; }
bool HasPosition() const { return mPosition.IsValid(); }
bool HasRotation() const { return mRotation.IsValid(); }
bool HasScale() const { return mScale.IsValid(); }
bool HasInstanceName() const { return mInstanceName.IsValid(); }
bool HasActive() const { return mActive.IsValid(); }
bool HasLightParameters() const { return mLightParameters.IsValid(); }
};
#endif // CSCRIPTOBJECT_H

View File

@ -10,8 +10,14 @@
CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster)
: mpMaster(pMaster)
, mpBaseStruct(nullptr)
, mpProperties(nullptr)
, mVisible(true)
, mpNameProperty(nullptr)
, mpPositionProperty(nullptr)
, mpRotationProperty(nullptr)
, mpScaleProperty(nullptr)
, mpActiveProperty(nullptr)
, mpLightParametersProperty(nullptr)
, mPreviewScale(1.f)
, mVolumeShape(eNoShape)
, mVolumeScale(1.f)
@ -20,7 +26,16 @@ CScriptTemplate::CScriptTemplate(CMasterTemplate *pMaster)
CScriptTemplate::~CScriptTemplate()
{
delete mpBaseStruct;
}
void CScriptTemplate::PostLoad()
{
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<CStructPropertyNew>( mpProperties->ChildByIDString(mLightParametersIDString) );
}
EGame CScriptTemplate::Game() const
@ -29,14 +44,14 @@ EGame CScriptTemplate::Game() const
}
// ************ PROPERTY FETCHING ************
template<typename PropType, EPropertyType PropEnum>
PropType TFetchProperty(CPropertyStruct *pProperties, const TIDString& rkID)
template<class PropType>
PropType* TFetchProperty(CStructPropertyNew* pProperties, const TIDString& rkID)
{
if (rkID.IsEmpty()) return nullptr;
IProperty *pProp = pProperties->PropertyByIDString(rkID);
IPropertyNew *pProp = pProperties->ChildByIDString(rkID);
if (pProp && (pProp->Type() == PropEnum))
return static_cast<PropType>(pProp);
return static_cast<PropType*>(pProp)->ValuePtr();
else
return nullptr;
}
@ -80,39 +95,42 @@ s32 CScriptTemplate::CheckVolumeConditions(CScriptObject *pObj, bool LogErrors)
// Private function
if (mVolumeShape == eConditionalShape)
{
IProperty *pProp = pObj->Properties()->PropertyByIDString(mVolumeConditionIDString);
TIDString PropID = mVolumeConditionIDString;
IPropertyNew* pProp = pObj->Template()->Properties()->ChildByIDString( PropID );
// Get value of the condition test property (only boolean, integral, and enum types supported)
void* pData = pObj->PropertyData();
int Val;
switch (pProp->Type())
{
case eBoolProperty:
Val = (static_cast<TBoolProperty*>(pProp)->Get() ? 1 : 0);
case EPropertyTypeNew::Bool:
Val = TPropCast<CBoolProperty>(pProp)->Value(pData) ? 1 : 0;
break;
case eByteProperty:
Val = (int) static_cast<TByteProperty*>(pProp)->Get();
case EPropertyTypeNew::Byte:
Val = (int) TPropCast<CByteProperty>(pProp)->Value(pData);
break;
case eShortProperty:
Val = (int) static_cast<TShortProperty*>(pProp)->Get();
case EPropertyTypeNew::Short:
Val = (int) TPropCast<CShortProperty>(pProp)->Value(pData);
break;
case eLongProperty:
Val = (int) static_cast<TLongProperty*>(pProp)->Get();
case EPropertyTypeNew::Int:
Val = TPropCast<CIntProperty>(pProp)->Value(pData);
break;
case eEnumProperty:
Val = (int) static_cast<TEnumProperty*>(pProp)->Get();
case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
Val = TPropCast<CEnumProperty>(pProp)->Value(pData);
break;
}
// Test and check whether any of the conditions are true
for (u32 iCon = 0; iCon < mVolumeConditions.size(); iCon++)
for (u32 LinkIdx = 0; LinkIdx < mVolumeConditions.size(); LinkIdx++)
{
if (mVolumeConditions[iCon].Value == Val)
return iCon;
if (mVolumeConditions[LinkIdx].Value == Val)
return LinkIdx;
}
if (LogErrors)
@ -122,37 +140,7 @@ s32 CScriptTemplate::CheckVolumeConditions(CScriptObject *pObj, bool LogErrors)
return -1;
}
TStringProperty* CScriptTemplate::FindInstanceName(CPropertyStruct *pProperties)
{
return TFetchProperty<TStringProperty*, eStringProperty>(pProperties, mNameIDString);
}
TVector3Property* CScriptTemplate::FindPosition(CPropertyStruct *pProperties)
{
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mPositionIDString);
}
TVector3Property* CScriptTemplate::FindRotation(CPropertyStruct *pProperties)
{
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mRotationIDString);
}
TVector3Property* CScriptTemplate::FindScale(CPropertyStruct *pProperties)
{
return TFetchProperty<TVector3Property*, eVector3Property>(pProperties, mScaleIDString);
}
TBoolProperty* CScriptTemplate::FindActive(CPropertyStruct *pProperties)
{
return TFetchProperty<TBoolProperty*, eBoolProperty>(pProperties, mActiveIDString);
}
CPropertyStruct* CScriptTemplate::FindLightParameters(CPropertyStruct *pProperties)
{
return TFetchProperty<CPropertyStruct*, eStructProperty>(pProperties, mLightParametersIDString);
}
CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame)
CResource* CScriptTemplate::FindDisplayAsset(void* pPropertyData, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame)
{
rOutCharIndex = -1;
rOutAnimIndex = -1;
@ -170,25 +158,28 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
// Property
else
{
IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation);
IPropertyNew* pProp = mpProperties->ChildByIDString(it->AssetLocation);
if (it->AssetType == SEditorAsset::eAnimParams && pProp->Type() == eCharacterProperty)
if (it->AssetType == SEditorAsset::eAnimParams && pProp->Type() == EPropertyTypeNew::AnimationSet)
{
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
pRes = pChar->Get().AnimSet();
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
CAnimationParameters Params = pAnimSet->Value(pPropertyData);
pRes = Params.AnimSet();
if (pRes)
{
u32 MaxNumChars = static_cast<CAnimSet*>(pRes)->NumCharacters();
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) MaxNumChars ? it->ForceNodeIndex : pChar->Get().CharacterIndex());
rOutAnimIndex = pChar->Get().AnimIndex();
rOutCharIndex = (it->ForceNodeIndex >= 0 && it->ForceNodeIndex < (s32) MaxNumChars ? it->ForceNodeIndex : Params.CharacterIndex());
rOutAnimIndex = Params.AnimIndex();
}
}
else
{
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
CResourceEntry *pEntry = gpResourceStore->FindEntry(pAsset->Get());
ASSERT(pProp->Type() == EPropertyTypeNew::Asset);
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
CAssetID ID = pAsset->Value(pPropertyData);
CResourceEntry *pEntry = gpResourceStore->FindEntry( ID );
if (pEntry) pRes = pEntry->Load();
}
}
@ -205,7 +196,7 @@ CResource* CScriptTemplate::FindDisplayAsset(CPropertyStruct *pProperties, u32&
return nullptr;
}
CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties)
CCollisionMeshGroup* CScriptTemplate::FindCollision(void* pPropertyData)
{
for (auto it = mAssets.begin(); it != mAssets.end(); it++)
{
@ -219,12 +210,12 @@ CCollisionMeshGroup* CScriptTemplate::FindCollision(CPropertyStruct *pProperties
// Property
else
{
IProperty *pProp = pProperties->PropertyByIDString(it->AssetLocation);
IPropertyNew* pProp = mpProperties->ChildByIDString(it->AssetLocation);
if (pProp->Type() == eAssetProperty)
if (pProp->Type() == EPropertyTypeNew::Asset)
{
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
pRes = gpResourceStore->LoadResource( pAsset->Get(), eDynamicCollision );
CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
pRes = gpResourceStore->LoadResource( pAsset->Value(pPropertyData), eDynamicCollision );
}
}

View File

@ -1,8 +1,7 @@
#ifndef CSCRIPTTEMPLATE_H
#define CSCRIPTTEMPLATE_H
#include "IPropertyTemplate.h"
#include "IProperty.h"
#include "Core/Resource/Script/Property/Properties.h"
#include "EPropertyType.h"
#include "EVolumeShape.h"
#include "Core/Resource/Model/CModel.h"
@ -12,6 +11,7 @@
#include <list>
#include <vector>
class CMasterTemplate;
class CScriptObject;
typedef TString TIDString;
@ -64,10 +64,9 @@ private:
s32 ForceNodeIndex; // Force animsets to use specific node instead of one from property
};
CMasterTemplate *mpMaster;
CStructTemplate *mpBaseStruct;
CMasterTemplate* mpMaster;
std::unique_ptr<CStructPropertyNew> mpProperties;
std::list<CScriptObject*> mObjectList;
TString mTemplateName;
std::vector<TString> mModules;
TString mSourceFile;
u32 mObjectID;
@ -80,6 +79,14 @@ private:
TIDString mScaleIDString;
TIDString mActiveIDString;
TIDString mLightParametersIDString;
CStringProperty* mpNameProperty;
CVectorProperty* mpPositionProperty;
CVectorProperty* mpRotationProperty;
CVectorProperty* mpScaleProperty;
CBoolProperty* mpActiveProperty;
CStructPropertyNew* mpLightParametersProperty;
std::vector<SEditorAsset> mAssets;
std::vector<SAttachment> mAttachments;
@ -102,44 +109,38 @@ private:
public:
CScriptTemplate(CMasterTemplate *pMaster);
~CScriptTemplate();
void PostLoad();
EGame Game() const;
// Property Fetching
EVolumeShape VolumeShape(CScriptObject *pObj);
float VolumeScale(CScriptObject *pObj);
TStringProperty* FindInstanceName(CPropertyStruct *pProperties);
TVector3Property* FindPosition(CPropertyStruct *pProperties);
TVector3Property* FindRotation(CPropertyStruct *pProperties);
TVector3Property* FindScale(CPropertyStruct *pProperties);
TBoolProperty* FindActive(CPropertyStruct *pProperties);
CPropertyStruct* FindLightParameters(CPropertyStruct *pProperties);
CResource* FindDisplayAsset(CPropertyStruct *pProperties, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame);
CCollisionMeshGroup* FindCollision(CPropertyStruct *pProperties);
CResource* FindDisplayAsset(void* pPropertyData, u32& rOutCharIndex, u32& rOutAnimIndex, bool& rOutIsInGame);
CCollisionMeshGroup* FindCollision(void* pPropertyData);
// Accessors
inline CMasterTemplate* MasterTemplate() const { return mpMaster; }
inline TString Name() const { return mTemplateName; }
inline TString Name() const { return mpProperties->Name(); }
inline ERotationType RotationType() const { return mRotationType; }
inline EScaleType ScaleType() const { return mScaleType; }
inline float PreviewScale() const { return mPreviewScale; }
inline u32 ObjectID() const { return mObjectID; }
inline bool IsVisible() const { return mVisible; }
inline TString SourceFile() const { return mSourceFile; }
inline CStructTemplate* BaseStruct() const { return mpBaseStruct; }
inline CStructPropertyNew* Properties() const { return mpProperties.get(); }
inline u32 NumAttachments() const { return mAttachments.size(); }
const SAttachment& Attachment(u32 Index) const { return mAttachments[Index]; }
const std::vector<TString>& RequiredModules() const { return mModules; }
inline bool HasName() const { return !mNameIDString.IsEmpty(); }
inline bool HasPosition() const { return !mPositionIDString.IsEmpty(); }
inline bool HasRotation() const { return !mRotationIDString.IsEmpty(); }
inline bool HasScale() const { return !mScaleIDString.IsEmpty(); }
inline bool HasActive() const { return !mActiveIDString.IsEmpty(); }
inline CStringProperty* NameProperty() const { return mpNameProperty; }
inline CVectorProperty* PositionProperty() const { return mpPositionProperty; }
inline CVectorProperty* RotationProperty() const { return mpRotationProperty; }
inline CVectorProperty* ScaleProperty() const { return mpScaleProperty; }
inline CBoolProperty* ActiveProperty() const { return mpActiveProperty; }
inline CStructPropertyNew* LightParametersProperty() const { return mpLightParametersProperty; }
inline void SetVisible(bool Visible) { mVisible = Visible; }
inline void DebugPrintProperties() { mpBaseStruct->DebugPrintProperties(""); }
// Object Tracking
u32 NumObjects() const;
const std::list<CScriptObject*>& ObjectList() const;

View File

@ -1,6 +1,9 @@
#ifndef EPROPERTYTYPE
#define EPROPERTYTYPE
#include "IPropertyNew.h"
#if 0
#include <Common/TString.h>
enum EPropertyType
@ -24,11 +27,12 @@ enum EPropertyType
eUnknownProperty,
eInvalidProperty
};
#endif
// functions defined in IPropertyTemplate.cpp
EPropertyType PropStringToPropEnum(TString Prop);
TString PropEnumToPropString(EPropertyType Prop);
const char* HashablePropTypeName(EPropertyType Prop);
EPropertyTypeNew PropStringToPropEnum(TString Prop);
TString PropEnumToPropString(EPropertyTypeNew Prop);
const char* HashablePropTypeName(EPropertyTypeNew Prop);
#endif // EPROPERTYTYPE

View File

@ -1,6 +1,7 @@
#include "IProperty.h"
#include "IPropertyTemplate.h"
#if 0
// ************ IProperty ************
bool IProperty::IsInArray() const
{
@ -241,3 +242,4 @@ TString CArrayProperty::ElementName() const
{
return static_cast<CArrayTemplate*>(Template())->ElementName();
}
#endif

View File

@ -1,6 +1,7 @@
#ifndef IPROPERTY
#define IPROPERTY
#if 0
#include "EPropertyType.h"
#include "IPropertyValue.h"
#include "Core/Resource/CResource.h"
@ -297,6 +298,6 @@ PropertyClass* TPropCast(IProperty *pProp)
{
return (pProp && pProp->Type() == PropertyClass::StaticType() ? static_cast<PropertyClass*>(pProp) : nullptr);
}
#endif
#endif // IPROPERTY

View File

@ -0,0 +1,364 @@
#include "IPropertyNew.h"
#include "Property/CAssetProperty.h"
#include "Property/CArrayProperty.h"
#include "Property/CEnumProperty.h"
#include "Property/CFlagsProperty.h"
#include "Property/CPointerProperty.h"
#include "Core/Resource/Script/CMasterTemplate.h"
#include "Core/Resource/Script/CScriptTemplate.h"
/** IPropertyNew */
IPropertyNew::IPropertyNew()
: mpParent( nullptr )
, mpPointerParent( nullptr )
, mpArchetype( nullptr )
, mOffset( -1 )
, mID( -1 )
, mCookPreference( ECookPreferenceNew::Default )
, mMinVersion( 0.0f )
, 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;
}
}
u32 IPropertyNew::_GetOffset() const
{
return mOffset;
}
void IPropertyNew::_ClearChildren()
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
delete mChildren[ChildIdx];
mChildren.clear();
}
IPropertyNew::~IPropertyNew()
{
// Remove from archetype
if( mpArchetype != nullptr )
{
NBasics::VectorRemoveOne(mpArchetype->mSubInstances, this);
}
// If this is an archetype, all our sub-instances should have destructed first.
if( IsArchetype() )
{
ASSERT(mSubInstances.empty());
}
// Delete children
_ClearChildren();
}
const char* IPropertyNew::HashableTypeName() const
{
return PropEnumToHashableTypeName( Type() );
}
void* IPropertyNew::GetChildDataPointer(void* pPropertyData) const
{
return pPropertyData;
}
#if 0
void IPropertyNew::Serialize(IArchive& rArc)
{
if (rArc.Game() <= ePrime)
{
rArc << SERIAL("Name", mName);
}
rArc << SERIAL_HEX("ID", mID)
<< SERIAL("Description", mDescription)
<< SERIAL("CookPref", mCookPref)
<< SERIAL("MinVersion", mMinVersion)
<< SERIAL("MaxVersion", mMaxVersion);
// Children don't get serialized for most property types
}
#endif
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;
mCookPreference = pOther->mCookPreference;
mMinVersion = pOther->mMinVersion;
mMaxVersion = pOther->mMaxVersion;
// Copy children
_ClearChildren();
for (u32 ChildIdx = 0; ChildIdx < pOther->mChildren.size(); ChildIdx++)
{
CreateCopy( pOther->mChildren[ChildIdx], this );
}
}
TString IPropertyNew::GetTemplateFileName()
{
if (mpScriptTemplate)
{
return mpScriptTemplate->SourceFile();
}
else if (IsArchetype())
{
IPropertyNew* pRootParent = RootParent();
ASSERT(pRootParent != this);
return pRootParent->GetTemplateFileName();
}
else
{
return mpArchetype->GetTemplateFileName();
}
}
void* IPropertyNew::RawValuePtr(void* pData) const
{
// For array archetypes, the caller needs to provide the pointer to the correct array item
if (IsArrayArchetype())
return pData;
void* pBasePtr = (mpPointerParent ? mpPointerParent->GetChildDataPointer(pData) : pData);
return ((char*)pBasePtr + mOffset);
}
IPropertyNew* IPropertyNew::ChildByID(u32 ID) const
{
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (mChildren[ChildIdx]->mID == ID)
return mChildren[ChildIdx];
}
return nullptr;
}
IPropertyNew* IPropertyNew::ChildByIDString(const TIDString& rkIdString)
{
// String must contain at least one ID!
// some ID strings are formatted with 8 characters and some with 2 (plus the beginning "0x")
ASSERT(rkIdString.Size() >= 4);
u32 IDEndPos = rkIdString.IndexOf(':');
u32 NextChildID = -1;
if (IDEndPos == -1)
NextChildID = rkIdString.ToInt32();
else
NextChildID = rkIdString.SubString(2, IDEndPos - 2).ToInt32();
if (NextChildID == 0xFFFFFFFF)
{
return nullptr;
}
IPropertyNew* pNextChild = ChildByID(NextChildID);
// Check if we need to recurse
if (IDEndPos != -1)
{
return pNextChild->ChildByIDString(rkIdString.ChopFront(IDEndPos + 1));
}
else
{
return pNextChild;
}
}
bool IPropertyNew::ShouldCook(void*pPropertyData) const
{
switch (mCookPreference)
{
case ECookPreferenceNew::Always:
return true;
case ECookPreferenceNew::Never:
return false;
default:
return (Game() < eReturns ? true : !MatchesDefault(pPropertyData));
}
}
void IPropertyNew::SetName(const TString& rkNewName)
{
mName = rkNewName;
mFlags.ClearFlag(EPropertyFlag::HasCachedNameCheck);
}
void IPropertyNew::SetDescription(const TString& rkNewDescription)
{
mDescription = rkNewDescription;
}
void IPropertyNew::SetSuffix(const TString& rkNewSuffix)
{
mSuffix = rkNewSuffix;
}
bool IPropertyNew::HasAccurateName()
{
if (!mFlags.HasFlag(EPropertyFlag::HasCachedNameCheck))
{
CCRC32 Hash;
Hash.Hash(*mName);
Hash.Hash(HashableTypeName());
u32 GeneratedID = Hash.Digest();
if (GeneratedID == mID)
mFlags.SetFlag( EPropertyFlag::HasCorrectPropertyName );
else
mFlags.ClearFlag( EPropertyFlag::HasCorrectPropertyName );
mFlags.SetFlag(EPropertyFlag::HasCachedNameCheck);
}
return mFlags.HasFlag( EPropertyFlag::HasCorrectPropertyName );
}
/** IPropertyNew Accessors */
EGame IPropertyNew::Game() const
{
return mpMasterTemplate->Game();
}
IPropertyNew* IPropertyNew::Create(EPropertyTypeNew Type,
IPropertyNew* pParent,
CMasterTemplate* pMaster,
CScriptTemplate* pScript,
bool CallPostInit /*= true*/)
{
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->mpMasterTemplate = pMaster;
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();
}
return pOut;
}
IPropertyNew* IPropertyNew::CreateCopy(IPropertyNew* pArchetype,
IPropertyNew* pParent,
bool CallPostInit /*= true*/)
{
// 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->mpMasterTemplate, pParent->mpScriptTemplate, false);
pOut->InitFromArchetype(pArchetype);
pArchetype->mSubInstances.push_back(pOut);
if (CallPostInit)
{
pOut->PostInitialize();
}
return pOut;
}

View File

@ -0,0 +1,432 @@
#ifndef IPROPERTYNEW_H
#define IPROPERTYNEW_H
#include "Core/Resource/Animation/CAnimationParameters.h"
#include <Common/Common.h>
#include <Math/CVector3f.h>
#include <Math/MathUtil.h>
#include <memory>
/** Forward declares */
class CMasterTemplate;
class CScriptTemplate;
class CStructPropertyNew;
/** Typedefs */
typedef TString TIDString;
/** Property flags */
enum class EPropertyFlag : u32
{
/** Property is an archetype (a template for other properties to copy from) */
IsArchetype = 0x1,
/** Property is an array archetype (a template for elements of an array property) */
IsArrayArchetype = 0x2,
/** This property and all its children are a single unit and do not have individual property IDs, sizes, etc. */
IsAtomic = 0x4,
/** We have cached whether the property name is correct */
HasCachedNameCheck = 0x40000000,
/** The name of the property is a match for the property ID hash */
HasCorrectPropertyName = 0x80000000,
/** Flags that are left intact when copying from an archetype */
ArchetypeCopyFlags = EPropertyFlag::IsAtomic,
/** Flags that are inheritable from parent */
InheritableFlags = EPropertyFlag::IsArchetype | EPropertyFlag::IsArrayArchetype | EPropertyFlag::IsAtomic,
};
DECLARE_FLAGS_ENUMCLASS(EPropertyFlag, FPropertyFlags)
/** Property type */
enum class EPropertyTypeNew
{
Bool = FOURCC('BOOL'),
Byte = FOURCC('BYTE'),
Short = FOURCC('SHRT'),
Int = FOURCC('INT '),
Float = FOURCC('REAL'),
Choice = FOURCC('CHOI'),
Enum = FOURCC('ENUM'),
Flags = FOURCC('FLAG'),
String = FOURCC('STRG'),
Vector = FOURCC('VECT'),
Color = FOURCC('COLR'),
Asset = FOURCC('ASST'),
Sound = FOURCC('SOND'),
Animation = FOURCC('ANIM'),
AnimationSet = FOURCC('ANMS'),
Sequence = FOURCC('SQNC'),
Spline = FOURCC('SPLN'),
Guid = FOURCC('GUID'),
Pointer = FOURCC('PNTR'),
Struct = FOURCC('STRC'),
Array = FOURCC('ARRY'),
Invalid = FOURCC('INVD')
};
inline void Serialize(IArchive& rArc, EPropertyTypeNew& rType)
{
rArc.SerializePrimitive( (CFourCC&) rType );
}
inline const char* PropEnumToHashableTypeName(EPropertyTypeNew Type)
{
switch (Type)
{
case EPropertyTypeNew::Bool: return "bool";
case EPropertyTypeNew::Int: return "int";
case EPropertyTypeNew::Float: return "float";
case EPropertyTypeNew::Choice: return "choice";
case EPropertyTypeNew::Enum: return "enum";
case EPropertyTypeNew::Flags: return "Flags";
case EPropertyTypeNew::String: return "string";
case EPropertyTypeNew::Vector: return "Vector";
case EPropertyTypeNew::Color: return "Color";
case EPropertyTypeNew::Asset: return "asset";
case EPropertyTypeNew::Sound: return "sound";
case EPropertyTypeNew::Spline: return "spline";
case EPropertyTypeNew::Guid: return "guid";
default: return "";
}
}
/** Enum that describes when/how properties should be cooked out */
enum class ECookPreferenceNew
{
Default,
Always,
Never
};
inline void Serialize(IArchive& rArc, ECookPreferenceNew& rPref)
{
rArc.SerializePrimitive( (u32&) rPref );
}
/** New property class */
class IPropertyNew
{
friend class CTemplateLoader;
friend class CPropertyFactory;
protected:
/** Flags */
FPropertyFlags mFlags;
/** Parent property */
IPropertyNew* mpParent;
/** Pointer parent; if non-null, this parent needs to be dereferenced to access the correct
* memory region that our property data is stored in */
IPropertyNew* mpPointerParent;
/** 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? */
std::vector<IPropertyNew*> mSubInstances;
/** Child properties; these appear underneath this property on the UI */
std::vector<IPropertyNew*> mChildren;
/** Master template for the game this property belongs to.
* Cannot be derived from mpScriptTemplate because mpScriptTemplate is null sometimes */
CMasterTemplate* mpMasterTemplate;
/** Script template that this property belongs to. Null for struct/enum/flag archetypes. */
CScriptTemplate* mpScriptTemplate;
/** Offset of this property within the property block */
u32 mOffset;
/** Property ID. This ID is used to uniquely identify this property within this struct. */
u32 mID;
/** Property metadata */
TString mName;
TString mDescription;
TString mSuffix;
ECookPreferenceNew mCookPreference;
/** Min/max allowed version number. These numbers correspond to the game's internal build number.
* This is not used yet but in the future it can be used to configure certain properties to only
* show up when certain versions of the game are being edited. The default values allow the
* property to show up in all versions. */
float mMinVersion;
float mMaxVersion;
/** Private constructor - use static methods to instantiate */
IPropertyNew();
void _CalcOffset();
u32 _GetOffset() const;
void _ClearChildren();
/** Called after property is created and fully initialized */
virtual void PostInitialize() {}
public:
virtual ~IPropertyNew();
/** Interface */
virtual EPropertyTypeNew Type() const = 0;
virtual u32 DataSize() const = 0;
virtual u32 DataAlignment() const = 0;
virtual void Construct(void* pData) const = 0;
virtual void Destruct(void* pData) const = 0;
virtual bool MatchesDefault(void* pData) const = 0;
virtual void RevertToDefault(void* pData) const = 0;
virtual void SerializeValue(void* pData, IArchive& Arc) const = 0;
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;
#if 0
virtual void Serialize(IArchive& rArc);
#endif
virtual void InitFromArchetype(IPropertyNew* pOther);
virtual TString GetTemplateFileName();
/** Utility methods */
void* RawValuePtr(void* pData) const;
IPropertyNew* ChildByID(u32 ID) const;
IPropertyNew* ChildByIDString(const TIDString& rkIdString);
bool ShouldCook(void* pPropertyData) const;
void SetName(const TString& rkNewName);
void SetDescription(const TString& rkNewDescription);
void SetSuffix(const TString& rkNewSuffix);
bool HasAccurateName();
/** Accessors */
EGame Game() const;
inline ECookPreferenceNew CookPreference() const;
inline u32 NumChildren() const;
inline IPropertyNew* ChildByIndex(u32 ChildIndex) const;
inline IPropertyNew* Parent() const;
inline IPropertyNew* RootParent();
inline IPropertyNew* Archetype() const;
inline CScriptTemplate* ScriptTemplate() const;
inline CMasterTemplate* MasterTemplate() const;
inline TString Name() const;
inline TString Description() const;
inline TString Suffix() const;
inline TIDString IDString(bool FullyQualified) const;
inline u32 ID() const;
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); }
/** Create */
static IPropertyNew* Create(EPropertyTypeNew Type,
IPropertyNew* pParent,
CMasterTemplate* pMaster,
CScriptTemplate* pScript,
bool CallPostInit = true);
static IPropertyNew* CreateCopy(IPropertyNew* pArchetype,
IPropertyNew* pParent,
bool CallPostInit = true);
};
inline ECookPreferenceNew IPropertyNew::CookPreference() const
{
return mCookPreference;
}
inline u32 IPropertyNew::NumChildren() const
{
return mChildren.size();
}
inline IPropertyNew* IPropertyNew::ChildByIndex(u32 ChildIndex) const
{
ASSERT(ChildIndex >= 0 && ChildIndex < mChildren.size());
return mChildren[ChildIndex];
}
inline IPropertyNew* IPropertyNew::Parent() const
{
return mpParent;
}
inline IPropertyNew* IPropertyNew::RootParent()
{
IPropertyNew* pParent = Parent();
IPropertyNew* pOut = this;
while (pParent)
{
pOut = pParent;
pParent = pParent->Parent();
}
return pOut;
}
inline IPropertyNew* IPropertyNew::Archetype() const
{
return mpArchetype;
}
inline CScriptTemplate* IPropertyNew::ScriptTemplate() const
{
return mpScriptTemplate;
}
inline CMasterTemplate* IPropertyNew::MasterTemplate() const
{
return mpMasterTemplate;
}
inline TString IPropertyNew::Name() const
{
return mName;
}
inline TString IPropertyNew::Description() const
{
return mDescription;
}
inline TString IPropertyNew::Suffix() const
{
return mSuffix;
}
inline TString IPropertyNew::IDString(bool FullyQualified) const
{
if (FullyQualified && mpParent != nullptr)
return mpParent->IDString(FullyQualified) + ":" + TString::HexString(mID);
else
return TString::HexString(mID);
}
inline u32 IPropertyNew::ID() const
{
return mID;
}
template<typename PropType, EPropertyTypeNew PropEnum>
class TTypedPropertyNew : public IPropertyNew
{
friend class IPropertyNew;
friend class CTemplateLoader;
public:
typedef PropType ValueType;
protected:
PropType mDefaultValue;
TTypedPropertyNew()
: IPropertyNew()
{
memset(&mDefaultValue, 0, sizeof(PropType));
}
public:
virtual EPropertyTypeNew 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); }
virtual void Destruct(void* pData) const { ValueRef(pData).~PropType(); }
virtual bool MatchesDefault(void* pData) const { return ValueRef(pData) == mDefaultValue; }
virtual void RevertToDefault(void* pData) const { ValueRef(pData) = mDefaultValue; }
virtual bool CanHaveDefault() const { return true; }
#if 0
virtual void Serialize(IArchive& rArc)
{
IPropertyNew::Serialize(rArc);
rArc << SERIAL("DefaultValue", mDefaultValue);
}
#endif
virtual void InitFromArchetype(IPropertyNew* pOther)
{
IPropertyNew::InitFromArchetype(pOther);
mDefaultValue = static_cast<TTypedPropertyNew*>(pOther)->mDefaultValue;
}
inline PropType* ValuePtr(void* pData) const
{
return (PropType*) RawValuePtr(pData);
}
inline PropType& ValueRef(void* pData) const
{
return *ValuePtr(pData);
}
inline PropType Value(void* pData) const
{
return *ValuePtr(pData);
}
inline static EPropertyTypeNew StaticType() { return PropEnum; }
};
template<typename PropType, EPropertyTypeNew PropEnum>
class TNumericalPropertyNew : public TTypedPropertyNew<PropType, PropEnum>
{
friend class IPropertyNew;
friend class CTemplateLoader;
protected:
PropType mMinValue;
PropType mMaxValue;
TNumericalPropertyNew()
: TTypedPropertyNew()
, mMinValue( -1 )
, mMaxValue( -1 )
{}
public:
#if 0
virtual void Serialize(IArchive& rArc)
{
TTypedPropertyNew::Serialize(rArc);
rArc << SERIAL("Min", mMin)
<< SERIAL("Max", mMax);
}
#endif
virtual void InitFromArchetype(IPropertyNew* pOther)
{
TTypedPropertyNew::InitFromArchetype(pOther);
TNumericalPropertyNew* pCastOther = static_cast<TNumericalPropertyNew*>(pOther);
mMinValue = pCastOther->mMinValue;
mMaxValue = pCastOther->mMaxValue;
}
virtual void PropertyValueChanged(void* pPropertyData)
{
IPropertyNew::PropertyValueChanged(pPropertyData);
if (mMinValue >= 0 && mMaxValue >= 0)
{
PropType& rValue = ValueRef(pPropertyData);
rValue = Math::Clamp(mMinValue, mMaxValue, rValue);
}
}
};
/** Property casting with dynamic type checking */
template<class PropertyClass>
inline PropertyClass* TPropCast(IPropertyNew* pProperty)
{
if (pProperty && pProperty->Type() == PropertyClass::StaticType())
{
return static_cast<PropertyClass*>(pProperty);
}
else
{
return nullptr;
}
}
#endif // IPROPERTYNEW_H

View File

@ -3,6 +3,7 @@
#include <Common/Hash/CCRC32.h>
#include <iostream>
#if 0
// ************ IPropertyTemplate ************
EGame IPropertyTemplate::Game() const
{
@ -250,75 +251,73 @@ void CStructTemplate::DetermineVersionPropertyCounts()
}
}
}
#endif
// ************ GLOBAL FUNCTIONS ************
TString PropEnumToPropString(EPropertyType Prop)
TString PropEnumToPropString(EPropertyTypeNew Prop)
{
switch (Prop)
{
case eBoolProperty: return "bool";
case eByteProperty: return "byte";
case eShortProperty: return "short";
case eLongProperty: return "long";
case eEnumProperty: return "enum";
case eBitfieldProperty: return "bitfield";
case eFloatProperty: return "float";
case eStringProperty: return "string";
case eColorProperty: return "color";
case eVector3Property: return "vector3f";
case eSoundProperty: return "sound";
case eAssetProperty: return "asset";
case eStructProperty: return "struct";
case eArrayProperty: return "array";
case eCharacterProperty: return "character";
case eMayaSplineProperty: return "MayaSpline";
case eUnknownProperty: return "unknown";
case EPropertyTypeNew::Bool: return "bool";
case EPropertyTypeNew::Byte: return "byte";
case EPropertyTypeNew::Short: return "short";
case EPropertyTypeNew::Int: return "long";
case EPropertyTypeNew::Enum: return "enum";
case EPropertyTypeNew::Flags: return "bitfield";
case EPropertyTypeNew::Float: return "float";
case EPropertyTypeNew::String: return "string";
case EPropertyTypeNew::Color: return "color";
case EPropertyTypeNew::Vector: return "vector3f";
case EPropertyTypeNew::Sound: return "sound";
case EPropertyTypeNew::Asset: return "asset";
case EPropertyTypeNew::Struct: return "struct";
case EPropertyTypeNew::Array: return "array";
case EPropertyTypeNew::AnimationSet: return "character";
case EPropertyTypeNew::Spline: return "MayaSpline";
case eInvalidProperty:
default:
return "invalid";
}
}
EPropertyType PropStringToPropEnum(TString Prop)
EPropertyTypeNew PropStringToPropEnum(TString Prop)
{
Prop = Prop.ToLower();
if (Prop == "bool") return eBoolProperty;
if (Prop == "byte") return eByteProperty;
if (Prop == "short") return eShortProperty;
if (Prop == "long") return eLongProperty;
if (Prop == "enum") return eEnumProperty;
if (Prop == "bitfield") return eBitfieldProperty;
if (Prop == "float") return eFloatProperty;
if (Prop == "string") return eStringProperty;
if (Prop == "color") return eColorProperty;
if (Prop == "vector3f") return eVector3Property;
if (Prop == "sound") return eSoundProperty;
if (Prop == "asset") return eAssetProperty;
if (Prop == "struct") return eStructProperty;
if (Prop == "array") return eArrayProperty;
if (Prop == "character") return eCharacterProperty;
if (Prop == "mayaspline") return eMayaSplineProperty;
if (Prop == "unknown") return eUnknownProperty;
return eInvalidProperty;
if (Prop == "bool") return EPropertyTypeNew::Bool;
if (Prop == "byte") return EPropertyTypeNew::Byte;
if (Prop == "short") return EPropertyTypeNew::Short;
if (Prop == "long") return EPropertyTypeNew::Int;
if (Prop == "enum") return EPropertyTypeNew::Enum;
if (Prop == "bitfield") return EPropertyTypeNew::Flags;
if (Prop == "float") return EPropertyTypeNew::Float;
if (Prop == "string") return EPropertyTypeNew::String;
if (Prop == "color") return EPropertyTypeNew::Color;
if (Prop == "vector3f") return EPropertyTypeNew::Vector;
if (Prop == "sound") return EPropertyTypeNew::Sound;
if (Prop == "asset") return EPropertyTypeNew::Asset;
if (Prop == "struct") return EPropertyTypeNew::Struct;
if (Prop == "array") return EPropertyTypeNew::Array;
if (Prop == "character") return EPropertyTypeNew::AnimationSet;
if (Prop == "mayaspline") return EPropertyTypeNew::Spline;
return EPropertyTypeNew::Invalid;
}
const char* HashablePropTypeName(EPropertyType Prop)
const char* HashablePropTypeName(EPropertyTypeNew Prop)
{
// Variants that match Retro's internal type names for generating property IDs. case sensitive
switch (Prop)
{
case eBoolProperty: return "bool";
case eLongProperty: return "int";
case eEnumProperty: return "enum";
case eBitfieldProperty: return "Flags";
case eFloatProperty: return "float";
case eStringProperty: return "string";
case eColorProperty: return "Color";
case eVector3Property: return "Vector";
case eSoundProperty: return "sound";
case eAssetProperty: return "asset";
case eMayaSplineProperty: return "spline";
case EPropertyTypeNew::Bool: return "bool";
case EPropertyTypeNew::Int: return "int";
case EPropertyTypeNew::Enum: return "enum";
case EPropertyTypeNew::Flags: return "Flags";
case EPropertyTypeNew::Float: return "float";
case EPropertyTypeNew::String: return "string";
case EPropertyTypeNew::Color: return "Color";
case EPropertyTypeNew::Vector: return "Vector";
case EPropertyTypeNew::Sound: return "sound";
case EPropertyTypeNew::Asset: return "asset";
case EPropertyTypeNew::Spline: return "spline";
// All other types are either invalid or need a custom reimplementation because they can return multiple strings (like struct)
default:
@ -327,6 +326,7 @@ const char* HashablePropTypeName(EPropertyType Prop)
}
}
#if 0
// ************ DEBUG ************
void CStructTemplate::DebugPrintProperties(TString base)
{
@ -343,3 +343,4 @@ void CStructTemplate::DebugPrintProperties(TString base)
Log::Write(base + tmp->Name());
}
}
#endif

View File

@ -1,6 +1,7 @@
#ifndef IPROPERTYTEMPLATE
#define IPROPERTYTEMPLATE
#if 0
#include "EPropertyType.h"
#include "IProperty.h"
#include "IPropertyValue.h"
@ -797,6 +798,7 @@ public:
return (CPropertyStruct*) CStructTemplate::InstantiateProperty(pInstance, pArray);
}
};
#endif
#endif // IPROPERTYTEMPLATE

View File

@ -1,6 +1,7 @@
#ifndef IPROPERTYVALUE_H
#define IPROPERTYVALUE_H
#if 0
#include "EPropertyType.h"
#include <Common/CAssetID.h>
#include <Common/Log.h>
@ -386,5 +387,6 @@ public:
return new CUnknownValue(mValue);
}
};
#endif
#endif // IPROPERTYVALUE_H

View File

@ -0,0 +1,27 @@
#ifndef CANIMATIONPROPERTY_H
#define CANIMATIONPROPERTY_H
#include "../IPropertyNew.h"
class CAnimationProperty : public TTypedPropertyNew< int, EPropertyTypeNew::Animation >
{
friend class IPropertyNew;
protected:
CAnimationProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& rArc) const
{
rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData) const
{
return TString::HexString( (u32) Value(pData) );
}
};
#endif // CANIMATIONPROPERTY_H

View File

@ -0,0 +1,22 @@
#ifndef CANIMATIONSETPROPERTY_H
#define CANIMATIONSETPROPERTY_H
#include "../IPropertyNew.h"
class CAnimationSetProperty : public TTypedPropertyNew< CAnimationParameters, EPropertyTypeNew::AnimationSet >
{
friend class IPropertyNew;
protected:
CAnimationSetProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Value(pData).Serialize(Arc);
}
};
#endif // CANIMATIONSETPROPERTY_H

View File

@ -0,0 +1,176 @@
#ifndef CARRAYPROPERTY_H
#define CARRAYPROPERTY_H
#include "../IPropertyNew.h"
struct SScriptArray
{
int Count;
std::vector<char> Array;
SScriptArray()
: Count(0)
{}
inline bool operator==(const SScriptArray& rkOther) const
{
return( Count == rkOther.Count && Array == rkOther.Array );
}
};
/** You probably shouldn't use this on intrinsic classes; script only */
/** @todo proper support of default values for arrays (this would be used for prefabs) */
class CArrayProperty : public TTypedPropertyNew<int, EPropertyTypeNew::Array>
{
friend class CTemplateLoader;
/** This class inherits from TTypedPropertyNew<int> in order to expose the array
* count value. Outside users can edit this value and we respond by updating the
* allocated space, handling destruction/construction, etc.
*/
IPropertyNew* mpItemArchetype;
/** Internal functions */
SScriptArray& _GetInternalArray(void* pData) const
{
return *( (SScriptArray*) RawValuePtr(pData) );
}
u32 _InternalArrayCount(void* pPropertyData) const
{
std::vector<char>& rArray = _GetInternalArray(pPropertyData).Array;
return rArray.size() / ItemSize();
}
public:
virtual u32 DataSize() const
{
return sizeof(SScriptArray);
}
virtual u32 DataAlignment() const
{
return alignof(SScriptArray);
}
virtual void Construct(void* pData) const
{
new(ValuePtr(pData)) SScriptArray;
}
virtual void Destruct(void* pData) const
{
RevertToDefault(pData);
TTypedPropertyNew::Destruct(pData);
}
virtual bool MatchesDefault(void* pData) const
{
return ArrayCount(pData) == 0;
}
virtual void RevertToDefault(void* pData) const
{
Resize(pData, 0);
ValueRef(pData) = 0;
}
virtual bool CanHaveDefault() const
{
return true;
}
virtual bool IsPointerType() const
{
return true;
}
virtual void* GetChildDataPointer(void* pPropertyData) const
{
return _GetInternalArray(pPropertyData).Array.data();
}
virtual void PropertyValueChanged(void* pPropertyData)
{
SScriptArray& rArray = _GetInternalArray(pPropertyData);
rArray.Count = Math::Max(rArray.Count, 0);
Resize(pPropertyData, rArray.Count);
}
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
u32 Count = ArrayCount(pData);
Arc.SerializePrimitive(Count);
if (Arc.IsReader())
Resize(pData, Count);
for (u32 ItemIdx = 0; ItemIdx < Count; ItemIdx++)
{
if (Arc.ParamBegin("ArrayElement"))
{
void* pItemData = ItemPointer(pData, ItemIdx);
mpArchetype->SerializeValue(pItemData, Arc);
Arc.ParamEnd();
}
}
}
u32 ArrayCount(void* pPropertyData) const
{
return ValueRef(pPropertyData);
}
void Resize(void* pPropertyData, u32 NewCount) const
{
u32 OldCount = _InternalArrayCount(pPropertyData);
if (OldCount != NewCount)
{
SScriptArray& rArray = _GetInternalArray(pPropertyData);
// Handle destruction of old elements
if (OldCount > NewCount)
{
for (u32 ItemIdx = NewCount; ItemIdx < OldCount; ItemIdx++)
{
void* pItemPtr = ItemPointer(pPropertyData, ItemIdx);
mpItemArchetype->Destruct(pItemPtr);
}
}
u32 NewSize = NewCount * ItemSize();
rArray.Array.resize(NewSize);
// Handle construction of new elements
if (NewCount > OldCount)
{
for (u32 ItemIdx = OldCount; ItemIdx < NewCount; ItemIdx++)
{
void* pItemPtr = ItemPointer(pPropertyData, ItemIdx);
mpItemArchetype->Construct(pItemPtr);
}
}
}
}
void* ItemPointer(void* pPropertyData, u32 ItemIndex) const
{
ASSERT(ArrayCount(pPropertyData) > ItemIndex);
std::vector<char>& rArray = _GetInternalArray(pPropertyData).Array;
u32 MyItemSize = ItemSize();
ASSERT(rArray.size() >= (MyItemSize * (ItemIndex+1)));
return rArray.data() + (MyItemSize * ItemIndex);
}
u32 ItemSize() const
{
u32 ItemAlign = mpItemArchetype->DataAlignment();
u32 ItemSize = ALIGN(mpItemArchetype->DataSize(), ItemAlign);
return ItemSize;
}
/** Accessors */
IPropertyNew* ArchetypeProperty() const { return mpArchetype; }
};
#endif // CARRAYPROPERTY_H

View File

@ -0,0 +1,42 @@
#ifndef CASSETPROPERTY_H
#define CASSETPROPERTY_H
#include "../IPropertyNew.h"
#include "Core/Resource/CResTypeFilter.h"
class CAssetProperty : public TTypedPropertyNew<CAssetID, EPropertyTypeNew::Asset>
{
friend class CTemplateLoader;
CResTypeFilter mTypeFilter;
public:
#if 0
virtual void Serialize(IArchive& rArc)
{
TTypedPropertyNew::Serialize(rArc);
rArc << SERIAL("AcceptedTypes", mTypeFilter);
}
#endif
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( ValueRef(pData) );
}
virtual TString ValueAsString(void* pData) const
{
return Value(pData).ToString();
}
void SetTypeFilter(const TStringList& rkExtensions)
{
mTypeFilter.SetAcceptedTypes(Game(), rkExtensions);
}
const CResTypeFilter& GetTypeFilter() const
{
return mTypeFilter;
}
};
#endif // CASSETPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CBOOLPROPERTY_H
#define CBOOLPROPERTY_H
#include "../IPropertyNew.h"
class CBoolProperty : public TTypedPropertyNew< bool, EPropertyTypeNew::Bool >
{
friend class IPropertyNew;
protected:
CBoolProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return Value(pData) ? "true" : "false";
}
};
#endif // CBOOLPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CBYTEPROPERTY_H
#define CBYTEPROPERTY_H
#include "../IPropertyNew.h"
class CByteProperty : public TNumericalPropertyNew< char, EPropertyTypeNew::Byte >
{
friend class IPropertyNew;
protected:
CByteProperty()
: TNumericalPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (u8&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return TString::FromInt32( (s32) Value(pData), 0, 10 );
}
};
#endif // CBYTEPROPERTY_H

View File

@ -0,0 +1,34 @@
#ifndef CCOLORPROPERTY_H
#define CCOLORPROPERTY_H
#include "../IPropertyNew.h"
class CColorProperty : public TTypedPropertyNew< CColor, EPropertyTypeNew::Color >
{
friend class IPropertyNew;
protected:
CColorProperty()
: TTypedPropertyNew()
{}
public:
virtual void PostInitialize()
{
IPropertyNew* pR = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
IPropertyNew* pG = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
IPropertyNew* pB = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
IPropertyNew* pA = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
pR->SetName("R");
pG->SetName("G");
pB->SetName("B");
pA->SetName("A");
}
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Value(pData).Serialize(Arc);
}
};
#endif // CVECTORPROPERTY_H

View File

@ -0,0 +1,124 @@
#ifndef CENUMPROPERTY_H
#define CENUMPROPERTY_H
#include "../IPropertyNew.h"
/** There are two types of enum properties: in the game data enum and choice.
*
* In the game, the difference is that choice properties are index-based, while
* enum properties are stored as a hash of the name of the enum.
*
* In PWE, however, they are both implemented the same way under the hood.
*/
template<EPropertyTypeNew TypeEnum>
class TEnumPropertyBase : public TTypedPropertyNew<int, TypeEnum>
{
friend class CTemplateLoader;
struct SEnumValue
{
TString Name;
u32 ID;
SEnumValue(const TString& rkInName, u32 InID)
: Name(rkInName), ID(InID) {}
inline bool operator==(const SEnumValue& rkOther) const
{
return( Name == rkOther.Name && ID == rkOther.ID );
}
};
std::vector<SEnumValue> mValues;
/** XML template file that this enum originated from; for archetypes */
TString mSourceFile;
public:
virtual const char* GetHashableTypeName() const
{
if (TypeEnum == EPropertyTypeNew::Enum)
return "enum";
else
return "choice";
}
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (u32&) ValueRef(pData) );
}
virtual TString GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mSourceFile : mpArchetype->GetTemplateFileName();
}
inline u32 NumPossibleValues() const { return mValues.size(); }
u32 ValueIndex(u32 ID) const
{
for (u32 ValueIdx = 0; ValueIdx < mValues.size(); ValueIdx++)
{
if (mValues[ValueIdx].ID == ID)
{
return ValueIdx;
}
}
return -1;
}
u32 ValueID(u32 Index) const
{
ASSERT(Index >= 0 && Index < mValues.size());
return mValues[Index].ID;
}
TString ValueName(u32 Index) const
{
ASSERT(Index >= 0 && Index < mValues.size());
return mValues[Index].Name;
}
bool HasValidValue(void* pPropertyData)
{
int ID = ValueRef(pPropertyData);
u32 Index = ValueIndex(ID);
return Index >= 0 && Index < mValues.size();
}
};
typedef TEnumPropertyBase<EPropertyTypeNew::Choice> CChoiceProperty;
typedef TEnumPropertyBase<EPropertyTypeNew::Enum> CEnumProperty;
// Specialization of TPropCast to allow interchangeable casting, as both types are the same thing
template<>
inline CEnumProperty* TPropCast(IPropertyNew* pProperty)
{
EPropertyTypeNew InType = pProperty->Type();
if (InType == EPropertyTypeNew::Enum || InType == EPropertyTypeNew::Choice)
{
return static_cast<CEnumProperty*>(pProperty);
}
else
{
return nullptr;
}
}
template<>
inline CChoiceProperty* TPropCast(IPropertyNew* pProperty)
{
if (pProperty)
{
EPropertyTypeNew InType = pProperty->Type();
if (InType == EPropertyTypeNew::Enum || InType == EPropertyTypeNew::Choice)
{
return static_cast<CChoiceProperty*>(pProperty);
}
}
return nullptr;
}
#endif // CENUMPROPERTY_H

View File

@ -0,0 +1,99 @@
#ifndef CFLAGSPROPERTY_H
#define CFLAGSPROPERTY_H
#include "../IPropertyNew.h"
class CFlagsProperty : public TTypedPropertyNew<int, EPropertyTypeNew::Flags>
{
friend class CTemplateLoader;
friend class IPropertyNew;
struct SBitFlag
{
TString Name;
u32 Mask;
SBitFlag(const TString& rkInName, u32 InMask)
: Name(rkInName), Mask(InMask)
{}
bool operator==(const SBitFlag& rkOther) const
{
return( Name == rkOther.Name && Mask == rkOther.Mask );
}
#if 0
void Serialize(IArchive& rArc)
{
rArc << SERIAL("FlagName", Name)
<< SERIAL_HEX("FlagMask", Mask);
}
#endif
};
std::vector<SBitFlag> mBitFlags;
u32 mAllFlags;
/** XML template file that this enum originated from; for archetypes */
TString mSourceFile;
CFlagsProperty()
: TTypedPropertyNew()
, mAllFlags(0)
{}
public:
inline u32 NumFlags() const
{
return mBitFlags.size();
}
inline TString FlagName(u32 Idx) const
{
ASSERT(Idx >= 0 && Idx < mBitFlags.size());
return mBitFlags[Idx].Name;
}
inline u32 FlagMask(u32 Idx) const
{
ASSERT(Idx >= 0 && Idx < mBitFlags.size());
return mBitFlags[Idx].Mask;
}
#if 0
virtual void Serialize(IArchive& rArc)
{
TTypedPropertyNew::Serialize(rArc);
rArc << SERIAL_CONTAINER("Flags", mFlags, "Flag");
// Initialize the "all flags" cache
if (rArc.IsReader())
{
mAllFlags = 0;
for (u32 FlagIdx = 0; FlagIdx < mFlags.size(); FlagIdx++)
mAllFlags |= mFlags[FlagIdx].Mask;
}
}
#endif
virtual void SerializeValue(void* pData, IArchive& rArc) const
{
rArc.SerializeHexPrimitive( (u32&) ValueRef(pData) );
}
virtual TString GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mSourceFile : mpArchetype->GetTemplateFileName();
}
/**
* Checks whether there are any unrecognized bits toggled on in the property value.
* Returns the mask of any invalid bits. If all bits are valid, returns 0.
*/
u32 HasValidValue(void* pPropertyData)
{
return ValueRef(pPropertyData) & ~mAllFlags;
}
};
#endif // CFLAGSPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CFLOATPROPERTY_H
#define CFLOATPROPERTY_H
#include "../IPropertyNew.h"
class CFloatProperty : public TNumericalPropertyNew< float, EPropertyTypeNew::Float >
{
friend class IPropertyNew;
protected:
CFloatProperty()
: TNumericalPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (float&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return TString::FromFloat( Value(pData) );
}
};
#endif // CFLOATPROPERTY_H

View File

@ -0,0 +1,22 @@
#ifndef CGUIDPROPERTY_H
#define CGUIDPROPERTY_H
#include "../IPropertyNew.h"
class CGuidProperty : public TTypedPropertyNew< std::vector<char>, EPropertyTypeNew::Guid >
{
friend class IPropertyNew;
protected:
CGuidProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializeBulkData( ValueRef(pData) );
}
};
#endif // CSPLINEPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CINTPROPERTY_H
#define CINTPROPERTY_H
#include "../IPropertyNew.h"
class CIntProperty : public TNumericalPropertyNew< int, EPropertyTypeNew::Int >
{
friend class IPropertyNew;
protected:
CIntProperty()
: TNumericalPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (u32&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return TString::FromInt32( Value(pData), 0, 10 );
}
};
#endif // CINTPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CPOINTERPROPERTY_H
#define CPOINTERPROPERTY_H
#include "../IPropertyNew.h"
class CPointerProperty : public TTypedPropertyNew<void*, EPropertyTypeNew::Pointer>
{
friend class CTemplateLoader;
public:
virtual bool IsPointerType() const
{
return true;
}
virtual void* GetChildDataPointer(void* pPropertyData) const
{
return ValueRef(pPropertyData);
}
virtual void SerializeValue(void* pData, IArchive& rArc) const
{
// pointers are not serializable, this shouldn't happen
ASSERT(false);
}
};
#endif // CPOINTERPROPERTY_H

View File

@ -0,0 +1,19 @@
#ifndef CSEQUENCEPROPERTY_H
#define CSEQUENCEPROPERTY_H
#include "../IPropertyNew.h"
class CSequenceProperty : public TTypedPropertyNew< int, EPropertyTypeNew::Sequence >
{
friend class IPropertyNew;
protected:
CSequenceProperty()
: TTypedPropertyNew()
{}
virtual void SerializeValue(void* pData, IArchive& rArc) const
{}
};
#endif // CSEQUENCEPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CSHORTPROPERTY_H
#define CSHORTPROPERTY_H
#include "../IPropertyNew.h"
class CShortProperty : public TNumericalPropertyNew< short, EPropertyTypeNew::Short >
{
friend class IPropertyNew;
protected:
CShortProperty()
: TNumericalPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (u16&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return TString::FromInt32( (s32) Value(pData), 0, 10 );
}
};
#endif // CSHORTPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CSOUNDPROPERTY_H
#define CSOUNDPROPERTY_H
#include "../IPropertyNew.h"
class CSoundProperty : public TTypedPropertyNew< int, EPropertyTypeNew::Sound >
{
friend class IPropertyNew;
protected:
CSoundProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( (u32&) ValueRef(pData) );
}
virtual TString ValueAsString(void* pData)
{
return TString::FromInt32( Value(pData), 0, 10 );
}
};
#endif // CSOUNDPROPERTY_H

View File

@ -0,0 +1,22 @@
#ifndef CSPLINEPROPERTY_H
#define CSPLINEPROPERTY_H
#include "../IPropertyNew.h"
class CSplineProperty : public TTypedPropertyNew< std::vector<char>, EPropertyTypeNew::Spline >
{
friend class IPropertyNew;
protected:
CSplineProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializeBulkData( ValueRef(pData) );
}
};
#endif // CSPLINEPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef CSTRINGPROPERTY_H
#define CSTRINGPROPERTY_H
#include "../IPropertyNew.h"
class CStringProperty : public TTypedPropertyNew< TString, EPropertyTypeNew::String >
{
friend class IPropertyNew;
protected:
CStringProperty()
: TTypedPropertyNew()
{}
public:
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
Arc.SerializePrimitive( ValueRef(pData) );
}
virtual TString ValueAsString(void* pData) const
{
return Value(pData);
}
};
#endif // CSTRINGPROPERTY_H

View File

@ -0,0 +1,146 @@
#ifndef CSTRUCTPROPERTY_H
#define CSTRUCTPROPERTY_H
#include "../IPropertyNew.h"
class CStructPropertyNew : public IPropertyNew
{
friend class CTemplateLoader;
public:
// Must be a valid type for TPropertyRef
typedef void* ValueType;
protected:
/** For archetypes, the filename of the template XML file. */
TString mTemplateFileName;
public:
virtual EPropertyTypeNew Type() const
{
return EPropertyTypeNew::Struct;
}
virtual u32 DataSize() const
{
if (!mChildren.empty())
{
IPropertyNew* pLastChild = mChildren.back();
return _GetOffset() + pLastChild->DataSize();
}
else
{
return 0;
}
}
virtual u32 DataAlignment() const
{
return (mChildren.empty() ? 1 : mChildren[0]->DataAlignment());
}
virtual void Construct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Construct(pData);
}
}
virtual void Destruct(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->Destruct(pData);
}
}
virtual bool MatchesDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (!mChildren[ChildIdx]->MatchesDefault(pData))
{
return false;
}
}
return true;
}
virtual void RevertToDefault(void* pData) const
{
for (int ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
mChildren[ChildIdx]->RevertToDefault(pData);
}
}
virtual const char* HashableTypeName() const
{
ASSERT(IsArchetype() || mpArchetype != nullptr);
if (IsArchetype())
return *mName;
else
return *mpArchetype->Name();
}
#if 0
virtual void Serialize(IArchive& rArc)
{
IPropertyNew::Serialize(rArc);
if (rArc.ParamBegin("SubProperties"))
{
u32 NumChildren;
rArc.SerializeContainerSize(NumChildren, "Property");
if (rArc.IsReader())
{
mChildren.resize(NumChildren);
}
for (u32 ChildIdx = 0; ChildIdx < NumChildren; ChildIdx++)
{
if (rArc.ParamBegin("Property"))
{
EPropertyTypeNew Type = (rArc.IsWriter() ? mChildren[ChildIdx]->Type() : EPropertyTypeNew::Invalid);
rArc << SERIAL_AUTO(Type);
if (rArc.IsReader())
{
mChildren[ChildIdx] = Create(Type, this, mpMasterTemplate, mpScriptTemplate);
}
mChildren[ChildIdx]->Serialize(rArc);
rArc.ParamEnd();
}
}
rArc.ParamEnd();
}
}
#endif
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
for (u32 ChildIdx = 0; ChildIdx < mChildren.size(); ChildIdx++)
{
if (Arc.ParamBegin("Property"))
{
mChildren[ChildIdx]->SerializeValue(pData, Arc);
Arc.ParamEnd();
}
}
}
virtual TString GetTemplateFileName()
{
ASSERT(IsArchetype() || mpArchetype);
return IsArchetype() ? mTemplateFileName : mpArchetype->GetTemplateFileName();
}
inline static EPropertyTypeNew StaticType() { return EPropertyTypeNew::Struct; }
};
#endif

View File

@ -0,0 +1,37 @@
#ifndef CVECTORPROPERTY_H
#define CVECTORPROPERTY_H
#include "../IPropertyNew.h"
class CVectorProperty : public TTypedPropertyNew< CVector3f, EPropertyTypeNew::Vector >
{
friend class IPropertyNew;
protected:
CVectorProperty()
: TTypedPropertyNew()
{}
public:
virtual void PostInitialize()
{
IPropertyNew* pX = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
IPropertyNew* pY = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
IPropertyNew* pZ = Create(EPropertyTypeNew::Float, this, mpMasterTemplate, mpScriptTemplate);
pX->SetName("X");
pY->SetName("Y");
pZ->SetName("Z");
}
virtual void SerializeValue(void* pData, IArchive& Arc) const
{
ValueRef(pData).Serialize(Arc);
}
virtual TString ValueAsString(void* pData) const
{
return Value(pData).ToString();
}
};
#endif // CVECTORPROPERTY_H

View File

@ -0,0 +1,27 @@
#ifndef PROPERTIES_H
#define PROPERTIES_H
#include "../IPropertyNew.h"
#include "CAnimationProperty.h"
#include "CAnimationSetProperty.h"
#include "CArrayProperty.h"
#include "CAssetProperty.h"
#include "CBoolProperty.h"
#include "CByteProperty.h"
#include "CColorProperty.h"
#include "CEnumProperty.h"
#include "CFlagsProperty.h"
#include "CFloatProperty.h"
#include "CGuidProperty.h"
#include "CIntProperty.h"
#include "CPointerProperty.h"
#include "CSequenceProperty.h"
#include "CShortProperty.h"
#include "CSoundProperty.h"
#include "CSplineProperty.h"
#include "CStringProperty.h"
#include "CStructProperty.h"
#include "CVectorProperty.h"
#include "TPropertyRef.h"
#endif // PROPERTIES_H

View File

@ -0,0 +1,113 @@
#ifndef TPROPERTYREF_H
#define TPROPERTYREF_H
#include "CAnimationProperty.h"
#include "CAnimationSetProperty.h"
#include "CArrayProperty.h"
#include "CAssetProperty.h"
#include "CBoolProperty.h"
#include "CByteProperty.h"
#include "CColorProperty.h"
#include "CEnumProperty.h"
#include "CFlagsProperty.h"
#include "CFloatProperty.h"
#include "CGuidProperty.h"
#include "CIntProperty.h"
#include "CPointerProperty.h"
#include "CSequenceProperty.h"
#include "CShortProperty.h"
#include "CSoundProperty.h"
#include "CSplineProperty.h"
#include "CStringProperty.h"
#include "CStructProperty.h"
#include "CVectorProperty.h"
/** TPropertyRef: Embeds a reference to a property on a specific script object */
template<class PropertyClass, typename ValueType = PropertyClass::ValueType>
class TPropertyRef
{
/** Script object containing the property data being referenced */
CScriptObject* mpObject;
/** Property being referenced */
PropertyClass* mpProperty;
public:
TPropertyRef()
: mpObject(nullptr), mpProperty(nullptr)
{}
TPropertyRef(CScriptObject* pInObject, IPropertyNew* pInProperty)
: mpObject(pInObject), mpProperty( TPropCast<PropertyClass>(pInProperty) )
{
}
TPropertyRef(CScriptObject* pInObject, PropertyClass* pInProperty)
: mpObject(pInObject), mpProperty(pInProperty)
{
}
/** Accessors */
inline CScriptObject* Object() const { return mpObject; }
inline PropertyClass* Property() const { return mpProperty; }
inline ValueType Get() const { ASSERT(IsValid()); return *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )); }
inline void Set(const ValueType& kIn) const { if (IsValid()) *((ValueType*) mpProperty->RawValuePtr( mpObject->PropertyData() )) = kIn; }
inline bool IsValid() const { return mpObject != nullptr && mpProperty != nullptr; }
/** Inline operators */
inline operator ValueType() const
{
return Get();
}
inline bool operator==(IPropertyNew* pProperty) const
{
return mpProperty == pProperty;
}
friend bool operator==(IPropertyNew* pLeft, const TPropertyRef& kRight)
{
return pLeft == kRight.Property();
}
};
/** Convenience typedefs */
typedef TPropertyRef<CBoolProperty> CBoolRef;
typedef TPropertyRef<CByteProperty> CByteRef;
typedef TPropertyRef<CShortProperty> CShortRef;
typedef TPropertyRef<CIntProperty> CIntRef;
typedef TPropertyRef<CFloatProperty> CFloatRef;
typedef TPropertyRef<CFlagsProperty> CFlagsRef;
typedef TPropertyRef<CStringProperty> CStringRef;
typedef TPropertyRef<CVectorProperty> CVectorRef;
typedef TPropertyRef<CColorProperty> CColorRef;
typedef TPropertyRef<CAssetProperty> CAssetRef;
typedef TPropertyRef<CSoundProperty> CSoundRef;
typedef TPropertyRef<CAnimationProperty> CAnimationRef;
typedef TPropertyRef<CAnimationSetProperty> CAnimationSetRef;
typedef TPropertyRef<CSequenceProperty> CSequenceRef;
typedef TPropertyRef<CSplineProperty> CSplineRef;
typedef TPropertyRef<CGuidProperty> CGuidRef;
typedef TPropertyRef<CPointerProperty> CPointerRef;
typedef TPropertyRef<CStructPropertyNew> CStructRef;
typedef TPropertyRef<CArrayProperty> CArrayRef;
/** Special version for enums */
template<typename ValueType>
class TEnumRef : public TPropertyRef<CEnumProperty, ValueType>
{
public:
TEnumRef()
: TPropertyRef()
{}
TEnumRef(CScriptObject* pInObject, IPropertyNew* pInProperty)
: TPropertyRef(pInObject, pInProperty)
{}
TEnumRef(CScriptObject* pInObject, CEnumProperty* pInProperty)
: TPropertyRef(pInObject, pInProperty)
{}
};
#endif // TPROPERTYREF_H

View File

@ -0,0 +1,39 @@
#ifndef TPROPERTYPROXY_H
#define TPROPERTYPROXY_H
#include <type_traits>
/**
* Lightweight proxy class representing a property instance. Easy to read/modify
* specific properties and efficient to pass around.
*/
template<class PropertyClass>
class TPropertyProxy
{
typedef PropertyClass::ValueType ValueType;
/** Property data buffer */
void* mpDataPtr;
/** Source property */
PropertyClass* mpProperty;
public:
TPropertyProxy()
: mpDataPtr(nullptr)
, mpProperty(nullptr)
{}
TPropertyProxy(void* pDataPtr, PropertyClass* pProperty)
: mpDataPtr(pDataPtr)
, mpProperty(pProperty)
{}
/** Returns whether this proxy points to a valid property instance */
bool IsValid() const
{
return mpDataPtr != nullptr && mpProperty != nullptr;
}
};
#endif // TPROPERTYPROXY_H

View File

@ -10,8 +10,11 @@ CScriptAttachNode::CScriptAttachNode(CScene *pScene, const SAttachment& rkAttach
, mAttachType(rkAttachment.AttachType)
, mLocatorName(rkAttachment.LocatorName)
{
CPropertyStruct *pBaseStruct = pParent->Instance()->Properties();
mpAttachAssetProp = pBaseStruct->PropertyByIDString(rkAttachment.AttachProperty);
CStructPropertyNew* pBaseStruct = pParent->Template()->Properties();
mpAttachAssetProp = pBaseStruct->ChildByIDString(rkAttachment.AttachProperty);
mAttachAssetRef = CAssetRef(pParent->Instance(), mpAttachAssetProp);
mAttachAnimSetRef = CAnimationSetRef(pParent->Instance(), mpAttachAssetProp);
if (mpAttachAssetProp) AttachPropertyModified();
ParentDisplayAssetChanged(mpScriptNode->DisplayAsset());
@ -21,12 +24,12 @@ void CScriptAttachNode::AttachPropertyModified()
{
if (mpAttachAssetProp)
{
if (mpAttachAssetProp->Type() == eAssetProperty)
mpAttachAsset = gpResourceStore->LoadResource<CModel>( TPropCast<TAssetProperty>(mpAttachAssetProp)->Get() );
else if (mpAttachAssetProp->Type() == eCharacterProperty)
mpAttachAsset = TPropCast<TCharacterProperty>(mpAttachAssetProp)->Get().AnimSet();
if (mAttachAssetRef.IsValid())
mpAttachAsset = gpResourceStore->LoadResource<CModel>(mAttachAssetRef.Get());
else if (mAttachAnimSetRef.IsValid())
mpAttachAsset = mAttachAnimSetRef.Get().AnimSet();
CModel *pModel = Model();
CModel* pModel = Model();
if (pModel && pModel->Type() == eModel)
mLocalAABox = pModel->AABox();
@ -37,11 +40,11 @@ void CScriptAttachNode::AttachPropertyModified()
}
}
void CScriptAttachNode::ParentDisplayAssetChanged(CResource *pNewDisplayAsset)
void CScriptAttachNode::ParentDisplayAssetChanged(CResource* pNewDisplayAsset)
{
if (pNewDisplayAsset->Type() == eAnimSet)
{
CSkeleton *pSkel = mpScriptNode->ActiveSkeleton();
CSkeleton* pSkel = mpScriptNode->ActiveSkeleton();
mpLocator = pSkel->BoneByName(mLocatorName);
}
@ -60,11 +63,8 @@ CModel* CScriptAttachNode::Model() const
if (mpAttachAsset->Type() == eModel)
return static_cast<CModel*>(mpAttachAsset.RawPointer());
if (mpAttachAsset->Type() == eAnimSet)
{
TCharacterProperty *pProp = TPropCast<TCharacterProperty>(mpAttachAssetProp);
return pProp->Get().GetCurrentModel();
}
else if (mpAttachAsset->Type() == eAnimSet)
return mAttachAnimSetRef.Get().GetCurrentModel();
}
return nullptr;

View File

@ -2,20 +2,23 @@
#define CSCRIPTATTACHNODE_H
#include "CSceneNode.h"
#include "Core/Resource/Script/IProperty.h"
#include "Core/Resource/Script/Property/Properties.h"
#include "Core/Resource/Script/CScriptTemplate.h"
class CScriptNode;
class CScriptAttachNode : public CSceneNode
{
CScriptNode *mpScriptNode;
CScriptNode* mpScriptNode;
TResPtr<CResource> mpAttachAsset;
IProperty *mpAttachAssetProp;
IPropertyNew* mpAttachAssetProp;
CAssetRef mAttachAssetRef;
CAnimationSetRef mAttachAnimSetRef;
EAttachType mAttachType;
TString mLocatorName;
CBone *mpLocator;
CBone* mpLocator;
public:
explicit CScriptAttachNode(CScene *pScene, const SAttachment& rkAttachment, CScriptNode *pParent);
@ -30,7 +33,7 @@ public:
void RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& rkViewInfo);
SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo);
inline IProperty* AttachProperty() const { return mpAttachAssetProp; }
inline IPropertyNew* AttachProperty() const { return mpAttachAssetProp; }
inline TString LocatorName() const { return mLocatorName; }
protected:

View File

@ -31,7 +31,7 @@ CScriptNode::CScriptNode(CScene *pScene, u32 NodeID, CSceneNode *pParent, CScrip
CScriptTemplate *pTemp = Template();
// Determine transform
mHasValidPosition = pTemp->HasPosition();
mHasValidPosition = pTemp->PositionProperty() != nullptr;
mPosition = mpInstance->Position();
mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
mScale = mpInstance->Scale();
@ -99,15 +99,13 @@ void CScriptNode::OnTransformed()
{
if (mpInstance)
{
CScriptTemplate *pTemplate = Template();
if (pTemplate->HasPosition() && LocalPosition() != mpInstance->Position())
if (LocalPosition() != mpInstance->Position())
mpInstance->SetPosition(LocalPosition());
if (pTemplate->HasRotation() && LocalRotation().ToEuler() != mpInstance->Rotation())
if (LocalRotation().ToEuler() != mpInstance->Rotation())
mpInstance->SetRotation(LocalRotation().ToEuler());
if (pTemplate->HasScale() && LocalScale() != mpInstance->Scale())
if (LocalScale() != mpInstance->Scale())
mpInstance->SetScale(LocalScale());
}
@ -456,27 +454,29 @@ void CScriptNode::LinksModified()
if (mpExtra) mpExtra->LinksModified();
}
void CScriptNode::PropertyModified(IProperty *pProp)
void CScriptNode::PropertyModified(IPropertyNew* pProp)
{
// Update volume
if ( (pProp->Type() == eBoolProperty) || (pProp->Type() == eByteProperty) || (pProp->Type() == eShortProperty) ||
(pProp->Type() == eLongProperty) || (pProp->Type() == eEnumProperty) )
EPropertyTypeNew Type = pProp->Type();
if ( Type == EPropertyTypeNew::Bool || Type == EPropertyTypeNew::Byte || Type == EPropertyTypeNew::Short ||
Type == EPropertyTypeNew::Int || Type == EPropertyTypeNew::Choice || Type == EPropertyTypeNew::Enum )
{
mpInstance->EvaluateVolume();
UpdatePreviewVolume();
}
// Update resources
if (pProp->Type() == eCharacterProperty)
else if (Type == EPropertyTypeNew::AnimationSet)
{
mpInstance->EvaluateDisplayAsset();
SetDisplayAsset(mpInstance->DisplayAsset());
}
else if (pProp->Type() == eAssetProperty)
else if (Type == EPropertyTypeNew::Asset)
{
CAssetTemplate *pAssetTemp = static_cast<CAssetTemplate*>(pProp->Template());
const CResTypeFilter& rkFilter = pAssetTemp->TypeFilter();
CAssetProperty* pAssetProperty = TPropCast<CAssetProperty>(pProp);
const CResTypeFilter& rkFilter = pAssetProperty->GetTypeFilter();
if (rkFilter.Accepts(eModel) || rkFilter.Accepts(eTexture) || rkFilter.Accepts(eAnimSet) || rkFilter.Accepts(eCharacter))
{
@ -491,40 +491,37 @@ void CScriptNode::PropertyModified(IProperty *pProp)
}
// Update other editor properties
if (mpInstance->IsEditorProperty(pProp))
{
CScriptTemplate *pTemplate = Template();
CScriptTemplate *pTemplate = Template();
if (pTemplate->HasName())
SetName("[" + mpInstance->Template()->Name() + "] " + mpInstance->InstanceName());
if (pProp == pTemplate->NameProperty())
SetName("[" + mpInstance->Template()->Name() + "] " + mpInstance->InstanceName());
if (pTemplate->HasPosition())
mPosition = mpInstance->Position();
else if (pProp == pTemplate->PositionProperty())
mPosition = mpInstance->Position();
if (pTemplate->HasRotation())
mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
else if (pProp == pTemplate->RotationProperty())
mRotation = CQuaternion::FromEuler(mpInstance->Rotation());
if (pTemplate->HasScale())
mScale = mpInstance->Scale();
else if (pProp == pTemplate->ScaleProperty())
mScale = mpInstance->Scale();
MarkTransformChanged();
SetLightLayerIndex(mpLightParameters->LightLayerIndex());
}
MarkTransformChanged();
SetLightLayerIndex(mpLightParameters->LightLayerIndex());
// Notify attachments
for (u32 iAttach = 0; iAttach < mAttachments.size(); iAttach++)
for (u32 AttachIdx = 0; AttachIdx < mAttachments.size(); AttachIdx++)
{
CScriptAttachNode *pAttach = mAttachments[iAttach];
CScriptAttachNode* pAttachNode = mAttachments[AttachIdx];
if (pAttach->AttachProperty() == pProp)
pAttach->AttachPropertyModified();
if (pAttachNode->AttachProperty() == pProp)
pAttachNode->AttachPropertyModified();
}
// Notify script extra
if (mpExtra) mpExtra->PropertyModified(pProp);
// Update game mode visibility
if (pProp && pProp == mpInstance->ActiveProperty())
if (pProp && pProp == pTemplate->ActiveProperty())
TestGameModeVisibility();
}

View File

@ -49,7 +49,7 @@ public:
CColor WireframeColor() const;
void LinksModified();
void PropertyModified(IProperty *pProp);
void PropertyModified(IPropertyNew* pProp);
void UpdatePreviewVolume();
void GeneratePosition();
void TestGameModeVisibility();

View File

@ -6,7 +6,6 @@
CDamageableTriggerExtra::CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
: CScriptExtra(pInstance, pScene, pParent)
, mpRenderSideProp(nullptr)
, mpMat(nullptr)
{
for (u32 iTex = 0; iTex < 3; iTex++)
@ -15,21 +14,21 @@ CDamageableTriggerExtra::CDamageableTriggerExtra(CScriptObject *pInstance, CScen
SetInheritance(true, false, false);
CreateMaterial();
CPropertyStruct *pBaseStruct = pInstance->Properties();
CStructPropertyNew* pProperties = pInstance->Template()->Properties();
// Fetch render side
mpRenderSideProp = TPropCast<TEnumProperty>(pBaseStruct->PropertyByIndex(0x5));
if (mpRenderSideProp) PropertyModified(mpRenderSideProp);
mRenderSide = TEnumRef<ERenderSide>(pInstance, pProperties->ChildByIndex(5));
if (mRenderSide.IsValid()) PropertyModified(mRenderSide.Property());
// Fetch scale
mpSizeProp = TPropCast<TVector3Property>(pBaseStruct->PropertyByIndex(0x2));
if (mpSizeProp) PropertyModified(mpSizeProp);
mPlaneSize = CVectorRef(pInstance, pProperties->ChildByIndex(2));
if (mPlaneSize.IsValid()) PropertyModified(mPlaneSize.Property());
// Fetch textures
for (u32 iTex = 0; iTex < 3; iTex++)
for (u32 TextureIdx = 0; TextureIdx < 3; TextureIdx++)
{
mpTextureProps[iTex] = TPropCast<TAssetProperty>(pBaseStruct->PropertyByIndex(0x6 + iTex));
if (mpTextureProps[iTex]) PropertyModified(mpTextureProps[iTex]);
mTextureAssets[TextureIdx] = CAssetRef(pInstance, pProperties->ChildByIndex(6 + TextureIdx));
if (mTextureAssets[TextureIdx].IsValid()) PropertyModified(mTextureAssets[TextureIdx].Property());
}
}
@ -80,7 +79,7 @@ void CDamageableTriggerExtra::CreateMaterial()
void CDamageableTriggerExtra::UpdatePlaneTransform()
{
CVector3f Extent = mPlaneSize / 2.f;
CVector3f Extent = mPlaneSize.Get() / 2.f;
switch (mRenderSide)
{
@ -92,7 +91,7 @@ void CDamageableTriggerExtra::UpdatePlaneTransform()
mPosition = CVector3f(0.f, Extent.Y * Scalar, 0.f);
mRotation = CQuaternion::FromEuler(CVector3f(90.f * Scalar, 0.f, 0.f));
mScale = CVector3f(Extent.X, Extent.Z, 0.f);
mCoordScale = mPlaneSize.XZ();
mCoordScale = mPlaneSize.Get().XZ();
break;
}
@ -104,7 +103,7 @@ void CDamageableTriggerExtra::UpdatePlaneTransform()
mPosition = CVector3f(-Extent.X * Scalar, 0.f, 0.f);
mRotation = CQuaternion::FromEuler(CVector3f(0.f, 90.f * Scalar, 0.f));
mScale = CVector3f(Extent.Z, Extent.Y, 0.f);
mCoordScale = -mPlaneSize.YZ();
mCoordScale = -mPlaneSize.Get().YZ();
break;
}
@ -117,7 +116,7 @@ void CDamageableTriggerExtra::UpdatePlaneTransform()
mPosition = CVector3f(0.f, 0.f, Extent.Z * Scalar);
mRotation = CQuaternion::FromEuler(CVector3f(0.f, RotAngle, 0.f));
mScale = CVector3f(Extent.X, Extent.Y, 0.f);
mCoordScale = -mPlaneSize.XY();
mCoordScale = -mPlaneSize.Get().XY();
break;
}
@ -176,36 +175,28 @@ CDamageableTriggerExtra::ERenderSide CDamageableTriggerExtra::TransformRenderSid
void CDamageableTriggerExtra::OnTransformed()
{
mPlaneSize = mpSizeProp->Get();
UpdatePlaneTransform();
}
void CDamageableTriggerExtra::PropertyModified(IProperty *pProperty)
void CDamageableTriggerExtra::PropertyModified(IPropertyNew* pProperty)
{
if (pProperty == mpRenderSideProp)
if (pProperty == mRenderSide || pProperty == mPlaneSize)
{
mRenderSide = TransformRenderSide( (ERenderSide) mpRenderSideProp->Get() );
UpdatePlaneTransform();
}
else if (pProperty == mpSizeProp)
{
mPlaneSize = mpSizeProp->Get();
UpdatePlaneTransform();
}
else
{
for (u32 iTex = 0; iTex < 3; iTex++)
for (u32 TextureIdx = 0; TextureIdx < 3; TextureIdx++)
{
if (pProperty == mpTextureProps[iTex])
if (pProperty == mTextureAssets[TextureIdx].Property())
{
mpTextures[iTex] = gpResourceStore->LoadResource<CTexture>( mpTextureProps[iTex]->Get() );
mpTextures[TextureIdx] = gpResourceStore->LoadResource<CTexture>( mTextureAssets[TextureIdx].Get() );
if (mpTextures[iTex] && mpTextures[iTex]->Type() != eTexture)
mpTextures[iTex] = nullptr;
if (mpTextures[TextureIdx] && mpTextures[TextureIdx]->Type() != eTexture)
mpTextures[TextureIdx] = nullptr;
mpMat->Pass(iTex)->SetTexture(mpTextures[iTex]);
mpMat->Pass(TextureIdx)->SetTexture(mpTextures[TextureIdx]);
break;
}
}

View File

@ -17,15 +17,12 @@ class CDamageableTriggerExtra : public CScriptExtra
eDown = 0x20
};
TVector3Property *mpSizeProp;
TEnumProperty *mpRenderSideProp;
TAssetProperty *mpTextureProps[3];
CVectorRef mPlaneSize;
TEnumRef<ERenderSide> mRenderSide;
CAssetRef mTextureAssets[3];
CVector3f mPlaneSize;
ERenderSide mRenderSide;
TResPtr<CTexture> mpTextures[3];
CMaterial *mpMat;
CMaterial* mpMat;
CTexture* mpTextures[3];
CVector2f mCoordScale;
float mCachedRayDistance;
@ -38,7 +35,7 @@ public:
ERenderSide RenderSideForDirection(const CVector3f& rkDir);
ERenderSide TransformRenderSide(ERenderSide Side);
void OnTransformed();
void PropertyModified(IProperty *pProperty);
void PropertyModified(IPropertyNew* pProperty);
bool ShouldDrawNormalAssets();
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo);

View File

@ -1,35 +1,32 @@
#include "CDoorExtra.h"
#include "Core/Render/CRenderer.h"
CDoorExtra::CDoorExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
CDoorExtra::CDoorExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent)
: CScriptExtra(pInstance, pScene, pParent)
, mpShieldModelProp(nullptr)
, mpShieldColorProp(nullptr)
, mpShieldModel(nullptr)
{
CPropertyStruct *pBaseStruct = pInstance->Properties();
CStructPropertyNew* pProperties = pInstance->Template()->Properties();
mpShieldModelProp = TPropCast<TAssetProperty>(pBaseStruct->PropertyByID(0xB20CC271));
if (mpShieldModelProp) PropertyModified(mpShieldModelProp);
mShieldModelProp = CAssetRef(pInstance, pProperties->ChildByID(0xB20CC271));
if (mShieldModelProp.IsValid()) PropertyModified(mShieldModelProp.Property());
if (mGame >= eEchoes)
{
mpShieldColorProp = TPropCast<TColorProperty>(pBaseStruct->PropertyByID(0x47B4E863));
if (mpShieldColorProp) PropertyModified(mpShieldColorProp);
mShieldColorProp = CColorRef(pInstance, pProperties->ChildByID(0x47B4E863));
if (mShieldColorProp.IsValid()) PropertyModified(mShieldColorProp.Property());
}
else
{
mpDisabledProp = TPropCast<TBoolProperty>(pBaseStruct->PropertyByID(0xDEE730F5));
if (mpDisabledProp) PropertyModified(mpDisabledProp);
mDisabledProp = CBoolRef(pInstance, pProperties->ChildByID(0xDEE730F5));
if (mDisabledProp.IsValid()) PropertyModified(mDisabledProp.Property());
}
}
void CDoorExtra::PropertyModified(IProperty *pProperty)
void CDoorExtra::PropertyModified(IPropertyNew* pProperty)
{
if (pProperty == mpShieldModelProp)
if (pProperty == mShieldModelProp)
{
mpShieldModel = gpResourceStore->LoadResource<CModel>( mpShieldModelProp->Get() );
mpShieldModel = gpResourceStore->LoadResource<CModel>( mShieldModelProp.Get() );
if (mpShieldModel)
mLocalAABox = mpShieldModel->AABox();
@ -40,18 +37,13 @@ void CDoorExtra::PropertyModified(IProperty *pProperty)
MarkTransformChanged();
}
else if (pProperty == mpShieldColorProp)
{
mShieldColor = mpShieldColorProp->Get();
}
else if (pProperty == mpDisabledProp)
else if (pProperty == mDisabledProp)
{
// The Echoes demo doesn't have the shield color property. The color is
// always cyan if the door is unlocked and always white if the door is locked.
mShieldColor = CColor::skWhite;
if (!mpDisabledProp->Get())
if (!mDisabledProp)
mShieldColor = CColor::skCyan;
}
}

View File

@ -6,16 +6,17 @@
class CDoorExtra : public CScriptExtra
{
// Render colored door shield in MP2/3
TAssetProperty *mpShieldModelProp;
TColorProperty *mpShieldColorProp;
TBoolProperty *mpDisabledProp;
CAssetRef mShieldModelProp;
CColorRef mShieldColorProp;
CBoolRef mDisabledProp;
TResPtr<CModel> mpShieldModel;
CColor mShieldColor;
public:
explicit CDoorExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0);
void PropertyModified(IProperty *pProperty);
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
explicit CDoorExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent = 0);
void PropertyModified(IPropertyNew* pProperty);
void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo);
void DrawSelection();
void RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& rkViewInfo);

View File

@ -5,21 +5,21 @@ const CColor CPointOfInterestExtra::skImportantColor = CColor::Integral(0xFF,0x0
CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
: CScriptExtra(pInstance, pScene, pParent)
, mpScanProperty(nullptr)
, mpScanData(nullptr)
{
// Fetch scan data property
CPropertyStruct *pBaseProp = pInstance->Properties();
CStructPropertyNew* pProperties = pInstance->Template()->Properties();
if (mGame <= ePrime) mpScanProperty = TPropCast<TAssetProperty>(pBaseProp->PropertyByIDString("0x04:0x00"));
else mpScanProperty = (TAssetProperty*) pBaseProp->PropertyByIDString("0xBDBEC295:0xB94E9BE7");
if (mpScanProperty) PropertyModified(mpScanProperty);
if (mGame <= ePrime) mScanProperty = CAssetRef(pInstance, pProperties->ChildByIDString("0x04:0x00"));
else mScanProperty = CAssetRef(pInstance, pProperties->ChildByIDString("0xBDBEC295:0xB94E9BE7"));
PropertyModified(mScanProperty.Property());
}
void CPointOfInterestExtra::PropertyModified(IProperty* pProperty)
void CPointOfInterestExtra::PropertyModified(IPropertyNew* pProperty)
{
if (mpScanProperty == pProperty)
mpScanData = gpResourceStore->LoadResource<CScan>( mpScanProperty->Get() );
if (mScanProperty.Property() == pProperty)
mpScanData = gpResourceStore->LoadResource<CScan>( mScanProperty.Get() );
}
void CPointOfInterestExtra::ModifyTintColor(CColor& Color)

View File

@ -8,12 +8,12 @@
class CPointOfInterestExtra : public CScriptExtra
{
// Tint POI billboard orange/red depending on scan importance
TAssetProperty *mpScanProperty;
CAssetRef mScanProperty;
TResPtr<CScan> mpScanData;
public:
explicit CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0);
void PropertyModified(IProperty* pProperty);
void PropertyModified(IPropertyNew* pProperty);
void ModifyTintColor(CColor& Color);
CScan* GetScan() const { return mpScanData; }

View File

@ -2,32 +2,32 @@
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CRenderer.h"
CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
CRadiusSphereExtra::CRadiusSphereExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent)
: CScriptExtra(pInstance, pScene, pParent)
, mpRadius(nullptr)
{
mObjectType = pInstance->ObjectTypeID();
CStructPropertyNew* pProperties = pInstance->Template()->Properties();
switch (mObjectType)
{
case 0x63: // Repulsor (MP1)
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x3));
mRadius = CFloatRef(pInstance, pProperties->ChildByID(3));
break;
case 0x68: // RadialDamage (MP1)
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x4));
mRadius = CFloatRef(pInstance, pProperties->ChildByID(0x4));
break;
case 0x5245504C: // "REPL" Repulsor (MP2/MP3)
case 0x52414444: // "RADD" RadialDamage (MP2/MP3/DKCR)
mpRadius = TPropCast<TFloatProperty>(pInstance->Properties()->PropertyByID(0x78C507EB));
case FOURCC('REPL'): // Repulsor (MP2/MP3)
case FOURCC('RADD'): // RadialDamage (MP2/MP3/DKCR)
mRadius = CFloatRef(pInstance, pProperties->ChildByID(0x78C507EB));
break;
}
}
void CRadiusSphereExtra::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo)
void CRadiusSphereExtra::AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo)
{
if (!rkViewInfo.GameMode && (rkViewInfo.ShowFlags & eShowObjectGeometry) && mpRadius && mpParent->IsVisible() && mpParent->IsSelected())
if (!rkViewInfo.GameMode && (rkViewInfo.ShowFlags & eShowObjectGeometry) && mRadius.IsValid() && mpParent->IsVisible() && mpParent->IsSelected())
{
CAABox BoundingBox = Bounds();
@ -42,7 +42,7 @@ void CRadiusSphereExtra::Draw(FRenderOptions /*Options*/, int /*ComponentIndex*/
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
CDrawUtil::DrawWireSphere(mpInstance->Position(), mpRadius->Get(), Color());
CDrawUtil::DrawWireSphere(mpInstance->Position(), mRadius, Color());
}
CColor CRadiusSphereExtra::Color() const
@ -66,7 +66,7 @@ CColor CRadiusSphereExtra::Color() const
CAABox CRadiusSphereExtra::Bounds() const
{
CAABox Bounds = CAABox::skOne * 2.f * mpRadius->Get();
CAABox Bounds = CAABox::skOne * 2.f * mRadius;
Bounds += mpParent->AbsolutePosition();
return Bounds;
}

View File

@ -7,11 +7,11 @@ class CRadiusSphereExtra : public CScriptExtra
{
// Sphere visualization for objects that have a float radius property.
u32 mObjectType;
TFloatProperty *mpRadius;
CFloatRef mRadius;
public:
explicit CRadiusSphereExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0);
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
explicit CRadiusSphereExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent = 0);
void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo);
CColor Color() const;
CAABox Bounds() const;

View File

@ -1,30 +1,30 @@
#include "CSandwormExtra.h"
CSandwormExtra::CSandwormExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
CSandwormExtra::CSandwormExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent)
: CScriptExtra(pInstance, pScene, pParent)
{
// The back pincers need to be flipped 180 degrees
for (u32 iAttach = 0; iAttach < pParent->NumAttachments(); iAttach++)
for (u32 AttachIdx = 0; AttachIdx < pParent->NumAttachments(); AttachIdx++)
{
CScriptAttachNode *pAttach = pParent->Attachment(iAttach);
CScriptAttachNode *pAttach = pParent->Attachment(AttachIdx);
if (pAttach->LocatorName() == "L_back_claw" || pAttach->LocatorName() == "R_back_claw")
pAttach->SetRotation(CVector3f(0,0,180));
}
// Get pincers scale
mpPincersScaleProperty = TPropCast<TFloatProperty>(pInstance->PropertyByIDString("0x3DB583AE"));
if (mpPincersScaleProperty) PropertyModified(mpPincersScaleProperty);
mPincersScale = CFloatRef(pInstance, pInstance->Template()->Properties()->ChildByID(0x3DB583AE));
if (mPincersScale.IsValid()) PropertyModified(mPincersScale.Property());
}
void CSandwormExtra::PropertyModified(IProperty *pProp)
void CSandwormExtra::PropertyModified(IPropertyNew* pProp)
{
if (pProp == mpPincersScaleProperty)
if (pProp == mPincersScale)
{
for (u32 iAttach = 0; iAttach < mpScriptNode->NumAttachments(); iAttach++)
for (u32 AttachIdx = 0; AttachIdx < mpScriptNode->NumAttachments(); AttachIdx++)
{
CScriptAttachNode *pAttach = mpScriptNode->Attachment(iAttach);
pAttach->SetScale(CVector3f(mpPincersScaleProperty->Get()));
CScriptAttachNode* pAttach = mpScriptNode->Attachment(AttachIdx);
pAttach->SetScale( CVector3f(mPincersScale) );
}
}
}

View File

@ -6,11 +6,11 @@
class CSandwormExtra : public CScriptExtra
{
// Transform adjustments to Sandworm attachments.
TFloatProperty *mpPincersScaleProperty;
CFloatRef mPincersScale;
public:
explicit CSandwormExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent);
void PropertyModified(IProperty *pProp);
explicit CSandwormExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent);
void PropertyModified(IPropertyNew* pProp);
};
#endif // CSANDWORMEXTRA_H

View File

@ -46,7 +46,7 @@ public:
// Virtual CScriptExtra functions
virtual void InstanceTransformed() {}
virtual void PropertyModified(IProperty* /*pProperty*/) {}
virtual void PropertyModified(IPropertyNew* /*pProperty*/) {}
virtual void DisplayAssetChanged(CResource* /*pNewDisplayAsset*/) {}
virtual void LinksModified() {}
virtual bool ShouldDrawNormalAssets() { return true; }

View File

@ -1,37 +1,33 @@
#include "CSpacePirateExtra.h"
CSpacePirateExtra::CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
CSpacePirateExtra::CSpacePirateExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent)
: CScriptExtra(pInstance, pScene ,pParent)
, mpPowerVuln(nullptr)
, mpWaveVuln(nullptr)
, mpIceVuln(nullptr)
, mpPlasmaVuln(nullptr)
{
CPropertyStruct *pBaseStruct = pInstance->Properties();
CPropertyStruct *pVulns = (CPropertyStruct*) pBaseStruct->PropertyByIDString("0x04:0x10");
CStructPropertyNew* pBaseStruct = pInstance->Template()->Properties();
CStructPropertyNew* pVulnerabilities = TPropCast<CStructPropertyNew>(pBaseStruct->ChildByIDString("0x04:0x10"));
if (pVulns && pVulns->Type() == eStructProperty)
if (pVulnerabilities)
{
mpPowerVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x0));
mpWaveVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x2));
mpIceVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x1));
mpPlasmaVuln = TPropCast<TEnumProperty>(pVulns->PropertyByID(0x3));
mPowerVulnerability = TEnumRef<EVulnerabilityTypeMP1>(pInstance, pVulnerabilities->ChildByID(0));
mWaveVulnerability = TEnumRef<EVulnerabilityTypeMP1>(pInstance, pVulnerabilities->ChildByID(2));
mIceVulnerability = TEnumRef<EVulnerabilityTypeMP1>(pInstance, pVulnerabilities->ChildByID(1));
mPlasmaVulnerability = TEnumRef<EVulnerabilityTypeMP1>(pInstance, pVulnerabilities->ChildByID(3));
}
}
CColor CSpacePirateExtra::TevColor()
{
// Priority: Plasma -> Ice -> Power -> Wave
if (mpPlasmaVuln && mpPlasmaVuln->Get() == 1)
if (mPlasmaVulnerability.IsValid() && mPlasmaVulnerability.Get() == EVulnerabilityTypeMP1::Normal)
return CColor::skRed;
if (mpIceVuln && mpIceVuln->Get() == 1)
if (mIceVulnerability.IsValid() && mIceVulnerability.Get() == EVulnerabilityTypeMP1::Normal)
return CColor::skWhite;
if (mpPowerVuln && mpPowerVuln->Get() == 1)
if (mPowerVulnerability.IsValid() && mPowerVulnerability.Get() == EVulnerabilityTypeMP1::Normal)
return CColor::skYellow;
if (mpWaveVuln && mpWaveVuln->Get() == 1)
if (mWaveVulnerability.IsValid() && mWaveVulnerability.Get() == EVulnerabilityTypeMP1::Normal)
return CColor::skPurple;
return CColor::skWhite;

View File

@ -4,13 +4,25 @@
#include "CScriptExtra.h"
#include "Core/Resource/Script/IProperty.h"
enum class EVulnerabilityTypeMP1
{
DoubleDamage,
Normal,
Reflect,
Immune,
PassThru,
DirectDouble,
DirectNormal,
DirectImmune
};
class CSpacePirateExtra : public CScriptExtra
{
// Render beam troopers with the correct color
TEnumProperty *mpPowerVuln;
TEnumProperty *mpWaveVuln;
TEnumProperty *mpIceVuln;
TEnumProperty *mpPlasmaVuln;
TEnumRef<EVulnerabilityTypeMP1> mPowerVulnerability;
TEnumRef<EVulnerabilityTypeMP1> mWaveVulnerability;
TEnumRef<EVulnerabilityTypeMP1> mIceVulnerability;
TEnumRef<EVulnerabilityTypeMP1> mPlasmaVulnerability;
public:
explicit CSpacePirateExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0);

View File

@ -3,15 +3,15 @@
#include "Core/Resource/Script/CLink.h"
#include "Core/Scene/CScene.h"
CSplinePathExtra::CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
CSplinePathExtra::CSplinePathExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent)
: CScriptExtra(pInstance, pScene, pParent)
{
mpPathColor = TPropCast<TColorProperty>(pInstance->Properties()->PropertyByID(0x00DD86E2));
mPathColor = CColorRef(pInstance, pInstance->Template()->Properties()->ChildByID(0x00DD86E2));
}
void CSplinePathExtra::PropertyModified(IProperty *pProperty)
void CSplinePathExtra::PropertyModified(IPropertyNew* pProperty)
{
if (pProperty == mpPathColor)
if (pProperty == mPathColor.Property())
{
for (auto it = mWaypoints.begin(); it != mWaypoints.end(); it++)
(*it)->CheckColor();
@ -23,7 +23,7 @@ void CSplinePathExtra::PostLoad()
AddWaypoints();
}
void CSplinePathExtra::FindAttachedWaypoints(std::set<CWaypointExtra*>& rChecked, CWaypointExtra *pWaypoint)
void CSplinePathExtra::FindAttachedWaypoints(std::set<CWaypointExtra*>& rChecked, CWaypointExtra* pWaypoint)
{
if (rChecked.find(pWaypoint) != rChecked.end())
return;
@ -46,18 +46,18 @@ void CSplinePathExtra::AddWaypoints()
std::set<CWaypointExtra*> CheckedWaypoints;
for (u32 iLink = 0; iLink < mpInstance->NumLinks(eOutgoing); iLink++)
for (u32 LinkIdx = 0; LinkIdx < mpInstance->NumLinks(eOutgoing); LinkIdx++)
{
CLink *pLink = mpInstance->Link(eOutgoing, iLink);
CLink* pLink = mpInstance->Link(eOutgoing, LinkIdx);
if ( (pLink->State() == 0x49533030 && pLink->Message() == 0x41544348) || // InternalState00/Attach
(pLink->State() == 0x4D4F5450 && pLink->Message() == 0x41544348) ) // MotionPath/Attach
if ( (pLink->State() == FOURCC('IS00') && pLink->Message() == FOURCC('ATCH')) || // InternalState00/Attach
(pLink->State() == FOURCC('MOTP') && pLink->Message() == FOURCC('ATCH')) ) // MotionPath/Attach
{
CScriptNode *pNode = mpScene->NodeForInstanceID(pLink->ReceiverID());
CScriptNode* pNode = mpScene->NodeForInstanceID(pLink->ReceiverID());
if (pNode && pNode->Instance()->ObjectTypeID() == 0x57415950) // Waypoint
if (pNode && pNode->Instance()->ObjectTypeID() == FOURCC('WAYP')) // Waypoint
{
CWaypointExtra *pWaypoint = static_cast<CWaypointExtra*>(pNode->Extra());
CWaypointExtra* pWaypoint = static_cast<CWaypointExtra*>(pNode->Extra());
FindAttachedWaypoints(CheckedWaypoints, pWaypoint);
}
}

View File

@ -11,20 +11,20 @@ class CWaypointExtra;
class CSplinePathExtra : public CScriptExtra
{
// Recolor waypoint paths to match the editor color parameter
TColorProperty *mpPathColor;
CColorRef mPathColor;
std::list<CWaypointExtra*> mWaypoints;
public:
explicit CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0);
explicit CSplinePathExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent = 0);
~CSplinePathExtra() { ClearWaypoints(); }
inline CColor PathColor() const { return (mpPathColor ? mpPathColor->Get() : CColor::skBlack); }
inline CColor PathColor() const { return (mPathColor.IsValid() ? mPathColor.Get() : CColor::skBlack); }
void PostLoad();
void PropertyModified(IProperty *pProperty);
void PropertyModified(IPropertyNew* pProperty);
void FindAttachedWaypoints(std::set<CWaypointExtra*>& rChecked, CWaypointExtra *pWaypoint);
void FindAttachedWaypoints(std::set<CWaypointExtra*>& rChecked, CWaypointExtra* pWaypoint);
void AddWaypoints();
void RemoveWaypoint(CWaypointExtra *pWaypoint);
void RemoveWaypoint(CWaypointExtra* pWaypoint);
void ClearWaypoints();
};

View File

@ -231,7 +231,8 @@ void CGeneratePropertyNamesDialog::ApplyChanges()
pItem->setText(3, NewName);
}
CTemplateWriter::SavePropertyList();
//FIXME
// CTemplateWriter::SavePropertyList();
}
/** Check progress on name generation task and display results on the UI */

View File

@ -6,7 +6,7 @@ CPropertyNameValidator::CPropertyNameValidator(QObject* pParent)
{}
/** Set the property to validate against */
void CPropertyNameValidator::SetProperty(IPropertyTemplate* pProp)
void CPropertyNameValidator::SetProperty(IPropertyNew* pProp)
{
mpProperty = pProp;
emit changed();
@ -19,10 +19,10 @@ QValidator::State CPropertyNameValidator::validate(QString& rInput, int&) const
{
CCRC32 Hash;
Hash.Hash( rInput.toStdString().c_str() );
Hash.Hash( mpProperty->GetTypeNameString() );
Hash.Hash( mpProperty->HashableTypeName() );
u32 PropertyID = Hash.Digest();
return ( PropertyID == mpProperty->PropertyID() ? QValidator::Acceptable : QValidator::Invalid );
return ( PropertyID == mpProperty->ID() ? QValidator::Acceptable : QValidator::Invalid );
}
return QValidator::Invalid;

View File

@ -2,7 +2,7 @@
#define CPROPERTYNAMEVALIDATOR_H
#include <QValidator>
#include <Core/Resource/Script/IPropertyTemplate.h>
#include <Core/Resource/Script/Property/Properties.h>
/** QValidator subclass that checks if a property name is valid */
class CPropertyNameValidator : public QValidator
@ -10,13 +10,13 @@ class CPropertyNameValidator : public QValidator
Q_OBJECT
/** The property being validated against */
IPropertyTemplate* mpProperty;
IPropertyNew* mpProperty;
public:
CPropertyNameValidator(QObject* pParent = 0);
/** Set the property to validate against */
void SetProperty(IPropertyTemplate* pProp);
void SetProperty(IPropertyNew* pProp);
/** Perform validation */
QValidator::State validate(QString& rInput, int& rPos) const;

View File

@ -49,7 +49,7 @@ void CPropertyDelegate::SetEditor(CWorldEditor *pEditor)
QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionViewItem& /*rkOption*/, const QModelIndex& rkIndex) const
{
if (!mpModel) return nullptr;
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false);
IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false);
QWidget *pOut = nullptr;
if (pProp)
@ -57,7 +57,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
switch (pProp->Type())
{
case eBoolProperty:
case EPropertyTypeNew::Bool:
{
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
@ -65,39 +65,39 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
}
case eShortProperty:
case EPropertyTypeNew::Short:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix()));
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox;
break;
}
case eLongProperty:
case EPropertyTypeNew::Int:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix()));
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox;
break;
}
case eFloatProperty:
case EPropertyTypeNew::Float:
{
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
pSpinBox->setSingleStep(0.1);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix()));
pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pOut = pSpinBox;
break;
}
case eColorProperty:
case EPropertyTypeNew::Color:
{
WColorPicker *pColorPicker = new WColorPicker(pParent);
CONNECT_RELAY(pColorPicker, rkIndex, ColorChanged(QColor))
@ -105,7 +105,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
}
case eSoundProperty:
case EPropertyTypeNew::Sound:
{
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(-1);
@ -115,7 +115,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
}
case eStringProperty:
case EPropertyTypeNew::String:
{
QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
@ -123,34 +123,34 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break;
}
case eEnumProperty:
case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
{
QComboBox *pComboBox = new QComboBox(pParent);
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template());
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
for (u32 ValueIdx = 0; ValueIdx < pEnum->NumPossibleValues(); ValueIdx++)
pComboBox->addItem(TO_QSTRING(pEnum->ValueName(ValueIdx)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
pOut = pComboBox;
break;
}
case eAssetProperty:
case EPropertyTypeNew::Asset:
{
CResourceSelector *pSelector = new CResourceSelector(pParent);
pSelector->SetFrameVisible(false);
CAssetTemplate *pTemp = static_cast<CAssetTemplate*>(pProp->Template());
pSelector->SetTypeFilter(pTemp->TypeFilter());
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
pSelector->SetTypeFilter(pAsset->GetTypeFilter());
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*))
pOut = pSelector;
break;
}
case eArrayProperty:
case EPropertyTypeNew::Array:
{
// No relay here, would prefer user to be sure of their change before it's reflected on the UI
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
@ -163,41 +163,23 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
}
}
// Check for sub-property of vector/color/character
else if (rkIndex.internalId() & 0x1)
// Check for sub-property of flgs/animation set
else if (rkIndex.internalId() & 0x80000000)
{
pProp = mpModel->PropertyForIndex(rkIndex, true);
EPropertyTypeNew Type = pProp->Type();
// Handle character
if (pProp->Type() == eCharacterProperty)
if (Type == EPropertyTypeNew::AnimationSet)
pOut = CreateCharacterEditor(pParent, rkIndex);
// Handle bitfield
else if (pProp->Type() == eBitfieldProperty)
// Handle flags
else if (Type == EPropertyTypeNew::Flags)
{
QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
pOut = pCheckBox;
}
// Handle vector/color
else
{
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
pSpinBox->setSingleStep(0.1);
// Limit to range of 0-1 on colors
pProp = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == eColorProperty)
{
pSpinBox->setMinimum(0.0);
pSpinBox->setMaximum(1.0);
}
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pOut = pSpinBox;
}
}
if (pOut)
@ -218,7 +200,8 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
if (pEditor)
{
// Set editor data for regular property
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false);
IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false);
void* pData = mpModel->GetPropertyData();
if (pProp)
{
@ -227,102 +210,114 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
switch (pProp->Type())
{
case eBoolProperty:
case EPropertyTypeNew::Bool:
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
TBoolProperty *pBool = static_cast<TBoolProperty*>(pProp);
pCheckBox->setChecked(pBool->Get());
CBoolProperty *pBool = TPropCast<CBoolProperty>(pProp);
pCheckBox->setChecked( pBool->Value(pData) );
break;
}
case eShortProperty:
case EPropertyTypeNew::Short:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus())
{
TShortProperty *pShort = static_cast<TShortProperty*>(pProp);
pSpinBox->setValue(pShort->Get());
CShortProperty *pShort = TPropCast<CShortProperty>(pProp);
pSpinBox->setValue( pShort->Value(pData) );
}
break;
}
case eLongProperty:
case eSoundProperty:
case EPropertyTypeNew::Int:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus())
{
TLongProperty *pLong = static_cast<TLongProperty*>(pProp);
pSpinBox->setValue(pLong->Get());
CIntProperty *pInt = TPropCast<CIntProperty>(pProp);
pSpinBox->setValue( pInt->Value(pData) );
}
break;
}
case eFloatProperty:
case EPropertyTypeNew::Sound:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus())
{
CSoundProperty *pSound = TPropCast<CSoundProperty>(pProp);
pSpinBox->setValue( pSound->Value(pData) );
}
break;
}
case EPropertyTypeNew::Float:
{
WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
if (!pSpinBox->hasFocus())
{
TFloatProperty *pFloat = static_cast<TFloatProperty*>(pProp);
pSpinBox->setValue(pFloat->Get());
CFloatProperty *pFloat = TPropCast<CFloatProperty>(pProp);
pSpinBox->setValue( pFloat->Value(pData) );
}
break;
}
case eColorProperty:
case EPropertyTypeNew::Color:
{
WColorPicker *pColorPicker = static_cast<WColorPicker*>(pEditor);
TColorProperty *pColor = static_cast<TColorProperty*>(pProp);
CColorProperty *pColor = TPropCast<CColorProperty>(pProp);
CColor Color = pColor->Get();
CColor Color = pColor->Value(pData);
pColorPicker->SetColor(TO_QCOLOR(Color));
break;
}
case eStringProperty:
case EPropertyTypeNew::String:
{
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
if (!pLineEdit->hasFocus())
{
TStringProperty *pString = static_cast<TStringProperty*>(pProp);
pLineEdit->setText(TO_QSTRING(pString->Get()));
CStringProperty *pString = TPropCast<CStringProperty>(pProp);
pLineEdit->setText( TO_QSTRING(pString->Value(pData)) );
}
break;
}
case eEnumProperty:
case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
{
QComboBox *pComboBox = static_cast<QComboBox*>(pEditor);
TEnumProperty *pEnum = static_cast<TEnumProperty*>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template());
pComboBox->setCurrentIndex(pTemp->EnumeratorIndex(pEnum->Get()));
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
pComboBox->setCurrentIndex( pEnum->ValueIndex( pEnum->Value(pData) ) );
break;
}
case eAssetProperty:
case EPropertyTypeNew::Asset:
{
CResourceSelector *pSelector = static_cast<CResourceSelector*>(pEditor);
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp);
pSelector->SetResource(pAsset->Get());
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
pSelector->SetResource(pAsset->Value(pData));
break;
}
case eArrayProperty:
case EPropertyTypeNew::Array:
{
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus())
{
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
pSpinBox->setValue(pArray->Count());
pSpinBox->setValue( pArray->ArrayCount(pData) );
}
break;
@ -332,54 +327,22 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
}
}
// Set editor data for character/bitfield/vector/color sub-property
else if (rkIndex.internalId() & 0x1)
// Set editor data for animation set/flags sub-property
else if (rkIndex.internalId() & 0x80000000)
{
pProp = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == eCharacterProperty)
if (pProp->Type() == EPropertyTypeNew::AnimationSet)
SetCharacterEditorData(pEditor, rkIndex);
else if (pProp->Type() == eBitfieldProperty)
else if (pProp->Type() == EPropertyTypeNew::Flags)
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
TBitfieldProperty *pBitfield = static_cast<TBitfieldProperty*>(pProp);
u32 Mask = static_cast<CBitfieldTemplate*>(pBitfield->Template())->FlagMask(rkIndex.row());
bool Set = (pBitfield->Get() & Mask) != 0;
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
u32 Mask = pFlags->FlagMask(rkIndex.row());
bool Set = (pFlags->Value(pData) & Mask) != 0;
pCheckBox->setChecked(Set);
}
else
{
WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
float Value;
if (!pSpinBox->hasFocus())
{
if (pProp->Type() == eVector3Property)
{
TVector3Property *pVector = static_cast<TVector3Property*>(pProp);
CVector3f Vector = pVector->Get();
if (rkIndex.row() == 0) Value = Vector.X;
if (rkIndex.row() == 1) Value = Vector.Y;
if (rkIndex.row() == 2) Value = Vector.Z;
}
else if (pProp->Type() == eColorProperty)
{
TColorProperty *pColor = static_cast<TColorProperty*>(pProp);
CColor Color = pColor->Get();
if (rkIndex.row() == 0) Value = Color.R;
if (rkIndex.row() == 1) Value = Color.G;
if (rkIndex.row() == 2) Value = Color.B;
if (rkIndex.row() == 3) Value = Color.A;
}
pSpinBox->setValue((double) Value);
}
}
}
}
@ -391,20 +354,26 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
if (!mpModel) return;
if (!pEditor) return;
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false);
IPropertyValue *pOldValue = nullptr;
//FIXME
/* IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false);
bool HadEditInProgress = mEditInProgress;
mEditInProgress = mInRelayWidgetEdit && (pEditor->hasFocus() || pProp->Type() == EPropertyTypeNew::Color);
bool EditJustFinished = (!mEditInProgress && HadEditInProgress);
bool Matches = false;
IUndoCommand* pCommand = nullptr;
if (pProp)
{
IPropertyValue *pRawValue = pProp->RawValue();
pOldValue = pRawValue ? pRawValue->Clone() : nullptr;
switch (pProp->Type())
{
case eBoolProperty:
case EPropertyTypeNew::Bool:
{
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
bool NewValue =
pCommand = new TEditScriptPropertyCommand<CBoolProperty>(pProp, mpModel->GetScriptObject(), mpEditor, pCheckBox->isChecked(),
bool NewValue = TEditScriptPropertyCommand<CBoolProperty>(pProp,
TBoolProperty *pBool = static_cast<TBoolProperty*>(pProp);
pBool->Set(pCheckBox->isChecked());
break;
@ -567,7 +536,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
else
delete pOldValue;
}
}*/
}
bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
@ -589,7 +558,8 @@ bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent)
// Character properties have separate functions because they're somewhat complicated - they have different layouts in different games
QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const
{
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true));
//FIXME
/* TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pProp->Get();
// Determine property type
@ -632,13 +602,15 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
return pSpinBox;
}
}*/
return nullptr;
}
void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const
{
//FIXME
/*
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pProp->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
@ -659,12 +631,15 @@ void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelInd
u32 Value = Params.Unknown(UnkIndex);
static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value);
}
*/
}
void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const
{
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pProp->Get();
//FIXME
/*
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pAnimSet->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
if (Type == eAssetProperty)
@ -693,27 +668,28 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
QModelIndex ParentIndex = rkIndex.parent();
mpModel->dataChanged(mpModel->index(1, 1, ParentIndex), mpModel->index(mpModel->rowCount(ParentIndex) - 1, 1, ParentIndex));
}
*/
}
EPropertyType CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const
EPropertyTypeNew CPropertyDelegate::DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const
{
if (Game <= eEchoes)
{
if (rkIndex.row() == 0) return eAssetProperty;
else if (rkIndex.row() == 1) return eEnumProperty;
else if (rkIndex.row() == 2) return eLongProperty;
if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() == 1) return EPropertyTypeNew::Choice;
else if (rkIndex.row() == 2) return EPropertyTypeNew::Int;
}
else if (Game <= eCorruption)
{
if (rkIndex.row() == 0) return eAssetProperty;
else if (rkIndex.row() == 1) return eLongProperty;
if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() == 1) return EPropertyTypeNew::Int;
}
else
{
if (rkIndex.row() == 0) return eAssetProperty;
else if (rkIndex.row() <= 2) return eLongProperty;
if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() <= 2) return EPropertyTypeNew::Int;
}
return eUnknownProperty;
return EPropertyTypeNew::Invalid;
}
// ************ PUBLIC SLOTS ************

View File

@ -28,7 +28,7 @@ public:
QWidget* CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const;
void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const;
void SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const;
EPropertyType DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const;
EPropertyTypeNew DetermineCharacterPropType(EGame Game, const QModelIndex& rkIndex) const;
public slots:
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);

View File

@ -8,77 +8,111 @@
CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/)
: QAbstractItemModel(pParent)
, mpBaseStruct(nullptr)
, mpProject(nullptr)
, mpRootProperty(nullptr)
, mpPropertyData(nullptr)
, mBoldModifiedProperties(true)
, mShowNameValidity(false)
{
}
void CPropertyModel::SetBaseStruct(CPropertyStruct *pBaseStruct)
int CPropertyModel::RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID)
{
mProperties << SProperty();
SProperty& Property = mProperties.back();
Property.pProperty = pProperty;
Property.ParentID = ParentID;
int MyID = mProperties.size() - 1;
int RowNumber = (ParentID >= 0 ? mProperties[ParentID].ChildIDs.size() : 0);
Property.Index = createIndex(RowNumber, 0, pProperty);
if (pProperty->Type() == EPropertyTypeNew::Array)
{
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProperty);
for (u32 ElementIdx = 0; ElementIdx < pArray->ArrayCount(mpPropertyData); ElementIdx++)
{
int NewChildID = RecursiveBuildArrays( pArray->Archetype(), MyID );
Property.ChildIDs.push_back(NewChildID);
}
}
else
{
for (u32 ChildIdx = 0; ChildIdx < pProperty->NumChildren(); ChildIdx++)
{
int NewChildID = RecursiveBuildArrays( pProperty->ChildByIndex(ChildIdx), MyID );
Property.ChildIDs.push_back(NewChildID);
}
}
if (!pProperty->IsArrayArchetype())
{
mPropertyToIDMap[pProperty] = MyID;
}
return MyID;
}
void CPropertyModel::ConfigureIntrinsic(CGameProject* pProject, IPropertyNew* pRootProperty, void* pPropertyData)
{
beginResetModel();
mpBaseStruct = pBaseStruct;
mpProject = pProject;
mpObject = nullptr;
mpRootProperty = pRootProperty;
mpPropertyData = pPropertyData;
mProperties.clear();
mPropertyToIDMap.clear();
if (pRootProperty)
RecursiveBuildArrays(pRootProperty, -1);
endResetModel();
}
IProperty* CPropertyModel::PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const
void CPropertyModel::ConfigureScript(CGameProject* pProject, IPropertyNew* pRootProperty, CScriptObject* pObject)
{
if (!rkIndex.isValid()) return mpBaseStruct;
ConfigureIntrinsic(pProject, pRootProperty, pObject);
mpObject = pObject;
}
if (rkIndex.internalId() & 0x1)
IPropertyNew* CPropertyModel::PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedIndices) const
{
if (!rkIndex.isValid()) return mpRootProperty;
int Index = rkIndex.internalId();
if (Index & 0x80000000)
{
if (HandleFlaggedPointers)
{
void *pID = (void*) (rkIndex.internalId() & ~0x1);
return static_cast<IProperty*>(pID);
}
if (HandleFlaggedIndices)
Index &= ~0x80000000;
else
return nullptr;
}
return static_cast<IProperty*>(rkIndex.internalPointer());
return mProperties[Index].pProperty;
}
QModelIndex CPropertyModel::IndexForProperty(IProperty *pProp) const
QModelIndex CPropertyModel::IndexForProperty(IPropertyNew *pProp) const
{
if (pProp == mpBaseStruct) return QModelIndex();
QVector<u32> RowNumbers;
IProperty *pChild = pProp;
CPropertyStruct *pParent = pProp->Parent();
while (pParent)
// Array archetype properties cannot be associated with a single index because the same IProperty
// is used for every element of the array. So instead fetch the index for the array itself.
if (pProp->IsArrayArchetype())
{
// Check for array with one sub-property
CPropertyStruct *pGrandparent = pParent->Parent();
if (pGrandparent && pGrandparent->Type() == eArrayProperty && pParent->Count() == 1)
{
pChild = pParent;
pParent = pGrandparent;
continue;
}
while (pProp && pProp->IsArrayArchetype())
pProp = pProp->Parent();
// Find row index for this child property
for (u32 iChild = 0; iChild < pParent->Count(); iChild++)
{
if (pParent->PropertyByIndex(iChild) == pChild)
{
RowNumbers << iChild;
break;
}
}
pChild = pParent;
pParent = pGrandparent;
ASSERT(pProp != nullptr && pProp->Type() == EPropertyTypeNew::Array);
}
// Find the corresponding QModelIndex in the same spot
QModelIndex Index = QModelIndex();
if (pProp == mpRootProperty) return QModelIndex();
for (int iChild = RowNumbers.size() - 1; iChild >= 0; iChild--)
Index = index(RowNumbers[iChild], 0, Index);
int ID = mPropertyToIDMap[pProp];
ASSERT(ID >= 0);
return Index;
return mProperties[ID].Index;
}
int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const
@ -88,38 +122,30 @@ int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const
int CPropertyModel::rowCount(const QModelIndex& rkParent) const
{
if (!mpBaseStruct) return 0;
if (!rkParent.isValid()) return mpBaseStruct->Count();
if (!mpRootProperty) return 0;
if (!rkParent.isValid()) return mpRootProperty->NumChildren();
if (rkParent.column() != 0) return 0;
if (rkParent.internalId() & 0x1) return 0;
if (rkParent.internalId() & 0x80000000) return 0;
IProperty *pProp = PropertyForIndex(rkParent, false);
IPropertyNew *pProp = PropertyForIndex(rkParent, false);
int ID = mPropertyToIDMap[pProp];
switch (pProp->Type())
{
case eStructProperty:
case eArrayProperty:
return static_cast<CPropertyStruct*>(pProp)->Count();
case EPropertyTypeNew::Flags:
return TPropCast<CFlagsProperty>(pProp)->NumFlags();
case eBitfieldProperty:
return static_cast<CBitfieldTemplate*>(pProp->Template())->NumFlags();
case eVector3Property:
return 3;
case eColorProperty:
return 4;
case eCharacterProperty:
case EPropertyTypeNew::AnimationSet:
{
CAnimationParameters Params = static_cast<TCharacterProperty*>(pProp)->Get();
CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(mpPropertyData);
if (Params.Version() <= eEchoes) return 3;
if (Params.Version() <= eCorruption) return 2;
return 4;
}
default:
return 0;
return mProperties[ID].ChildIDs.size();
}
}
@ -142,73 +168,29 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
{
if (rkIndex.internalId() & 0x1)
{
IProperty *pProp = PropertyForIndex(rkIndex, true);
IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
EPropertyTypeNew Type = pProp->Type();
if (pProp->Type() == eColorProperty)
if (Type == EPropertyTypeNew::Flags)
{
if (rkIndex.column() == 0)
{
if (rkIndex.row() == 0) return "R";
if (rkIndex.row() == 1) return "G";
if (rkIndex.row() == 2) return "B";
if (rkIndex.row() == 3) return "A";
}
else if (rkIndex.column() == 1)
{
TStringList Strings = pProp->ToString().Split(" ,");
int i = 0;
for (auto it = Strings.begin(); it != Strings.end(); it++)
{
if (i == rkIndex.row()) return TO_QSTRING(*it);
i++;
}
}
}
else if (pProp->Type() == eVector3Property)
{
if (rkIndex.column() == 0)
{
if (rkIndex.row() == 0) return "X";
if (rkIndex.row() == 1) return "Y";
if (rkIndex.row() == 2) return "Z";
}
else if (rkIndex.column() == 1)
{
TStringList Strings = pProp->ToString().Split(" ,");
int i = 0;
for (auto it = Strings.begin(); it != Strings.end(); it++)
{
if (i == rkIndex.row()) return TO_QSTRING(*it);
i++;
}
}
}
else if (pProp->Type() == eBitfieldProperty)
{
CBitfieldTemplate *pBitfield = static_cast<CBitfieldTemplate*>(pProp->Template());
CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
if (rkIndex.column() == 0)
return TO_QSTRING(pBitfield->FlagName(rkIndex.row()));
return TO_QSTRING( pFlags->FlagName(rkIndex.row()) );
if (rkIndex.column() == 1)
{
if (Role == Qt::DisplayRole)
return "";
else
return TO_QSTRING(TString::HexString(pBitfield->FlagMask(rkIndex.row())));
return TO_QSTRING(TString::HexString( pFlags->FlagMask(rkIndex.row())));
}
}
else if (pProp->Type() == eCharacterProperty)
else if (Type == EPropertyTypeNew::AnimationSet)
{
TCharacterProperty *pChar = static_cast<TCharacterProperty*>(pProp);
CAnimationParameters Params = pChar->Get();
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
CAnimationParameters Params = pAnimSet->Value(mpPropertyData);
// There are three different layouts for this property - one for MP1/2, one for MP3, and one for DKCR
if (Params.Version() <= eEchoes)
@ -255,28 +237,18 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
else
{
IProperty *pProp = PropertyForIndex(rkIndex, false);
IPropertyNew *pProp = PropertyForIndex(rkIndex, false);
if (rkIndex.column() == 0)
{
// Check for arrays
IProperty *pParent = pProp->Parent();
IPropertyNew *pParent = pProp->Parent();
if (pParent)
if (pParent && pParent->Type() == EPropertyTypeNew::Array)
{
// For direct array sub-properties, display the element name instead of the property name (the property name is the array name)
if (pProp->Type() == eStructProperty && pParent->Type() == eArrayProperty)
{
TString ElementName = static_cast<CArrayProperty*>(pParent)->ElementName();
return QString("%1 %2").arg(TO_QSTRING(ElementName)).arg(rkIndex.row() + 1);
}
// Check whether the parent struct is an array element with one sub-property
if (pParent->Type() == eStructProperty && pParent->Parent() && pParent->Parent()->Type() == eArrayProperty)
{
if (static_cast<CPropertyStruct*>(pParent)->Count() == 1)
return QString("%1 %2").arg(TO_QSTRING(pProp->Name())).arg(rkIndex.row() + 1);
}
// For direct array sub-properties, display the element index after the name
TString ElementName = pParent->Name();
return QString("%1 %2").arg( TO_QSTRING(ElementName) ).arg(rkIndex.row() + 1);
}
// Display property name for everything else
@ -288,19 +260,20 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
switch (pProp->Type())
{
// Enclose vector property text in parentheses
case eVector3Property:
return "(" + TO_QSTRING(pProp->ToString()) + ")";
case EPropertyTypeNew::Vector:
{
CVector3f Value = TPropCast<CVectorProperty>(pProp)->Value(mpPropertyData);
return TO_QSTRING("(" + Value.ToString() + ")");
}
// Display the AGSC/sound name for sounds
case eSoundProperty:
case EPropertyTypeNew::Sound:
{
TSoundProperty *pSound = static_cast<TSoundProperty*>(pProp);
u32 SoundID = pSound->Get();
CSoundProperty* pSound = TPropCast<CSoundProperty>(pProp);
u32 SoundID = pSound->Value(mpPropertyData);
if (SoundID == -1) return "[None]";
CGameProject *pProj = pSound->Instance()->Area()->Entry()->Project();
SSoundInfo SoundInfo = pProj->AudioManager()->GetSoundInfo(SoundID);
SSoundInfo SoundInfo = mpProject->AudioManager()->GetSoundInfo(SoundID);
QString Out = QString::number(SoundID);
if (SoundInfo.DefineID == -1)
@ -320,40 +293,47 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
}
// Display character name for characters
case eCharacterProperty:
return TO_QSTRING(static_cast<TCharacterProperty*>(pProp)->Get().GetCurrentCharacterName());
case EPropertyTypeNew::AnimationSet:
return TO_QSTRING(TPropCast<CAnimationSetProperty>(pProp)->Value(mpPropertyData).GetCurrentCharacterName());
// Display enumerator name for enums (but only on ToolTipRole)
case eEnumProperty:
case EPropertyTypeNew::Choice:
case EPropertyTypeNew::Enum:
if (Role == Qt::ToolTipRole)
{
TEnumProperty *pEnum = static_cast<TEnumProperty*>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pEnum->Template());
return TO_QSTRING(pTemp->EnumeratorName( pTemp->EnumeratorIndex(pEnum->Get()) ));
CEnumProperty *pEnum = TPropCast<CEnumProperty>(pProp);
u32 ValueID = pEnum->Value(mpPropertyData);
u32 ValueIndex = pEnum->ValueIndex(ValueID);
return TO_QSTRING( pEnum->ValueName(ValueIndex) );
}
else return "";
// Display the element count for arrays
case eArrayProperty:
case EPropertyTypeNew::Array:
{
u32 Count = static_cast<CArrayProperty*>(pProp)->Count();
u32 Count = TPropCast<CArrayProperty>(pProp)->Value(mpPropertyData);
return QString("%1 element%2").arg(Count).arg(Count != 1 ? "s" : "");
}
// Display "[MayaSpline]" for MayaSplines (todo: proper support)
case eMayaSplineProperty:
return "[MayaSpline]";
// Display "[spline]" for splines (todo: proper support)
case EPropertyTypeNew::Spline:
return "[spline]";
// No display text on properties with persistent editors
case eBoolProperty:
case eAssetProperty:
case eColorProperty:
case EPropertyTypeNew::Bool:
if (Role == Qt::DisplayRole)
return TPropCast<CBoolProperty>(pProp)->Value(mpPropertyData) ? "True" : "False";
else
return "";
case EPropertyTypeNew::Asset:
case EPropertyTypeNew::Color:
if (Role == Qt::DisplayRole)
return "";
// fall through
// Display property value to string for everything else
default:
return TO_QSTRING(pProp->ToString() + pProp->Template()->Suffix());
return TO_QSTRING(pProp->ValueAsString(mpPropertyData) + pProp->Suffix());
}
}
}
@ -364,23 +344,23 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (!(rkIndex.internalId() & 0x1))
{
// Add name
IProperty *pProp = PropertyForIndex(rkIndex, false);
IPropertyNew *pProp = PropertyForIndex(rkIndex, false);
QString DisplayText = data(rkIndex, Qt::DisplayRole).toString();
QString Text = QString("<b>%1</b> <i>(%2)</i>").arg(DisplayText).arg(TO_QSTRING(PropEnumToPropString(pProp->Type())));
// Add uncooked notification
if (pProp->Template()->CookPreference() == eNeverCook)
if (pProp->CookPreference() == ECookPreferenceNew::Never)
{
Text.prepend("<i>[uncooked]</i>");
}
// Add description
TString Desc = pProp->Template()->Description();
TString Desc = pProp->Description();
if (!Desc.IsEmpty()) Text += "<br/>" + TO_QSTRING(Desc);
// MayaSpline notification
if (pProp->Type() == eMayaSplineProperty)
Text += "<br/><i>(NOTE: MayaSpline properties are currently unsupported for editing)</i>";
// Spline notification
if (pProp->Type() == EPropertyTypeNew::Spline)
Text += "<br/><i>(NOTE: Spline properties are currently unsupported for editing)</i>";
return Text;
}
@ -393,45 +373,12 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (mBoldModifiedProperties)
{
IProperty *pProp = PropertyForIndex(rkIndex, true);
IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
if (!pProp->IsInArray())
if (!pProp->IsArrayArchetype())
{
if (rkIndex.internalId() & 0x1)
{
if (pProp->Type() == eVector3Property)
{
TVector3Property *pVec = static_cast<TVector3Property*>(pProp);
TVector3Template *pTemp = static_cast<TVector3Template*>(pProp->Template());
CVector3f Value = pVec->Get();
CVector3f Default = pTemp->GetDefaultValue();
if (rkIndex.row() == 0) Bold = (Value.X != Default.X);
if (rkIndex.row() == 1) Bold = (Value.Y != Default.Y);
if (rkIndex.row() == 2) Bold = (Value.Z != Default.Z);
}
else if (pProp->Type() == eColorProperty)
{
TColorProperty *pColor = static_cast<TColorProperty*>(pProp);
TColorTemplate *pTemp = static_cast<TColorTemplate*>(pProp->Template());
CColor Value = pColor->Get();
CColor Default = pTemp->GetDefaultValue();
if (rkIndex.row() == 0) Bold = (Value.R != Default.R);
if (rkIndex.row() == 1) Bold = (Value.G != Default.G);
if (rkIndex.row() == 2) Bold = (Value.B != Default.B);
if (rkIndex.row() == 3) Bold = (Value.A != Default.A);
}
}
else
{
Bold = !pProp->MatchesDefault();
}
}
Bold = !pProp->MatchesDefault(mpPropertyData);
}
}
Font.setBold(Bold);
@ -445,17 +392,16 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (Role == Qt::ForegroundRole)
{
if (mShowNameValidity && mpBaseStruct->Template()->Game() >= eEchoesDemo)
if (mShowNameValidity && mpRootProperty->ScriptTemplate()->Game() >= eEchoesDemo)
{
IProperty *pProp = PropertyForIndex(rkIndex, true);
IPropertyTemplate *pTemp = (pProp ? pProp->Template() : nullptr);
IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
// Don't highlight the name of the root property
if (pTemp && pTemp->Parent() != nullptr)
if (pProp && pProp->Parent() != nullptr && !pProp->IsArrayArchetype())
{
static const QColor skRightColor = QColor(128, 255, 128);
static const QColor skWrongColor = QColor(255, 128, 128);
return QBrush( pTemp->IsNameCorrect() ? skRightColor : skWrongColor );
return QBrush( pProp->HasAccurateName() ? skRightColor : skWrongColor );
}
}
}
@ -470,33 +416,19 @@ QModelIndex CPropertyModel::index(int Row, int Column, const QModelIndex& rkPare
return QModelIndex();
// Check property for children
IProperty *pParent = (rkParent.isValid() ? PropertyForIndex(rkParent, false) : mpBaseStruct);
IPropertyNew* pParent = (rkParent.isValid() ? PropertyForIndex(rkParent, false) : mpRootProperty);
EPropertyTypeNew ParentType = pParent->Type();
int ParentID = mPropertyToIDMap[pParent];
// Struct
if (pParent->Type() == eStructProperty)
if (ParentType == EPropertyTypeNew::Flags || ParentType == EPropertyTypeNew::AnimationSet)
{
IProperty *pProp = static_cast<CPropertyStruct*>(pParent)->PropertyByIndex(Row);
return createIndex(Row, Column, pProp);
return createIndex(Row, Column, ParentID | 0x80000000);
}
// Array
if (pParent->Type() == eArrayProperty)
else
{
IProperty *pProp = static_cast<CArrayProperty*>(pParent)->PropertyByIndex(Row);
// If this array element only has one sub-property then let's just skip the redundant tree node and show the sub-property directly.
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pProp);
if (pStruct->Count() == 1)
pProp = pStruct->PropertyByIndex(0);
return createIndex(Row, Column, pProp);
int ChildID = mProperties[ParentID].ChildIDs[Row];
return createIndex(Row, Column, ChildID);
}
// Other property
if (pParent->Type() == eColorProperty || pParent->Type() == eVector3Property || pParent->Type() == eBitfieldProperty || pParent->Type() == eCharacterProperty)
return createIndex(Row, Column, u64(pParent) | 0x1);
return QModelIndex();
}
QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
@ -505,39 +437,14 @@ QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
if (!rkChild.isValid())
return QModelIndex();
// Find parent property
IProperty *pParent;
int ID = int(rkChild.internalId());
if (rkChild.internalId() & 0x1)
pParent = PropertyForIndex(rkChild, true);
if (ID & 0x80000000)
ID &= ~0x80000000;
else
pParent = PropertyForIndex(rkChild, false)->Parent();
ID = mProperties[ID].ParentID;
if (pParent == mpBaseStruct)
return QModelIndex();
// Iterate over grandfather properties until we find the row
CPropertyStruct *pGrandparent = pParent->Parent();
// Check for array with one sub-property
if (pGrandparent->Type() == eArrayProperty)
{
CPropertyStruct *pStruct = static_cast<CPropertyStruct*>(pParent);
if (pStruct->Count() == 1)
{
pParent = pGrandparent;
pGrandparent = pGrandparent->Parent();
}
}
for (u32 iProp = 0; iProp < pGrandparent->Count(); iProp++)
{
if (pGrandparent->PropertyByIndex(iProp) == pParent)
return createIndex(iProp, 0, pParent);
}
return QModelIndex();
return mProperties[ID].Index;
}
Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const
@ -546,7 +453,7 @@ Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const
else return (Qt::ItemIsEnabled | Qt::ItemIsEditable);
}
void CPropertyModel::NotifyPropertyModified(class CScriptObject*, IProperty *pProp)
void CPropertyModel::NotifyPropertyModified(class CScriptObject*, IPropertyNew* pProp)
{
NotifyPropertyModified(IndexForProperty(pProp));
}
@ -556,7 +463,7 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
if (rowCount(rkIndex) != 0)
emit dataChanged( index(0, 0, rkIndex), index(rowCount(rkIndex) - 1, 1, rkIndex));
if (rkIndex.internalId() & 0x1)
if (rkIndex.internalId() & 0x80000000)
{
QModelIndex Parent = rkIndex.parent();
QModelIndex Col0 = Parent.sibling(Parent.row(), 0);
@ -573,7 +480,8 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSize)
{
QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
//FIXME
/*QModelIndex Index = rkIndex.sibling(rkIndex.row(), 0);
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(Index, false));
if (pArray && pArray->Type() == eArrayProperty)
@ -587,12 +495,13 @@ void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSi
else
beginRemoveRows(Index, NewSize, OldSize - 1);
}
}
}*/
}
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
{
CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
//FIXME
/*CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(rkIndex, false));
u32 NewSize = pArray->Count();
if (NewSize != OldSize)
@ -601,7 +510,7 @@ void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
endInsertRows();
else
endRemoveRows();
}
}*/
}
void CPropertyModel::SetShowPropertyNameValidity(bool Enable)

View File

@ -1,24 +1,41 @@
#ifndef CPROPERTYMODEL_H
#define CPROPERTYMODEL_H
#include <Core/Resource/Script/Property/Properties.h>
#include <QAbstractItemModel>
#include <Core/Resource/Script/IProperty.h>
#include <QFont>
class CPropertyModel : public QAbstractItemModel
{
Q_OBJECT
CPropertyStruct *mpBaseStruct;
struct SProperty
{
IPropertyNew* pProperty;
QModelIndex Index;
int ParentID;
std::vector<int> ChildIDs;
};
QVector<SProperty> mProperties;
QMap<IPropertyNew*, int> mPropertyToIDMap;
CGameProject* mpProject;
CScriptObject* mpObject; // may be null
IPropertyNew* mpRootProperty;
void* mpPropertyData;
bool mBoldModifiedProperties;
bool mShowNameValidity;
QFont mFont;
int RecursiveBuildArrays(IPropertyNew* pProperty, int ParentID);
public:
CPropertyModel(QObject *pParent = 0);
void SetBaseStruct(CPropertyStruct *pBaseStruct);
IProperty* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedPointers) const;
QModelIndex IndexForProperty(IProperty *pProp) const;
void ConfigureIntrinsic(CGameProject* pProject, IPropertyNew* pRootProperty, void* pPropertyData);
void ConfigureScript(CGameProject* pProject, IPropertyNew* pRootProperty, CScriptObject* pObject);
IPropertyNew* PropertyForIndex(const QModelIndex& rkIndex, bool HandleFlaggedIndices) const;
QModelIndex IndexForProperty(IPropertyNew *pProp) const;
int columnCount(const QModelIndex& rkParent) const;
int rowCount(const QModelIndex& rkParent) const;
@ -36,9 +53,11 @@ public:
inline void SetFont(QFont Font) { mFont = Font; }
inline void SetBoldModifiedProperties(bool Enable) { mBoldModifiedProperties = Enable; }
inline void* GetPropertyData() const { return mpPropertyData; }
inline CScriptObject* GetScriptObject() const { return mpObject; }
public slots:
void NotifyPropertyModified(class CScriptObject *pInst, IProperty *pProp);
void NotifyPropertyModified(class CScriptObject *pInst, IPropertyNew *pProp);
void NotifyPropertyModified(const QModelIndex& rkIndex);
signals:

Some files were not shown because too many files have changed in this diff Show More