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 # CONFIG += PUBLIC_RELEASE
win32: { win32: {
QMAKE_CXXFLAGS += /WX \ # Treat warnings as errors QMAKE_CXXFLAGS += /WX \ # Treat warnings as errors
/wd4267 # Disable C4267: conversion from 'size_t' to 'type', possible loss of data /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 BUILD_DIR = $$PWD/../build

View File

@ -1,6 +1,7 @@
#ifndef COMMON_H #ifndef COMMON_H
#define COMMON_H #define COMMON_H
#include "types.h"
#include "AssertMacro.h" #include "AssertMacro.h"
#include "CAssetID.h" #include "CAssetID.h"
#include "CColor.h" #include "CColor.h"
@ -15,10 +16,13 @@
#include "Flags.h" #include "Flags.h"
#include "Log.h" #include "Log.h"
#include "TString.h" #include "TString.h"
#include "types.h"
#include "Hash/CCRC32.h" #include "Hash/CCRC32.h"
#include "Hash/CFNV1A.h" #include "Hash/CFNV1A.h"
#include "Serialization/Binary.h" #include "Serialization/Binary.h"
#include "Serialization/XML.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 #endif // COMMON_H

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@ public:
TFlags() : mValue(0) {} TFlags() : mValue(0) {}
TFlags(int Val) : mValue(Val) {} TFlags(int Val) : mValue(Val) {}
TFlags(u32 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 operator int() const { return mValue; }
inline bool operator!() const { return !mValue; } inline bool operator!() const { return !mValue; }
@ -22,25 +22,41 @@ public:
inline void operator&=(int Mask) { mValue &= Mask; } inline void operator&=(int Mask) { mValue &= Mask; }
inline void operator&=(u32 Mask) { mValue &= Mask; } inline void operator&=(u32 Mask) { mValue &= Mask; }
inline void operator|=(TFlags Flags) { mValue |= Flags.mValue; } 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|(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&(int Mask) const { return TFlags(FlagEnum(mValue & Mask)); }
inline TFlags operator&(u32 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 HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); }
inline bool HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); } 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 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 ClearFlag(TFlags Flags) { mValue &= ~Flags; }
inline void Serialize(IArchive& rArc) { rArc.SerializeHexPrimitive(mValue); } inline void Serialize(IArchive& rArc) { rArc.SerializeHexPrimitive(mValue); }
}; };
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName; #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 #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); 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() ~CBasicBinaryReader()
{ {
if (mOwnsStream) delete mpStream; if (mOwnsStream) delete mpStream;
@ -74,6 +83,8 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); } virtual void SerializeHexPrimitive(u16& rValue) { rValue = mpStream->ReadShort(); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); } virtual void SerializeHexPrimitive(u32& rValue) { rValue = mpStream->ReadLong(); }
virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); } virtual void SerializeHexPrimitive(u64& rValue) { rValue = mpStream->ReadLongLong(); }
virtual void BulkSerialize(void* pData, u32 Size) { mpStream->ReadBytes(pData, Size); }
}; };
#endif // CBASICBINARYREADER #endif // CBASICBINARYREADER

View File

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

View File

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

View File

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

View File

@ -135,6 +135,19 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(16); } virtual void SerializeHexPrimitive(u16& rValue) { rValue = (u16) ReadParam().ToInt32(16); }
virtual void SerializeHexPrimitive(u32& rValue) { rValue = (u32) 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 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 #endif // CXMLREADER

View File

@ -122,6 +122,17 @@ public:
virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); } virtual void SerializeHexPrimitive(u16& rValue) { WriteParam(*TString::HexString(rValue, 4)); }
virtual void SerializeHexPrimitive(u32& rValue) { WriteParam(*TString::HexString(rValue, 8)); } virtual void SerializeHexPrimitive(u32& rValue) { WriteParam(*TString::HexString(rValue, 8)); }
virtual void SerializeHexPrimitive(u64& rValue) { WriteParam(*TString::HexString((u32) rValue, 16)); } 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 #endif // CXMLWRITER

View File

@ -404,6 +404,21 @@ public:
virtual void SerializeHexPrimitive(u32& rValue) = 0; virtual void SerializeHexPrimitive(u32& rValue) = 0;
virtual void SerializeHexPrimitive(u64& 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 // Accessors
inline u16 ArchiveVersion() const { return mArchiveVersion; } inline u16 ArchiveVersion() const { return mArchiveVersion; }
inline u16 FileVersion() const { return mFileVersion; } inline u16 FileVersion() const { return mFileVersion; }

View File

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

View File

@ -932,46 +932,7 @@ public:
static _TString FromFloat(float Value, int MinDecimals = 1) static _TString FromFloat(float Value, int MinDecimals = 1)
{ {
// Initial float -> string conversion return Format("%f.*", Value, MinDecimals);
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;
} }
static _TString FileSizeString(u64 Size, u32 NumDecimals = 2) static _TString FileSizeString(u64 Size, u32 NumDecimals = 2)

View File

@ -13,48 +13,30 @@ CAreaAttributes::~CAreaAttributes()
void CAreaAttributes::SetObject(CScriptObject *pObj) void CAreaAttributes::SetObject(CScriptObject *pObj)
{ {
mpObj = pObj; CScriptTemplate* pTemplate = pObj->Template();
mGame = pObj->Template()->MasterTemplate()->Game(); 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 bool CAreaAttributes::IsLayerEnabled() const
{ {
return mpObj->Layer()->IsActive(); return mpObject->Layer()->IsActive();
} }
bool CAreaAttributes::IsSkyEnabled() const bool CAreaAttributes::IsSkyEnabled() const
{ {
CPropertyStruct *pBaseStruct = mpObj->Properties(); return mNeedSky.IsValid() ? mNeedSky.Get() : false;
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;
}
} }
CModel* CAreaAttributes::SkyModel() const CModel* CAreaAttributes::SkyModel() const
{ {
CPropertyStruct *pBaseStruct = mpObj->Properties(); return mOverrideSky.IsValid() ? gpResourceStore->LoadResource<CModel>(mOverrideSky.Get()) : nullptr;
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;
}
} }

View File

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

View File

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

View File

@ -232,7 +232,31 @@ HEADERS += \
IUIRelay.h \ IUIRelay.h \
Resource/CResTypeFilter.h \ Resource/CResTypeFilter.h \
GameProject/COpeningBanner.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 # Source Files
SOURCES += \ SOURCES += \
@ -342,4 +366,5 @@ SOURCES += \
IUIRelay.cpp \ IUIRelay.cpp \
GameProject\COpeningBanner.cpp \ GameProject\COpeningBanner.cpp \
IProgressNotifier.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++) 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')) if (pInst->ObjectTypeID() == 0x42 || pInst->ObjectTypeID() == FOURCC('POIN'))
{ {
@ -292,12 +293,12 @@ void GenerateAssetNames(CGameProject *pProj)
if (Name.StartsWith("POI_", false)) if (Name.StartsWith("POI_", false))
{ {
TIDString ScanIDString = (pProj->Game() <= ePrime ? "0x4:0x0" : "0xBDBEC295:0xB94E9BE7"); 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 ASSERT(pScanProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pScanProperty) if (pScanProperty)
{ {
CAssetID ScanID = pScanProperty->Get(); CAssetID ScanID = pScanProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(ScanID); CResourceEntry *pEntry = pStore->FindEntry(ScanID);
if (pEntry && !pEntry->IsNamed()) if (pEntry && !pEntry->IsNamed())
@ -327,12 +328,12 @@ void GenerateAssetNames(CGameProject *pProj)
if (Name.EndsWith(".STRG", false)) if (Name.EndsWith(".STRG", false))
{ {
u32 StringPropID = (pProj->Game() <= ePrime ? 0x4 : 0x9182250C); 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 ASSERT(pStringProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pStringProperty) if (pStringProperty)
{ {
CAssetID StringID = pStringProperty->Get(); CAssetID StringID = pStringProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(StringID); CResourceEntry *pEntry = pStore->FindEntry(StringID);
if (pEntry && !pEntry->IsNamed()) if (pEntry && !pEntry->IsNamed())
@ -353,12 +354,12 @@ void GenerateAssetNames(CGameProject *pProj)
pInst->ObjectTypeID() == 0x8 || pInst->ObjectTypeID() == FOURCC('PLAT')) pInst->ObjectTypeID() == 0x8 || pInst->ObjectTypeID() == FOURCC('PLAT'))
{ {
u32 ModelPropID = (pProj->Game() <= ePrime ? (pInst->ObjectTypeID() == 0x0 ? 0xA : 0x6) : 0xC27FFA8F); 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 ASSERT(pModelProperty); // Temporary assert to remind myself later to update this code when uncooked properties are added to the template
if (pModelProperty) if (pModelProperty)
{ {
CAssetID ModelID = pModelProperty->Get(); CAssetID ModelID = pModelProperty->Value(pInst->PropertyData());
CResourceEntry *pEntry = pStore->FindEntry(ModelID); CResourceEntry *pEntry = pStore->FindEntry(ModelID);
if (pEntry && !pEntry->IsCategorized()) if (pEntry && !pEntry->IsCategorized())

View File

@ -132,28 +132,32 @@ CScriptInstanceDependency* CScriptInstanceDependency::BuildTree(CScriptObject *p
{ {
CScriptInstanceDependency *pInst = new CScriptInstanceDependency(); CScriptInstanceDependency *pInst = new CScriptInstanceDependency();
pInst->mObjectType = pInstance->ObjectTypeID(); pInst->mObjectType = pInstance->ObjectTypeID();
ParseStructDependencies(pInst, pInstance->Properties()); ParseStructDependencies(pInst, pInstance, pInstance->Template()->Properties());
return pInst; 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 // 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); IPropertyNew *pProp = pStruct->ChildByIndex(PropertyIdx);
EPropertyType Type = pProp->Type(); EPropertyTypeNew Type = pProp->Type();
if (Type == eStructProperty || Type == eArrayProperty) // Technically we aren't parsing array children, but it's not really worth refactoring this function
ParseStructDependencies(pInst, static_cast<CPropertyStruct*>(pProp)); // 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) if (SoundID != -1)
{ {
CGameProject *pProj = pStruct->Instance()->Area()->Entry()->Project(); CGameProject *pProj = pInstance->Area()->Entry()->Project();
SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID); SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID);
if (Info.pAudioGroup) 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()) 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 = TPropCast<CAnimationSetProperty>(pProp)->Value(pPropertyData);
CAnimationParameters Params = pChar->Get();
CAssetID ID = Params.ID(); CAssetID ID = Params.ID();
if (ID.IsValid()) if (ID.IsValid())
{ {
// Character sets are removed starting in MP3, so we only need char property dependencies in Echoes and earlier // 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()); CCharPropertyDependency *pDep = new CCharPropertyDependency(pProp->IDString(true), ID, Params.CharacterIndex());
pInst->mChildren.push_back(pDep); pInst->mChildren.push_back(pDep);

View File

@ -8,7 +8,7 @@
class CScriptLayer; class CScriptLayer;
class CScriptObject; class CScriptObject;
class CPropertyStruct; class CStructPropertyNew;
class CAnimSet; class CAnimSet;
class CAnimationParameters; class CAnimationParameters;
struct SSetCharacter; struct SSetCharacter;
@ -142,7 +142,7 @@ public:
// Static // Static
static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance); static CScriptInstanceDependency* BuildTree(CScriptObject *pInstance);
protected: 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. // 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*/) const SSetCharacter* CAnimationParameters::GetCurrentSetCharacter(s32 NodeIndex /*= -1*/)
{ {
CAnimSet *pSet = AnimSet(); CAnimSet *pSet = AnimSet();

View File

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

View File

@ -47,6 +47,12 @@ public:
SetAcceptedTypes(Game, rkString.Split(",")); 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 inline bool Accepts(EResType Type) const
{ {
return mAcceptedTypes.find(Type) != mAcceptedTypes.end(); return mAcceptedTypes.find(Type) != mAcceptedTypes.end();

View File

@ -4,9 +4,10 @@
std::unordered_map<EResType, CResTypeInfo*> CResTypeInfo::smTypeMap; 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) : mType(Type)
, mTypeName(rkTypeName) , mTypeName(rkTypeName)
, mRetroExtension(rkRetroExtension)
, mCanBeSerialized(false) , mCanBeSerialized(false)
, mCanHaveDependencies(true) , 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 ************ // ************ CREATION ************
CResTypeInfo::CResTypeInfoFactory CResTypeInfo::smTypeInfoFactory; CResTypeInfo::CResTypeInfoFactory CResTypeInfo::smTypeInfoFactory;
@ -153,235 +175,235 @@ void CResTypeInfo::CResTypeInfoFactory::AddExtension(CResTypeInfo *pType, CFourC
void CResTypeInfo::CResTypeInfoFactory::InitTypes() void CResTypeInfo::CResTypeInfoFactory::InitTypes()
{ {
{ {
CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation"); CResTypeInfo *pType = new CResTypeInfo(eAnimation, "Animation", "ani");
AddExtension(pType, "ANIM", ePrimeDemo, eReturns); 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); AddExtension(pType, "CPRM", eReturns, eReturns);
pType->mCanHaveDependencies = false; 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); 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); AddExtension(pType, "ANCS", ePrimeDemo, eEchoes);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eArea, "Area"); CResTypeInfo *pType = new CResTypeInfo(eArea, "Area", "mrea");
AddExtension(pType, "MREA", ePrimeDemo, eReturns); 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); 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); AddExtension(pType, "AGSC", ePrimeDemo, eEchoes);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro"); CResTypeInfo *pType = new CResTypeInfo(eAudioMacro, "Audio Macro", "caud");
AddExtension(pType, "CAUD", eCorruptionProto, eReturns); 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); AddExtension(pType, "CSMP", eCorruptionProto, eReturns);
pType->mCanHaveDependencies = false; 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); AddExtension(pType, "ATBL", ePrimeDemo, eCorruption);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data"); CResTypeInfo *pType = new CResTypeInfo(eBinaryData, "Generic Data", "dat");
AddExtension(pType, "DUMB", ePrimeDemo, eCorruption); 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); AddExtension(pType, "BFRC", eCorruptionProto, eCorruption);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character"); CResTypeInfo *pType = new CResTypeInfo(eCharacter, "Character", "char");
AddExtension(pType, "CHAR", eCorruptionProto, eReturns); AddExtension(pType, "CHAR", eCorruptionProto, eReturns);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group"); CResTypeInfo *pType = new CResTypeInfo(eDependencyGroup, "Dependency Group", "?");
AddExtension(pType, "DGRP", ePrimeDemo, eReturns); 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); AddExtension(pType, "DCLN", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eFont, "Font"); CResTypeInfo *pType = new CResTypeInfo(eFont, "Font", "rpff");
AddExtension(pType, "FONT", ePrimeDemo, eReturns); 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); AddExtension(pType, "FRME", ePrimeDemo, eReturns);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe"); CResTypeInfo *pType = new CResTypeInfo(eGuiKeyFrame, "Gui Keyframe", "?");
AddExtension(pType, "KFAM", ePrimeDemo, ePrimeDemo); 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); 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); 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); 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); AddExtension(pType, "MAPU", ePrimeDemo, eEchoes);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI"); CResTypeInfo *pType = new CResTypeInfo(eMidi, "MIDI", "?");
AddExtension(pType, "CSNG", ePrimeDemo, eEchoes); AddExtension(pType, "CSNG", ePrimeDemo, eEchoes);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eModel, "Model"); CResTypeInfo *pType = new CResTypeInfo(eModel, "Model", "cmdl");
AddExtension(pType, "CMDL", ePrimeDemo, eReturns); 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); 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); 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); 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); 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); 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); 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); 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); 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); 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); AddExtension(pType, "PATH", ePrimeDemo, eCorruption);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area"); CResTypeInfo *pType = new CResTypeInfo(ePortalArea, "Portal Area", "?");
AddExtension(pType, "PTLA", eEchoesDemo, eCorruption); AddExtension(pType, "PTLA", eEchoesDemo, eCorruption);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set"); CResTypeInfo *pType = new CResTypeInfo(eRuleSet, "Rule Set", "rule");
AddExtension(pType, "RULE", eEchoesDemo, eReturns); 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); AddExtension(pType, "SAVA", eCorruptionProto, eCorruption);
pType->mCanHaveDependencies = false; 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); AddExtension(pType, "SAVW", ePrime, eReturns);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan"); CResTypeInfo *pType = new CResTypeInfo(eScan, "Scan", "scan");
AddExtension(pType, "SCAN", ePrimeDemo, eCorruption); AddExtension(pType, "SCAN", ePrimeDemo, eCorruption);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton"); CResTypeInfo *pType = new CResTypeInfo(eSkeleton, "Skeleton", "cin");
AddExtension(pType, "CINF", ePrimeDemo, eReturns); AddExtension(pType, "CINF", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin"); CResTypeInfo *pType = new CResTypeInfo(eSkin, "Skin", "cskr");
AddExtension(pType, "CSKR", ePrimeDemo, eReturns); AddExtension(pType, "CSKR", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false; 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); AddExtension(pType, "SAND", eCorruptionProto, eCorruption);
pType->mCanHaveDependencies = false; // all dependencies are added to the CHAR dependency tree 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); AddExtension(pType, "CSPP", eEchoesDemo, eEchoes);
pType->mCanHaveDependencies = false; 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, "AFSM", ePrimeDemo, eEchoes);
AddExtension(pType, "FSM2", eCorruptionProto, eCorruption); AddExtension(pType, "FSM2", eCorruptionProto, eCorruption);
AddExtension(pType, "FSMC", eReturns, eReturns); 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); 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); AddExtension(pType, "EGMC", eEchoesDemo, eCorruption);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio"); CResTypeInfo *pType = new CResTypeInfo(eStreamedAudio, "Streamed Audio", "?");
AddExtension(pType, "STRM", eCorruptionProto, eReturns); AddExtension(pType, "STRM", eCorruptionProto, eReturns);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List"); CResTypeInfo *pType = new CResTypeInfo(eStringList, "String List", "stlc");
AddExtension(pType, "STLC", eEchoesDemo, eCorruptionProto); AddExtension(pType, "STLC", eEchoesDemo, eCorruptionProto);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table"); CResTypeInfo *pType = new CResTypeInfo(eStringTable, "String Table", "strg");
AddExtension(pType, "STRG", ePrimeDemo, eReturns); AddExtension(pType, "STRG", ePrimeDemo, eReturns);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture"); CResTypeInfo *pType = new CResTypeInfo(eTexture, "Texture", "txtr");
AddExtension(pType, "TXTR", ePrimeDemo, eReturns); AddExtension(pType, "TXTR", ePrimeDemo, eReturns);
pType->mCanHaveDependencies = false; pType->mCanHaveDependencies = false;
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data"); CResTypeInfo *pType = new CResTypeInfo(eTweak, "Tweak Data", "ctwk");
AddExtension(pType, "CTWK", ePrimeDemo, ePrime); AddExtension(pType, "CTWK", ePrimeDemo, ePrime);
pType->mCanHaveDependencies = false; 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); AddExtension(pType, "USRC", eCorruptionProto, eCorruption);
} }
{ {
CResTypeInfo *pType = new CResTypeInfo(eWorld, "World"); CResTypeInfo *pType = new CResTypeInfo(eWorld, "World", "mwld");
AddExtension(pType, "MLVL", ePrimeDemo, eReturns); AddExtension(pType, "MLVL", ePrimeDemo, eReturns);
pType->mCanBeSerialized = true; pType->mCanBeSerialized = true;
} }

View File

@ -20,13 +20,14 @@ class CResTypeInfo
EResType mType; EResType mType;
TString mTypeName; TString mTypeName;
std::vector<SGameExtension> mCookedExtensions; 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 mCanBeSerialized;
bool mCanHaveDependencies; bool mCanHaveDependencies;
static std::unordered_map<EResType, CResTypeInfo*> smTypeMap; static std::unordered_map<EResType, CResTypeInfo*> smTypeMap;
// Private Methods // Private Methods
CResTypeInfo(EResType Type, const TString& rkTypeName); CResTypeInfo(EResType Type, const TString& rkTypeName, const TString& rkRetroExtension);
~CResTypeInfo(); ~CResTypeInfo();
// Public Methods // Public Methods

View File

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

View File

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

View File

@ -1,9 +1,11 @@
#include "CTemplateWriter.h" #include "CTemplateWriter.h"
#include "CAreaCooker.h" #include "CAreaCooker.h"
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Core/Resource/Script/IPropertyTemplate.h>
#include <tinyxml2.h> #include <tinyxml2.h>
#if 0
using namespace tinyxml2; using namespace tinyxml2;
TString CTemplateWriter::smTemplatesDir = "../templates/"; TString CTemplateWriter::smTemplatesDir = "../templates/";
@ -802,9 +804,9 @@ void CTemplateWriter::SavePropertyOverrides(XMLDocument *pDoc, XMLElement *pPare
// Struct/array-specific parameters // Struct/array-specific parameters
else if (pProp->Type() == eStructProperty || pProp->Type() == eArrayProperty) 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); 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); pFlags->LinkEndChild(pElem);
} }
} }
#endif

View File

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

View File

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

View File

@ -2,256 +2,294 @@
#include "CTemplateLoader.h" #include "CTemplateLoader.h"
#include "Core/GameProject/CResourceStore.h" #include "Core/GameProject/CResourceStore.h"
#include "Core/Resource/Script/CMasterTemplate.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 <Common/Log.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
// Whether to ensure the values of enum/flag properties are valid
#define VALIDATE_PROPERTY_VALUES 1
CScriptLoader::CScriptLoader() CScriptLoader::CScriptLoader()
: mpObj(nullptr) : 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); CBoolProperty* pBool = TPropCast<CBoolProperty>(pProp);
pBoolCast->Set( (rSCLY.ReadByte() != 0) ); pBool->ValueRef(pData) = rSCLY.ReadBool();
break; break;
} }
case eByteProperty: case EPropertyTypeNew::Byte:
{ {
TByteProperty *pByteCast = static_cast<TByteProperty*>(pProp); CByteProperty* pByte = TPropCast<CByteProperty>(pProp);
pByteCast->Set(rSCLY.ReadByte()); pByte->ValueRef(pData) = rSCLY.ReadByte();
break; break;
} }
case eShortProperty: case EPropertyTypeNew::Short:
{ {
TShortProperty *pShortCast = static_cast<TShortProperty*>(pProp); CShortProperty* pShort = TPropCast<CShortProperty>(pProp);
pShortCast->Set(rSCLY.ReadShort()); pShort->ValueRef(pData) = rSCLY.ReadShort();
break; break;
} }
case eLongProperty: case EPropertyTypeNew::Int:
{ {
TLongProperty *pLongCast = static_cast<TLongProperty*>(pProp); CIntProperty* pInt = TPropCast<CIntProperty>(pProp);
pLongCast->Set(rSCLY.ReadLong()); pInt->ValueRef(pData) = rSCLY.ReadLong();
break; break;
} }
case eBitfieldProperty: case EPropertyTypeNew::Float:
{ {
TBitfieldProperty *pBitfieldCast = static_cast<TBitfieldProperty*>(pProp); CFloatProperty* pFloat = TPropCast<CFloatProperty>(pProp);
pBitfieldCast->Set(rSCLY.ReadLong()); pFloat->ValueRef(pData) = rSCLY.ReadFloat();
// 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));
break; break;
} }
case eEnumProperty: case EPropertyTypeNew::Choice:
{ {
TEnumProperty *pEnumCast = static_cast<TEnumProperty*>(pProp); CChoiceProperty* pChoice = TPropCast<CChoiceProperty>(pProp);
CEnumTemplate *pEnumTemp = static_cast<CEnumTemplate*>(pTemp); pChoice->ValueRef(pData) = rSCLY.ReadLong();
u32 ID = rSCLY.ReadLong();
// Validate #if VALIDATE_PROPERTY_VALUES
u32 Index = pEnumTemp->EnumeratorIndex(ID); if (!pChoice->HasValidValue(pData))
if (Index == -1) Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Enum property \"" + pEnumTemp->FullName() + "\" (" + pEnumTemp->IDString(true) + ") has invalid enumerator value: " + TString::HexString(ID)); {
u32 Value = pChoice->ValueRef(pData);
pEnumCast->Set(ID); Log::FileError(rSCLY.GetSourceString(), rSCLY.Tell() - 4, "Choice property \"" + pChoice->Name() + "\" (" + pChoice->IDString(true) + ") has unrecognized value: " + TString::HexString(Value));
}
#endif
break; break;
} }
case eFloatProperty: case EPropertyTypeNew::Enum:
{ {
TFloatProperty *pFloatCast = static_cast<TFloatProperty*>(pProp); CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
pFloatCast->Set(rSCLY.ReadFloat()); 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; break;
} }
case eStringProperty: case EPropertyTypeNew::Flags:
{ {
TStringProperty *pStringCast = static_cast<TStringProperty*>(pProp); CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
pStringCast->Set(rSCLY.ReadString()); 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; break;
} }
case eVector3Property: case EPropertyTypeNew::String:
{ {
TVector3Property *pVector3Cast = static_cast<TVector3Property*>(pProp); CStringProperty* pString = TPropCast<CStringProperty>(pProp);
pVector3Cast->Set(CVector3f(rSCLY)); pString->ValueRef(pData) = rSCLY.ReadString();
break; break;
} }
case eColorProperty: case EPropertyTypeNew::Vector:
{ {
TColorProperty *pColorCast = static_cast<TColorProperty*>(pProp); CVectorProperty* pVector = TPropCast<CVectorProperty>(pProp);
pColorCast->Set(CColor(rSCLY)); pVector->ValueRef(pData) = CVector3f(rSCLY);
break; break;
} }
case eSoundProperty: case EPropertyTypeNew::Color:
{ {
TSoundProperty *pSoundCast = static_cast<TSoundProperty*>(pProp); CColorProperty* pColor = TPropCast<CColorProperty>(pProp);
pSoundCast->Set(rSCLY.ReadLong()); pColor->ValueRef(pData) = CColor(rSCLY);
break; 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 #if VALIDATE_PROPERTY_VALUES
CAssetID ID; CAssetID ID = pAsset->ValueRef(pData);
if (mVersion == eReturns)
ID = CAssetID(rSCLY, (EIDLength) Size);
else
ID = CAssetID(rSCLY, mVersion);
pAssetCast->Set(ID);
// Verify this is a valid resource type for this property
if (ID.IsValid()) if (ID.IsValid())
{ {
CResourceEntry *pEntry = gpResourceStore->FindEntry(ID); CResourceEntry *pEntry = gpResourceStore->FindEntry(ID);
if (pEntry) if (pEntry)
{ {
const CResTypeFilter& rkFilter = static_cast<CAssetTemplate*>(pTemp)->TypeFilter(); const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
bool Valid = rkFilter.Accepts(pEntry->ResourceType()); bool Valid = rkFilter.Accepts(pEntry->ResourceType());
if (!Valid) 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; 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) if (mVersion < eEchoesDemo)
LoadStructMP1(rSCLY, pStructCast, static_cast<CStructTemplate*>(pStructCast->Template())); LoadStructMP1(rSCLY, pStruct);
else else
LoadStructMP2(rSCLY, pStructCast, static_cast<CStructTemplate*>(pTemp)); LoadStructMP2(rSCLY, pStruct);
break; break;
} }
case eArrayProperty: case EPropertyTypeNew::Array:
{ {
CArrayProperty *pArrayCast = static_cast<CArrayProperty*>(pProp); CArrayProperty *pArray = TPropCast<CArrayProperty>(pProp);
int Count = rSCLY.ReadLong(); 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()); * so this is kind of annoying, there isn't really any good way to cleanly integrate arrays into the property system
else * because calculating the pointer to an item requires knowing the array index, which the property itself can't store
LoadStructMP2(rSCLY, static_cast<CPropertyStruct*>(pArrayCast->PropertyByIndex(iElem)), pArrayCast->SubStructTemplate()); * 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; 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(); u32 StructStart = rSCLY.Tell();
// Verify property count // Verify property count
u32 PropCount = pTemp->Count(); u32 PropertyCount = pStruct->NumChildren();
u32 Version = 0; u32 Version = 0;
if (!pTemp->IsSingleProperty()) if (!pStruct->IsAtomic())
{ {
u32 FilePropCount = rSCLY.ReadLong(); u32 FilePropCount = rSCLY.ReadLong();
Version = pTemp->VersionForPropertyCount(FilePropCount); //@todo version checking
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;
}
} }
// Parse properties // Parse properties
for (u32 iProp = 0; iProp < PropCount; iProp++) for (u32 ChildIndex = 0; ChildIndex < PropertyCount; ChildIndex++)
{ {
IPropertyTemplate *pPropTemp = pTemp->PropertyByIndex(iProp); IPropertyNew *pProperty = pStruct->ChildByIndex(ChildIndex);
IProperty *pProp = pStruct->PropertyByIndex(iProp);
if (pPropTemp->CookPreference() != eNeverCook && pPropTemp->IsInVersion(Version)) //@todo version check
ReadProperty(pProp, 0, rSCLY); if (pProperty->CookPreference() != ECookPreferenceNew::Never)
ReadProperty(pProperty, 0, rSCLY);
} }
} }
CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY) CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
{ {
u32 ObjStart = rSCLY.Tell(); u32 StartOffset = rSCLY.Tell();
u8 Type = rSCLY.ReadByte(); u8 Type = rSCLY.ReadByte();
u32 Size = rSCLY.ReadLong(); u32 Size = rSCLY.ReadLong();
u32 End = rSCLY.Tell() + Size; u32 End = rSCLY.Tell() + Size;
CScriptTemplate *pTemp = mpMaster->TemplateByID((u32) Type); CScriptTemplate *pTemplate = mpMaster->TemplateByID((u32) Type);
if (!pTemp) if (!pTemplate)
{ {
// No valid template for this object; can't load // 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); rSCLY.Seek(End, SEEK_SET);
return nullptr; return nullptr;
} }
u32 InstanceID = rSCLY.ReadLong() & 0x03FFFFFF; u32 InstanceID = rSCLY.ReadLong() & 0x03FFFFFF;
if (InstanceID == 0x03FFFFFF) InstanceID = mpArea->FindUnusedInstanceID(); if (InstanceID == 0x03FFFFFF) InstanceID = mpArea->FindUnusedInstanceID();
mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemp); mpObj = new CScriptObject(InstanceID, mpArea, mpLayer, pTemplate);
// Load connections // Load connections
u32 NumLinks = rSCLY.ReadLong(); u32 NumLinks = rSCLY.ReadLong();
@ -268,8 +306,8 @@ CScriptObject* CScriptLoader::LoadObjectMP1(IInputStream& rSCLY)
} }
// Load object... // Load object...
CPropertyStruct *pBase = mpObj->mpProperties; CStructPropertyNew* pProperties = pTemplate->Properties();
LoadStructMP1(rSCLY, pBase, static_cast<CStructTemplate*>(pBase->Template())); LoadStructMP1(rSCLY, pProperties);
// Cleanup and return // Cleanup and return
rSCLY.Seek(End, SEEK_SET); rSCLY.Seek(End, SEEK_SET);
@ -288,11 +326,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
mpLayer = new CScriptLayer(mpArea); mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects); mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++) for (u32 ObjectIndex = 0; ObjectIndex < NumObjects; ObjectIndex++)
{ {
CScriptObject *pObj = LoadObjectMP1(rSCLY); CScriptObject *pObject = LoadObjectMP1(rSCLY);
if (pObj) if (pObject)
mpLayer->AddInstance(pObj); mpLayer->AddInstance(pObject);
} }
// Layer sizes are always a multiple of 32 - skip end padding before returning // Layer sizes are always a multiple of 32 - skip end padding before returning
@ -301,46 +339,39 @@ CScriptLayer* CScriptLoader::LoadLayerMP1(IInputStream& rSCLY)
return mpLayer; return mpLayer;
} }
void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CPropertyStruct *pStruct, CStructTemplate *pTemp) void CScriptLoader::LoadStructMP2(IInputStream& rSCLY, CStructPropertyNew* pStruct)
{ {
// Verify property count // Verify property count
u32 StructStart = rSCLY.Tell(); u32 ChildCount = pStruct->NumChildren();
StructStart += 0;
u32 PropCount = pTemp->Count();
if (!pTemp->IsSingleProperty()) if (!pStruct->IsAtomic())
PropCount = rSCLY.ReadShort(); ChildCount = rSCLY.ReadShort();
// Parse properties // Parse properties
for (u32 iProp = 0; iProp < PropCount; iProp++) for (u32 ChildIdx = 0; ChildIdx < ChildCount; ChildIdx++)
{ {
IProperty *pProp; IPropertyNew* pProperty = nullptr;
IPropertyTemplate *pPropTemp;
u32 PropertyStart = rSCLY.Tell(); u32 PropertyStart = rSCLY.Tell();
u32 PropertyID = -1; u32 PropertyID = -1;
u16 PropertyLength = 0; u16 PropertySize = 0;
u32 NextProperty = 0; u32 NextProperty = 0;
if (pTemp->IsSingleProperty()) if (pStruct->IsAtomic())
{ {
pProp = pStruct->PropertyByIndex(iProp); pProperty = pStruct->ChildByIndex(ChildIdx);
pPropTemp = pTemp->PropertyByIndex(iProp);
} }
else else
{ {
PropertyID = rSCLY.ReadLong(); PropertyID = rSCLY.ReadLong();
PropertyLength = rSCLY.ReadShort(); PropertySize = rSCLY.ReadShort();
NextProperty = rSCLY.Tell() + PropertyLength; NextProperty = rSCLY.Tell() + PropertySize;
pProperty = pStruct->ChildByID(PropertyID);
pProp = pStruct->PropertyByID(PropertyID);
pPropTemp = pTemp->PropertyByID(PropertyID);
} }
if (!pPropTemp) if (!pProperty)
Log::FileError(rSCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping"); Log::FileError(rSCLY.GetSourceString(), PropertyStart, "Can't find template for property " + TString::HexString(PropertyID) + " - skipping");
else else
ReadProperty(pProp, PropertyLength, rSCLY); ReadProperty(pProperty, PropertySize, rSCLY);
if (NextProperty > 0) if (NextProperty > 0)
rSCLY.Seek(NextProperty, SEEK_SET); rSCLY.Seek(NextProperty, SEEK_SET);
@ -354,7 +385,7 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
u16 ObjectSize = rSCLY.ReadShort(); u16 ObjectSize = rSCLY.ReadShort();
u32 ObjEnd = rSCLY.Tell() + ObjectSize; u32 ObjEnd = rSCLY.Tell() + ObjectSize;
CScriptTemplate *pTemplate = mpMaster->TemplateByID(ObjectID); CScriptTemplate* pTemplate = mpMaster->TemplateByID(ObjectID);
if (!pTemplate) if (!pTemplate)
{ {
@ -371,19 +402,19 @@ CScriptObject* CScriptLoader::LoadObjectMP2(IInputStream& rSCLY)
u32 NumConnections = rSCLY.ReadShort(); u32 NumConnections = rSCLY.ReadShort();
mpObj->mOutLinks.reserve(NumConnections); mpObj->mOutLinks.reserve(NumConnections);
for (u32 iCon = 0; iCon < NumConnections; iCon++) for (u32 LinkIdx = 0; LinkIdx < NumConnections; LinkIdx++)
{ {
u32 State = rSCLY.ReadLong(); u32 State = rSCLY.ReadLong();
u32 Message = rSCLY.ReadLong(); u32 Message = rSCLY.ReadLong();
u32 ReceiverID = rSCLY.ReadLong() & 0x03FFFFFF; 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); mpObj->mOutLinks.push_back(pLink);
} }
// Load object // Load object
rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size rSCLY.Seek(0x6, SEEK_CUR); // Skip base struct ID + size
LoadStructMP2(rSCLY, mpObj->mpProperties, mpObj->mpTemplate->BaseStruct()); LoadStructMP2(rSCLY, pTemplate->Properties());
// Cleanup and return // Cleanup and return
rSCLY.Seek(ObjEnd, SEEK_SET); rSCLY.Seek(ObjEnd, SEEK_SET);
@ -399,11 +430,11 @@ CScriptLayer* CScriptLoader::LoadLayerMP2(IInputStream& rSCLY)
mpLayer = new CScriptLayer(mpArea); mpLayer = new CScriptLayer(mpArea);
mpLayer->Reserve(NumObjects); mpLayer->Reserve(NumObjects);
for (u32 iObj = 0; iObj < NumObjects; iObj++) for (u32 ObjectIdx = 0; ObjectIdx < NumObjects; ObjectIdx++)
{ {
CScriptObject *pObj = LoadObjectMP2(rSCLY); CScriptObject* pObject = LoadObjectMP2(rSCLY);
if (pObj) if (pObject)
mpLayer->AddInstance(pObj); mpLayer->AddInstance(pObject);
} }
return mpLayer; return mpLayer;

View File

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

View File

@ -1,6 +1,7 @@
#include "CTemplateLoader.h" #include "CTemplateLoader.h"
#include "CAreaLoader.h" #include "CAreaLoader.h"
#include "Core/Resource/Script/IPropertyTemplate.h" #include "Core/Resource/Script/IPropertyTemplate.h"
#include "Core/Resource/Script/Property/Properties.h"
#include <Common/FileUtil.h> #include <Common/FileUtil.h>
#include <Common/Log.h> #include <Common/Log.h>
@ -9,7 +10,105 @@ const TString CTemplateLoader::mskGameListPath = CTemplateLoader::mskTemplatesDi
using namespace tinyxml2; 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 NodeType = TString(pElem->Name()).ToLower();
TString IDAttr = TString(pElem->Attribute("ID")).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)? // Does the property already exist (eg is this an override)?
IPropertyTemplate *pProp = pStruct->PropertyByID(ID); IPropertyNew* pProp = pParent->ChildByID(ID);
EPropertyType Type; EPropertyTypeNew Type;
bool IsNewProperty = false; bool IsNewProperty = false;
// If it doesn't, then we'll need to create it. // If it doesn't, then we'll need to create it.
@ -50,7 +149,7 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
Type = PropStringToPropEnum(TypeStr); Type = PropStringToPropEnum(TypeStr);
IsNewProperty = true; IsNewProperty = true;
if (Type == eInvalidProperty) if (Type == EPropertyTypeNew::Invalid)
{ {
if (TypeStr.IsEmpty()) if (TypeStr.IsEmpty())
Log::Error(rkTemplateName + ": Property " + TString::HexString(ID) + " doesn't have a type set"); 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; 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) if (!pProp)
{ {
Log::Error(rkTemplateName + ": Property " + TString::HexString(ID) + " seems to be using a valid but unsupported property type? (" + TypeStr + ")"); Log::Error(rkTemplateName + ": Property " + TString::HexString(ID) + " seems to be using a valid but unsupported property type? (" + TypeStr + ")");
return nullptr; return nullptr;
} }
// Initialize parameters on the new property
pProp->mID = ID;
pProp->mName = Name;
} }
else else
Type = pProp->Type(); Type = pProp->Type();
@ -79,6 +221,7 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
TString ParamName = TString(pParams->Name()).ToLower(); TString ParamName = TString(pParams->Name()).ToLower();
TString ParamVal = TString(pParams->GetText()); TString ParamVal = TString(pParams->GetText());
#if 0
// Load versions // Load versions
if (ParamName == "versions") if (ParamName == "versions")
{ {
@ -100,245 +243,284 @@ IPropertyTemplate* CTemplateLoader::LoadProperty(XMLElement *pElem, CScriptTempl
// Otherwise, delegate it to the template to parse the parameter. // 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.) // (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(); pParams = pParams->NextSiblingElement();
} }
// Asset-specific parameters // Asset-specific parameters
if (Type == eAssetProperty) if (Type == EPropertyTypeNew::Asset)
{ {
TString ExtensionsAttr = pElem->Attribute("extensions"); TString ExtensionsAttr = pElem->Attribute("extensions");
if (!ExtensionsAttr.IsEmpty()) if (!ExtensionsAttr.IsEmpty())
{ {
TStringList ExtensionsList = ExtensionsAttr.Split(", "); TStringList ExtensionsList = ExtensionsAttr.Split(", ");
CAssetTemplate *pAsset = static_cast<CAssetTemplate*>(pProp); CAssetProperty* pAsset = TPropCast<CAssetProperty>(pProp);
pAsset->SetTypeFilter(ExtensionsList); pAsset->SetTypeFilter(ExtensionsList);
} }
} }
// Enum-specific parameters // Enum-specific parameters
else if (Type == eEnumProperty) else if (Type == EPropertyTypeNew::Enum || Type == EPropertyTypeNew::Choice)
{ {
CEnumTemplate *pEnum = static_cast<CEnumTemplate*>(pProp); // use static_cast so we can do both enum and choice with this code
CEnumProperty* pEnum = static_cast<CEnumProperty*>(pProp);
// Load template
if (!TemplateAttr.IsEmpty())
LoadEnumTemplate(TemplateAttr, pEnum);
// Load embedded enumerators // Load embedded enumerators
XMLElement *pEnumerators = pElem->FirstChildElement("enumerators"); XMLElement* pEnumerators = pElem->FirstChildElement("enumerators");
if (pEnumerators) if (pEnumerators)
LoadEnumerators(pEnumerators, pEnum, rkTemplateName); LoadEnumerators(pEnumerators, pEnum, rkTemplateName);
} }
// Bitfield-specific parameters // Bitfield-specific parameters
else if (Type == eBitfieldProperty) else if (Type == EPropertyTypeNew::Flags)
{ {
CBitfieldTemplate *pBitfield = static_cast<CBitfieldTemplate*>(pProp); CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
// Load template
if (!TemplateAttr.IsEmpty())
LoadBitfieldTemplate(TemplateAttr, pBitfield);
// Load embedded flags // Load embedded flags
XMLElement *pFlags = pElem->FirstChildElement("flags"); XMLElement* pFlagsElem = pElem->FirstChildElement("flags");
if (pFlags) if (pFlagsElem)
LoadBitFlags(pFlags, pBitfield, rkTemplateName); LoadBitFlags(pFlagsElem, pFlags, rkTemplateName);
} }
// Struct-specific parameters // 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 (Type == EPropertyTypeNew::Struct)
if (!TemplateAttr.IsEmpty()) {
LoadStructTemplate(TemplateAttr, pStruct); pStruct = TPropCast<CStructPropertyNew>(pProp);
}
else
{
CArrayProperty* pArray = TPropCast<CArrayProperty>(pProp);
if (IsNewProperty && TemplateAttr.IsEmpty() && Type == eStructProperty) if (pArray->mpArchetype != nullptr)
pStruct->mIsSingleProperty = (TypeAttr == "single"); {
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"); XMLElement *pProperties = pElem->FirstChildElement("properties");
if (pProperties) if (pProperties)
{
LoadProperties(pProperties, pScript, pStruct, rkTemplateName); LoadProperties(pProperties, pScript, pStruct, rkTemplateName);
}
if (Type == EPropertyTypeNew::Array)
{
pStruct->PostInitialize();
}
} }
if (IsNewProperty) if (IsNewProperty)
CMasterTemplate::AddProperty(pProp, mMasterDir + rkTemplateName); CMasterTemplate::AddProperty(pProp, mMasterDir + rkTemplateName);
pProp->PostInitialize();
return pProp; return pProp;
} }
#define CREATE_PROP_TEMP(Class) new Class(ID, rkName, eNoCookPreference, pScript, mpMaster, pStruct) CStructPropertyNew* CTemplateLoader::LoadStructArchetype(const TString& rkTemplateFileName)
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)
{ {
// Check whether this struct has already been read // Check whether this struct has already been read
auto it = mpMaster->mStructTemplates.find(rkTemplateFileName); 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 the struct template hasn't been read yet, then we read it and add it to master's list
if (!pSource) if (!pArchetype)
{ {
XMLDocument Doc; XMLDocument Doc;
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc); OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!Doc.Error()) 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); pArchetype->mSourceFile = "Structs/" +
pRootElem = Doc.FirstChildElement("struct"); GetGameShortName(mGame) +
"-" +
if (!pRootElem) pArchetype->mTypeName +
{ ".xml";
Log::Error(rkTemplateFileName + ": There is no root \"struct\" element"); pArchetype->mTypeName = pArchetype->mSourceFile.GetFileName(false);
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);
} }
#endif
else if (pStruct->Type() == eArrayProperty) // ignore struct name attribute - archetypes should always have the type name
{ #if 0
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);
TString NameAttr = TString(pRootElem->Attribute("name")); TString NameAttr = TString(pRootElem->Attribute("name"));
if (!NameAttr.IsEmpty()) if (!NameAttr.IsEmpty())
pSource->mName = NameAttr; pArchetype->mName = NameAttr;
#endif
// Read sub-properties // Read sub-properties
XMLElement *pSubPropsElem = pRootElem->FirstChildElement("properties"); XMLElement* pSubPropsElem = pRootElem->FirstChildElement("properties");
ASSERT(pSubPropsElem);
if (pSubPropsElem) LoadProperties(pSubPropsElem, nullptr, pArchetype, rkTemplateFileName);
{ mpMaster->mStructTemplates[rkTemplateFileName] = pArchetype;
LoadProperties(pSubPropsElem, nullptr, pSource, rkTemplateFileName); pArchetype->PostInitialize();
mpMaster->mStructTemplates[rkTemplateFileName] = pSource;
}
else
{
Log::Error(rkTemplateFileName + ": There is no \"properties\" block element");
delete pSource;
pSource = nullptr;
}
} }
} }
// Copy source to the new struct template ASSERT(pArchetype != nullptr);
if (pSource) return pArchetype;
pStruct->CopyStructData(pSource);
} }
void CTemplateLoader::LoadEnumTemplate(const TString& rkTemplateFileName, CEnumTemplate *pEnum) CEnumProperty* CTemplateLoader::LoadEnumArchetype(const TString& rkTemplateFileName, bool bIsChoice)
{ {
XMLDocument Doc; // Check whether this struct has already been read
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc); 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; XMLDocument Doc;
XMLElement *pRootElem = Doc.FirstChildElement("enum"); OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!pRootElem) if (!Doc.Error())
{ {
Log::Error(rkTemplateFileName + ": There is no root \"enum\" element"); // use static_cast so this code works for both enum and choice
return; 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; // Check whether this struct has already been read
OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc); 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; XMLDocument Doc;
XMLElement *pRootElem = Doc.FirstChildElement("bitfield"); OpenXML(mskTemplatesDir + mMasterDir + rkTemplateFileName, Doc);
if (!pRootElem) if (!Doc.Error())
{ {
Log::Error(rkTemplateFileName + ": There is no root \"bitfield\" element"); pArchetype = TPropCast<CFlagsProperty>(
return; 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(); XMLElement *pChild = pPropertiesElem->FirstChildElement();
@ -359,12 +541,9 @@ void CTemplateLoader::LoadProperties(XMLElement *pPropertiesElem, CScriptTemplat
pChild = pChild->NextSiblingElement(); 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"); XMLElement *pChild = pEnumeratorsElem->FirstChildElement("enumerator");
@ -376,10 +555,7 @@ void CTemplateLoader::LoadEnumerators(XMLElement *pEnumeratorsElem, CEnumTemplat
if (pkID && pkName) if (pkID && pkName)
{ {
u32 EnumeratorID = TString(pkID).ToInt32(); u32 EnumeratorID = TString(pkID).ToInt32();
pTemp->mEnumerators.push_back(CEnumTemplate::SEnumerator(pkName, EnumeratorID)); pEnum->mValues.push_back(CEnumProperty::SEnumValue(pkName, EnumeratorID));
if (EnumeratorID > 0xFF)
pTemp->mUsesHashes = true;
} }
else 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"); XMLElement *pChild = pFlagsElem->FirstChildElement("flag");
@ -405,11 +581,11 @@ void CTemplateLoader::LoadBitFlags(XMLElement *pFlagsElem, CBitfieldTemplate *pT
const char *pkName = pChild->Attribute("name"); const char *pkName = pChild->Attribute("name");
if (pkMask && pkName) if (pkMask && pkName)
pTemp->mBitFlags.push_back(CBitfieldTemplate::SBitFlag(pkName, TString(pkMask).ToInt32())); pFlags->mBitFlags.push_back(CFlagsProperty::SBitFlag(pkName, TString(pkMask).ToInt32()));
else 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 + ")"); if (!pkMask && pkName) Log::Error(LogErrorBase + "no mask (" + pkName + ")");
else if (pkMask && !pkName) Log::Error(LogErrorBase + "no name (mask " + pkMask + ")"); 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 ************ // ************ SCRIPT OBJECT ************
CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TString& rkTemplateName, u32 ObjectID) CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TString& rkTemplateName, u32 ObjectID)
{ {
CScriptTemplate *pScript = new CScriptTemplate(mpMaster); CScriptTemplate *pScript = new CScriptTemplate(mpMaster);
pScript->mObjectID = ObjectID; pScript->mObjectID = ObjectID;
pScript->mpBaseStruct = new CStructTemplate(-1, pScript, mpMaster);
pScript->mSourceFile = rkTemplateName; 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"); XMLElement *pRoot = pDoc->FirstChildElement("ScriptTemplate");
// Name // Name
XMLElement *pNameElem = pRoot->FirstChildElement("name"); XMLElement *pNameElem = pRoot->FirstChildElement("name");
ASSERT(pNameElem);
if (pNameElem) pScript->mpProperties->mName = pNameElem->GetText();
{
pScript->mTemplateName = pNameElem->GetText();
pScript->mpBaseStruct->SetName(pScript->mTemplateName);
}
// Modules // Modules
XMLElement *pModulesElem = pRoot->FirstChildElement("modules"); XMLElement *pModulesElem = pRoot->FirstChildElement("modules");
@ -457,7 +636,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
XMLElement *pPropsElem = pRoot->FirstChildElement("properties"); XMLElement *pPropsElem = pRoot->FirstChildElement("properties");
if (pPropsElem) if (pPropsElem)
LoadProperties(pPropsElem, pScript, pScript->mpBaseStruct, rkTemplateName); LoadProperties(pPropsElem, pScript, pScript->Properties(), rkTemplateName);
else else
Log::Error(rkTemplateName + ": There is no \"properties\" block element"); Log::Error(rkTemplateName + ": There is no \"properties\" block element");
@ -565,7 +744,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
// Validate property asset // Validate property asset
if (Asset.AssetSource == CScriptTemplate::SEditorAsset::eProperty) 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); Log::Error(rkTemplateName + ": Invalid property for " + Type + " asset: " + ID);
pAsset = pAsset->NextSiblingElement(); pAsset = pAsset->NextSiblingElement();
@ -609,12 +788,12 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
Attachment.AttachType = eAttach; Attachment.AttachType = eAttach;
// Validate property // Validate property
IPropertyTemplate *pProp = pScript->mpBaseStruct->PropertyByIDString(Attachment.AttachProperty); IPropertyNew* pProp = pScript->mpProperties->ChildByIDString(Attachment.AttachProperty);
if (!pProp) if (!pProp)
Log::Error(rkTemplateName + ": Invalid property for attachment " + TString::FromInt32(AttachIdx) + ": " + Attachment.AttachProperty); 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))) 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 a character property."); 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 else
{ {
@ -746,6 +925,7 @@ CScriptTemplate* CTemplateLoader::LoadScriptTemplate(XMLDocument *pDoc, const TS
} }
} }
pScript->PostLoad();
return pScript; return pScript;
} }

View File

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

View File

@ -88,7 +88,7 @@ SMessage CMasterTemplate::MessageByIndex(u32 Index)
return (std::next(it, Index))->second; return (std::next(it, Index))->second;
} }
CStructTemplate* CMasterTemplate::StructAtSource(const TString& rkSource) CStructPropertyNew* CMasterTemplate::StructAtSource(const TString& rkSource)
{ {
auto InfoIt = mStructTemplates.find(rkSource); auto InfoIt = mStructTemplates.find(rkSource);
@ -149,38 +149,44 @@ TString CMasterTemplate::PropertyName(u32 PropertyID)
return "Unknown"; 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. // 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). // 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; // 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
CStructTemplate *pStruct = pTemp->Parent(); // 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) CCRC32 Hash;
{ Hash.Hash(*IDString);
Source = pStruct->SourceFile(); Hash.Hash(*TemplateFile);
if (!Source.IsEmpty()) break; return Hash.Digest();
IDString.Prepend(pStruct->IDString(false) + ":");
pStruct = pStruct->Parent();
}
return IDString.Hash32() * Source.Hash32();
} }
void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTemplateName /*= ""*/) void CMasterTemplate::AddProperty(IPropertyNew* pProp, const TString& rkTemplateName /*= ""*/)
{ {
u32 ID; u32 ID;
if (pTemp->Game() >= eEchoesDemo) if (pProp->Game() >= eEchoesDemo)
ID = pTemp->PropertyID(); ID = pProp->ID();
// Use a different ID for MP1 // Use a different ID for MP1
else else
{ {
// For MP1 we only really need to track properties that come from struct templates. // For MP1 we only really need to track properties that come from struct templates.
if (!pTemp->IsFromStructTemplate()) return; IPropertyNew* pArchetype = pProp->Archetype();
else ID = CreatePropertyID(pTemp);
if (!pArchetype ||
pArchetype->ScriptTemplate() != nullptr ||
pArchetype->RootParent()->Type() != EPropertyTypeNew::Struct)
return;
ID = CreatePropertyID(pProp);
} }
auto it = smIDMap.find(ID); auto it = smIDMap.find(ID);
@ -189,7 +195,7 @@ void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTem
if (it != smIDMap.end()) if (it != smIDMap.end())
{ {
SPropIDInfo& rInfo = it->second; SPropIDInfo& rInfo = it->second;
rInfo.PropertyList.push_back(pTemp); rInfo.PropertyList.push_back(pProp);
if (!rkTemplateName.IsEmpty()) if (!rkTemplateName.IsEmpty())
{ {
@ -214,15 +220,15 @@ void CMasterTemplate::AddProperty(IPropertyTemplate *pTemp, const TString& rkTem
{ {
SPropIDInfo Info; SPropIDInfo Info;
if (!rkTemplateName.IsEmpty()) Info.XMLList.push_back(rkTemplateName); if (!rkTemplateName.IsEmpty()) Info.XMLList.push_back(rkTemplateName);
Info.PropertyList.push_back(pTemp); Info.PropertyList.push_back(pProp);
smIDMap[ID] = Info; smIDMap[ID] = Info;
} }
} }
void CMasterTemplate::RenameProperty(IPropertyTemplate *pTemp, const TString& rkNewName) void CMasterTemplate::RenameProperty(IPropertyNew* pProp, const TString& rkNewName)
{ {
u32 ID = pTemp->PropertyID(); u32 ID = pProp->ID();
if (ID <= 0xFF) ID = CreatePropertyID(pTemp); if (ID <= 0xFF) ID = CreatePropertyID(pProp);
RenameProperty(ID, rkNewName); RenameProperty(ID, rkNewName);
} }
@ -245,10 +251,10 @@ void CMasterTemplate::RenameProperty(u32 ID, const TString& rkNewName)
{ {
const SPropIDInfo& rkInfo = InfoIt->second; 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) if (Original.IsEmpty() || rkInfo.PropertyList[PropertyIdx]->Name() == Original)
rkInfo.PropertyList[iTemp]->SetName(rkNewName); 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(); u32 ID = pProp->ID();
if (ID <= 0xFF) ID = CreatePropertyID(pTemp); if (ID <= 0xFF) ID = CreatePropertyID(pProp);
auto InfoIt = smIDMap.find(ID); auto InfoIt = smIDMap.find(ID);

View File

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

View File

@ -13,19 +13,29 @@ CScriptObject::CScriptObject(u32 InstanceID, CGameArea *pArea, CScriptLayer *pLa
, mIsCheckingNearVisibleActivation(false) , mIsCheckingNearVisibleActivation(false)
{ {
mpTemplate->AddObject(this); mpTemplate->AddObject(this);
mpProperties = (CPropertyStruct*) pTemplate->BaseStruct()->InstantiateProperty(this, nullptr);
mpInstanceName = mpTemplate->FindInstanceName(mpProperties); // Init properties
mpPosition = mpTemplate->FindPosition(mpProperties); CStructPropertyNew* pProperties = pTemplate->Properties();
mpRotation = mpTemplate->FindRotation(mpProperties); u32 PropertiesSize = pProperties->DataSize();
mpScale = mpTemplate->FindScale(mpProperties); mPropertyData.resize( PropertiesSize );
mpActive = mpTemplate->FindActive(mpProperties); pProperties->Construct( mPropertyData.data() );
mpLightParameters = mpTemplate->FindLightParameters(mpProperties);
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() CScriptObject::~CScriptObject()
{ {
if (mpProperties) delete mpProperties; if (!mPropertyData.empty())
{
mpTemplate->Properties()->Destruct( mPropertyData.data() );
mPropertyData.clear();
}
mpTemplate->RemoveObject(this); mpTemplate->RemoveObject(this);
// Note: Incoming links will be deleted by the sender. // Note: Incoming links will be deleted by the sender.
@ -34,6 +44,19 @@ CScriptObject::~CScriptObject()
} }
// ************ DATA MANIPULATION ************ // ************ 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() void CScriptObject::EvaluateProperties()
{ {
EvaluateDisplayAsset(); EvaluateDisplayAsset();
@ -43,12 +66,12 @@ CScriptObject::~CScriptObject()
void CScriptObject::EvaluateDisplayAsset() void CScriptObject::EvaluateDisplayAsset()
{ {
mpDisplayAsset = mpTemplate->FindDisplayAsset(mpProperties, mActiveCharIndex, mActiveAnimIndex, mHasInGameModel); mpDisplayAsset = mpTemplate->FindDisplayAsset(PropertyData(), mActiveCharIndex, mActiveAnimIndex, mHasInGameModel);
} }
void CScriptObject::EvaluateCollisionModel() void CScriptObject::EvaluateCollisionModel()
{ {
mpCollision = mpTemplate->FindCollision(mpProperties); mpCollision = mpTemplate->FindCollision(PropertyData());
} }
void CScriptObject::EvaluateVolume() void CScriptObject::EvaluateVolume()
@ -57,15 +80,15 @@ void CScriptObject::EvaluateVolume()
mVolumeScale = mpTemplate->VolumeScale(this); mVolumeScale = mpTemplate->VolumeScale(this);
} }
bool CScriptObject::IsEditorProperty(IProperty *pProp) bool CScriptObject::IsEditorProperty(IPropertyNew *pProp)
{ {
return ( (pProp == mpInstanceName) || return ( (pProp == mInstanceName.Property()) ||
(pProp == mpPosition) || (pProp == mPosition.Property()) ||
(pProp == mpRotation) || (pProp == mRotation.Property()) ||
(pProp == mpScale) || (pProp == mScale.Property()) ||
(pProp == mpActive) || (pProp == mActive.Property()) ||
(pProp == mpLightParameters) || (pProp == mLightParameters.Property()) ||
(pProp->Parent() == mpLightParameters) (pProp->Parent() == mLightParameters.Property())
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
#ifndef IPROPERTYVALUE_H #ifndef IPROPERTYVALUE_H
#define IPROPERTYVALUE_H #define IPROPERTYVALUE_H
#if 0
#include "EPropertyType.h" #include "EPropertyType.h"
#include <Common/CAssetID.h> #include <Common/CAssetID.h>
#include <Common/Log.h> #include <Common/Log.h>
@ -386,5 +387,6 @@ public:
return new CUnknownValue(mValue); return new CUnknownValue(mValue);
} }
}; };
#endif
#endif // IPROPERTYVALUE_H #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) , mAttachType(rkAttachment.AttachType)
, mLocatorName(rkAttachment.LocatorName) , mLocatorName(rkAttachment.LocatorName)
{ {
CPropertyStruct *pBaseStruct = pParent->Instance()->Properties(); CStructPropertyNew* pBaseStruct = pParent->Template()->Properties();
mpAttachAssetProp = pBaseStruct->PropertyByIDString(rkAttachment.AttachProperty);
mpAttachAssetProp = pBaseStruct->ChildByIDString(rkAttachment.AttachProperty);
mAttachAssetRef = CAssetRef(pParent->Instance(), mpAttachAssetProp);
mAttachAnimSetRef = CAnimationSetRef(pParent->Instance(), mpAttachAssetProp);
if (mpAttachAssetProp) AttachPropertyModified(); if (mpAttachAssetProp) AttachPropertyModified();
ParentDisplayAssetChanged(mpScriptNode->DisplayAsset()); ParentDisplayAssetChanged(mpScriptNode->DisplayAsset());
@ -21,12 +24,12 @@ void CScriptAttachNode::AttachPropertyModified()
{ {
if (mpAttachAssetProp) if (mpAttachAssetProp)
{ {
if (mpAttachAssetProp->Type() == eAssetProperty) if (mAttachAssetRef.IsValid())
mpAttachAsset = gpResourceStore->LoadResource<CModel>( TPropCast<TAssetProperty>(mpAttachAssetProp)->Get() ); mpAttachAsset = gpResourceStore->LoadResource<CModel>(mAttachAssetRef.Get());
else if (mpAttachAssetProp->Type() == eCharacterProperty) else if (mAttachAnimSetRef.IsValid())
mpAttachAsset = TPropCast<TCharacterProperty>(mpAttachAssetProp)->Get().AnimSet(); mpAttachAsset = mAttachAnimSetRef.Get().AnimSet();
CModel *pModel = Model(); CModel* pModel = Model();
if (pModel && pModel->Type() == eModel) if (pModel && pModel->Type() == eModel)
mLocalAABox = pModel->AABox(); mLocalAABox = pModel->AABox();
@ -37,11 +40,11 @@ void CScriptAttachNode::AttachPropertyModified()
} }
} }
void CScriptAttachNode::ParentDisplayAssetChanged(CResource *pNewDisplayAsset) void CScriptAttachNode::ParentDisplayAssetChanged(CResource* pNewDisplayAsset)
{ {
if (pNewDisplayAsset->Type() == eAnimSet) if (pNewDisplayAsset->Type() == eAnimSet)
{ {
CSkeleton *pSkel = mpScriptNode->ActiveSkeleton(); CSkeleton* pSkel = mpScriptNode->ActiveSkeleton();
mpLocator = pSkel->BoneByName(mLocatorName); mpLocator = pSkel->BoneByName(mLocatorName);
} }
@ -60,11 +63,8 @@ CModel* CScriptAttachNode::Model() const
if (mpAttachAsset->Type() == eModel) if (mpAttachAsset->Type() == eModel)
return static_cast<CModel*>(mpAttachAsset.RawPointer()); return static_cast<CModel*>(mpAttachAsset.RawPointer());
if (mpAttachAsset->Type() == eAnimSet) else if (mpAttachAsset->Type() == eAnimSet)
{ return mAttachAnimSetRef.Get().GetCurrentModel();
TCharacterProperty *pProp = TPropCast<TCharacterProperty>(mpAttachAssetProp);
return pProp->Get().GetCurrentModel();
}
} }
return nullptr; return nullptr;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,16 +6,17 @@
class CDoorExtra : public CScriptExtra class CDoorExtra : public CScriptExtra
{ {
// Render colored door shield in MP2/3 // Render colored door shield in MP2/3
TAssetProperty *mpShieldModelProp; CAssetRef mShieldModelProp;
TColorProperty *mpShieldColorProp; CColorRef mShieldColorProp;
TBoolProperty *mpDisabledProp; CBoolRef mDisabledProp;
TResPtr<CModel> mpShieldModel; TResPtr<CModel> mpShieldModel;
CColor mShieldColor; CColor mShieldColor;
public: public:
explicit CDoorExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); explicit CDoorExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent = 0);
void PropertyModified(IProperty *pProperty); void PropertyModified(IPropertyNew* pProperty);
void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo); void AddToRenderer(CRenderer* pRenderer, const SViewInfo& rkViewInfo);
void Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo); void Draw(FRenderOptions Options, int ComponentIndex, ERenderCommand Command, const SViewInfo& rkViewInfo);
void DrawSelection(); void DrawSelection();
void RayAABoxIntersectTest(CRayCollisionTester& rTester, const SViewInfo& rkViewInfo); 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) CPointOfInterestExtra::CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent)
: CScriptExtra(pInstance, pScene, pParent) : CScriptExtra(pInstance, pScene, pParent)
, mpScanProperty(nullptr)
, mpScanData(nullptr) , mpScanData(nullptr)
{ {
// Fetch scan data property // Fetch scan data property
CPropertyStruct *pBaseProp = pInstance->Properties(); CStructPropertyNew* pProperties = pInstance->Template()->Properties();
if (mGame <= ePrime) mpScanProperty = TPropCast<TAssetProperty>(pBaseProp->PropertyByIDString("0x04:0x00")); if (mGame <= ePrime) mScanProperty = CAssetRef(pInstance, pProperties->ChildByIDString("0x04:0x00"));
else mpScanProperty = (TAssetProperty*) pBaseProp->PropertyByIDString("0xBDBEC295:0xB94E9BE7"); else mScanProperty = CAssetRef(pInstance, pProperties->ChildByIDString("0xBDBEC295:0xB94E9BE7"));
if (mpScanProperty) PropertyModified(mpScanProperty);
PropertyModified(mScanProperty.Property());
} }
void CPointOfInterestExtra::PropertyModified(IProperty* pProperty) void CPointOfInterestExtra::PropertyModified(IPropertyNew* pProperty)
{ {
if (mpScanProperty == pProperty) if (mScanProperty.Property() == pProperty)
mpScanData = gpResourceStore->LoadResource<CScan>( mpScanProperty->Get() ); mpScanData = gpResourceStore->LoadResource<CScan>( mScanProperty.Get() );
} }
void CPointOfInterestExtra::ModifyTintColor(CColor& Color) void CPointOfInterestExtra::ModifyTintColor(CColor& Color)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,15 +3,15 @@
#include "Core/Resource/Script/CLink.h" #include "Core/Resource/Script/CLink.h"
#include "Core/Scene/CScene.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) : 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++) for (auto it = mWaypoints.begin(); it != mWaypoints.end(); it++)
(*it)->CheckColor(); (*it)->CheckColor();
@ -23,7 +23,7 @@ void CSplinePathExtra::PostLoad()
AddWaypoints(); 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()) if (rChecked.find(pWaypoint) != rChecked.end())
return; return;
@ -46,18 +46,18 @@ void CSplinePathExtra::AddWaypoints()
std::set<CWaypointExtra*> CheckedWaypoints; 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 if ( (pLink->State() == FOURCC('IS00') && pLink->Message() == FOURCC('ATCH')) || // InternalState00/Attach
(pLink->State() == 0x4D4F5450 && pLink->Message() == 0x41544348) ) // MotionPath/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); FindAttachedWaypoints(CheckedWaypoints, pWaypoint);
} }
} }

View File

@ -11,20 +11,20 @@ class CWaypointExtra;
class CSplinePathExtra : public CScriptExtra class CSplinePathExtra : public CScriptExtra
{ {
// Recolor waypoint paths to match the editor color parameter // Recolor waypoint paths to match the editor color parameter
TColorProperty *mpPathColor; CColorRef mPathColor;
std::list<CWaypointExtra*> mWaypoints; std::list<CWaypointExtra*> mWaypoints;
public: public:
explicit CSplinePathExtra(CScriptObject *pInstance, CScene *pScene, CScriptNode *pParent = 0); explicit CSplinePathExtra(CScriptObject* pInstance, CScene* pScene, CScriptNode* pParent = 0);
~CSplinePathExtra() { ClearWaypoints(); } ~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 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 AddWaypoints();
void RemoveWaypoint(CWaypointExtra *pWaypoint); void RemoveWaypoint(CWaypointExtra* pWaypoint);
void ClearWaypoints(); void ClearWaypoints();
}; };

View File

@ -231,7 +231,8 @@ void CGeneratePropertyNamesDialog::ApplyChanges()
pItem->setText(3, NewName); pItem->setText(3, NewName);
} }
CTemplateWriter::SavePropertyList(); //FIXME
// CTemplateWriter::SavePropertyList();
} }
/** Check progress on name generation task and display results on the UI */ /** 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 */ /** Set the property to validate against */
void CPropertyNameValidator::SetProperty(IPropertyTemplate* pProp) void CPropertyNameValidator::SetProperty(IPropertyNew* pProp)
{ {
mpProperty = pProp; mpProperty = pProp;
emit changed(); emit changed();
@ -19,10 +19,10 @@ QValidator::State CPropertyNameValidator::validate(QString& rInput, int&) const
{ {
CCRC32 Hash; CCRC32 Hash;
Hash.Hash( rInput.toStdString().c_str() ); Hash.Hash( rInput.toStdString().c_str() );
Hash.Hash( mpProperty->GetTypeNameString() ); Hash.Hash( mpProperty->HashableTypeName() );
u32 PropertyID = Hash.Digest(); u32 PropertyID = Hash.Digest();
return ( PropertyID == mpProperty->PropertyID() ? QValidator::Acceptable : QValidator::Invalid ); return ( PropertyID == mpProperty->ID() ? QValidator::Acceptable : QValidator::Invalid );
} }
return QValidator::Invalid; return QValidator::Invalid;

View File

@ -2,7 +2,7 @@
#define CPROPERTYNAMEVALIDATOR_H #define CPROPERTYNAMEVALIDATOR_H
#include <QValidator> #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 */ /** QValidator subclass that checks if a property name is valid */
class CPropertyNameValidator : public QValidator class CPropertyNameValidator : public QValidator
@ -10,13 +10,13 @@ class CPropertyNameValidator : public QValidator
Q_OBJECT Q_OBJECT
/** The property being validated against */ /** The property being validated against */
IPropertyTemplate* mpProperty; IPropertyNew* mpProperty;
public: public:
CPropertyNameValidator(QObject* pParent = 0); CPropertyNameValidator(QObject* pParent = 0);
/** Set the property to validate against */ /** Set the property to validate against */
void SetProperty(IPropertyTemplate* pProp); void SetProperty(IPropertyNew* pProp);
/** Perform validation */ /** Perform validation */
QValidator::State validate(QString& rInput, int& rPos) const; 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 QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionViewItem& /*rkOption*/, const QModelIndex& rkIndex) const
{ {
if (!mpModel) return nullptr; if (!mpModel) return nullptr;
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false); IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false);
QWidget *pOut = nullptr; QWidget *pOut = nullptr;
if (pProp) if (pProp)
@ -57,7 +57,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
switch (pProp->Type()) switch (pProp->Type())
{ {
case eBoolProperty: case EPropertyTypeNew::Bool:
{ {
QCheckBox *pCheckBox = new QCheckBox(pParent); QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
@ -65,39 +65,39 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break; break;
} }
case eShortProperty: case EPropertyTypeNew::Short:
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT16_MIN); pSpinBox->setMinimum(INT16_MIN);
pSpinBox->setMaximum(INT16_MAX); pSpinBox->setMaximum(INT16_MAX);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix())); pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
case eLongProperty: case EPropertyTypeNew::Int:
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(INT32_MIN); pSpinBox->setMinimum(INT32_MIN);
pSpinBox->setMaximum(INT32_MAX); pSpinBox->setMaximum(INT32_MAX);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix())); pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int))
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
case eFloatProperty: case EPropertyTypeNew::Float:
{ {
WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent); WDraggableSpinBox *pSpinBox = new WDraggableSpinBox(pParent);
pSpinBox->setSingleStep(0.1); pSpinBox->setSingleStep(0.1);
pSpinBox->setSuffix(TO_QSTRING(pProp->Template()->Suffix())); pSpinBox->setSuffix(TO_QSTRING(pProp->Suffix()));
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double)) CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(double))
pOut = pSpinBox; pOut = pSpinBox;
break; break;
} }
case eColorProperty: case EPropertyTypeNew::Color:
{ {
WColorPicker *pColorPicker = new WColorPicker(pParent); WColorPicker *pColorPicker = new WColorPicker(pParent);
CONNECT_RELAY(pColorPicker, rkIndex, ColorChanged(QColor)) CONNECT_RELAY(pColorPicker, rkIndex, ColorChanged(QColor))
@ -105,7 +105,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break; break;
} }
case eSoundProperty: case EPropertyTypeNew::Sound:
{ {
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
pSpinBox->setMinimum(-1); pSpinBox->setMinimum(-1);
@ -115,7 +115,7 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break; break;
} }
case eStringProperty: case EPropertyTypeNew::String:
{ {
QLineEdit *pLineEdit = new QLineEdit(pParent); QLineEdit *pLineEdit = new QLineEdit(pParent);
CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString)) CONNECT_RELAY(pLineEdit, rkIndex, textEdited(QString))
@ -123,34 +123,34 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
break; break;
} }
case eEnumProperty: case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
{ {
QComboBox *pComboBox = new QComboBox(pParent); QComboBox *pComboBox = new QComboBox(pParent);
CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template()); for (u32 ValueIdx = 0; ValueIdx < pEnum->NumPossibleValues(); ValueIdx++)
pComboBox->addItem(TO_QSTRING(pEnum->ValueName(ValueIdx)));
for (u32 iEnum = 0; iEnum < pTemp->NumEnumerators(); iEnum++)
pComboBox->addItem(TO_QSTRING(pTemp->EnumeratorName(iEnum)));
CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int)) CONNECT_RELAY(pComboBox, rkIndex, currentIndexChanged(int))
pOut = pComboBox; pOut = pComboBox;
break; break;
} }
case eAssetProperty: case EPropertyTypeNew::Asset:
{ {
CResourceSelector *pSelector = new CResourceSelector(pParent); CResourceSelector *pSelector = new CResourceSelector(pParent);
pSelector->SetFrameVisible(false); pSelector->SetFrameVisible(false);
CAssetTemplate *pTemp = static_cast<CAssetTemplate*>(pProp->Template()); CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
pSelector->SetTypeFilter(pTemp->TypeFilter()); pSelector->SetTypeFilter(pAsset->GetTypeFilter());
CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*)) CONNECT_RELAY(pSelector, rkIndex, ResourceChanged(CResourceEntry*))
pOut = pSelector; pOut = pSelector;
break; 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 // No relay here, would prefer user to be sure of their change before it's reflected on the UI
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
@ -163,41 +163,23 @@ QWidget* CPropertyDelegate::createEditor(QWidget *pParent, const QStyleOptionVie
} }
} }
// Check for sub-property of vector/color/character // Check for sub-property of flgs/animation set
else if (rkIndex.internalId() & 0x1) else if (rkIndex.internalId() & 0x80000000)
{ {
pProp = mpModel->PropertyForIndex(rkIndex, true); pProp = mpModel->PropertyForIndex(rkIndex, true);
EPropertyTypeNew Type = pProp->Type();
// Handle character // Handle character
if (pProp->Type() == eCharacterProperty) if (Type == EPropertyTypeNew::AnimationSet)
pOut = CreateCharacterEditor(pParent, rkIndex); pOut = CreateCharacterEditor(pParent, rkIndex);
// Handle bitfield // Handle flags
else if (pProp->Type() == eBitfieldProperty) else if (Type == EPropertyTypeNew::Flags)
{ {
QCheckBox *pCheckBox = new QCheckBox(pParent); QCheckBox *pCheckBox = new QCheckBox(pParent);
CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool)) CONNECT_RELAY(pCheckBox, rkIndex, toggled(bool))
pOut = pCheckBox; 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) if (pOut)
@ -218,7 +200,8 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
if (pEditor) if (pEditor)
{ {
// Set editor data for regular property // Set editor data for regular property
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false); IPropertyNew *pProp = mpModel->PropertyForIndex(rkIndex, false);
void* pData = mpModel->GetPropertyData();
if (pProp) if (pProp)
{ {
@ -227,102 +210,114 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
switch (pProp->Type()) switch (pProp->Type())
{ {
case eBoolProperty: case EPropertyTypeNew::Bool:
{ {
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor); QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
TBoolProperty *pBool = static_cast<TBoolProperty*>(pProp); CBoolProperty *pBool = TPropCast<CBoolProperty>(pProp);
pCheckBox->setChecked(pBool->Get()); pCheckBox->setChecked( pBool->Value(pData) );
break; break;
} }
case eShortProperty: case EPropertyTypeNew::Short:
{ {
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor); WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus()) if (!pSpinBox->hasFocus())
{ {
TShortProperty *pShort = static_cast<TShortProperty*>(pProp); CShortProperty *pShort = TPropCast<CShortProperty>(pProp);
pSpinBox->setValue(pShort->Get()); pSpinBox->setValue( pShort->Value(pData) );
} }
break; break;
} }
case eLongProperty: case EPropertyTypeNew::Int:
case eSoundProperty:
{ {
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor); WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus()) if (!pSpinBox->hasFocus())
{ {
TLongProperty *pLong = static_cast<TLongProperty*>(pProp); CIntProperty *pInt = TPropCast<CIntProperty>(pProp);
pSpinBox->setValue(pLong->Get()); pSpinBox->setValue( pInt->Value(pData) );
} }
break; 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); WDraggableSpinBox *pSpinBox = static_cast<WDraggableSpinBox*>(pEditor);
if (!pSpinBox->hasFocus()) if (!pSpinBox->hasFocus())
{ {
TFloatProperty *pFloat = static_cast<TFloatProperty*>(pProp); CFloatProperty *pFloat = TPropCast<CFloatProperty>(pProp);
pSpinBox->setValue(pFloat->Get()); pSpinBox->setValue( pFloat->Value(pData) );
} }
break; break;
} }
case eColorProperty: case EPropertyTypeNew::Color:
{ {
WColorPicker *pColorPicker = static_cast<WColorPicker*>(pEditor); 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)); pColorPicker->SetColor(TO_QCOLOR(Color));
break; break;
} }
case eStringProperty: case EPropertyTypeNew::String:
{ {
QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor); QLineEdit *pLineEdit = static_cast<QLineEdit*>(pEditor);
if (!pLineEdit->hasFocus()) if (!pLineEdit->hasFocus())
{ {
TStringProperty *pString = static_cast<TStringProperty*>(pProp); CStringProperty *pString = TPropCast<CStringProperty>(pProp);
pLineEdit->setText(TO_QSTRING(pString->Get())); pLineEdit->setText( TO_QSTRING(pString->Value(pData)) );
} }
break; break;
} }
case eEnumProperty: case EPropertyTypeNew::Enum:
case EPropertyTypeNew::Choice:
{ {
QComboBox *pComboBox = static_cast<QComboBox*>(pEditor); QComboBox *pComboBox = static_cast<QComboBox*>(pEditor);
TEnumProperty *pEnum = static_cast<TEnumProperty*>(pProp); CEnumProperty* pEnum = TPropCast<CEnumProperty>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pProp->Template()); pComboBox->setCurrentIndex( pEnum->ValueIndex( pEnum->Value(pData) ) );
pComboBox->setCurrentIndex(pTemp->EnumeratorIndex(pEnum->Get()));
break; break;
} }
case eAssetProperty: case EPropertyTypeNew::Asset:
{ {
CResourceSelector *pSelector = static_cast<CResourceSelector*>(pEditor); CResourceSelector *pSelector = static_cast<CResourceSelector*>(pEditor);
TAssetProperty *pAsset = static_cast<TAssetProperty*>(pProp); CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
pSelector->SetResource(pAsset->Get()); pSelector->SetResource(pAsset->Value(pData));
break; break;
} }
case eArrayProperty: case EPropertyTypeNew::Array:
{ {
WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor); WIntegralSpinBox *pSpinBox = static_cast<WIntegralSpinBox*>(pEditor);
if (!pSpinBox->hasFocus()) if (!pSpinBox->hasFocus())
{ {
CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp); CArrayProperty *pArray = static_cast<CArrayProperty*>(pProp);
pSpinBox->setValue(pArray->Count()); pSpinBox->setValue( pArray->ArrayCount(pData) );
} }
break; break;
@ -332,54 +327,22 @@ void CPropertyDelegate::setEditorData(QWidget *pEditor, const QModelIndex &rkInd
} }
} }
// Set editor data for character/bitfield/vector/color sub-property // Set editor data for animation set/flags sub-property
else if (rkIndex.internalId() & 0x1) else if (rkIndex.internalId() & 0x80000000)
{ {
pProp = mpModel->PropertyForIndex(rkIndex, true); pProp = mpModel->PropertyForIndex(rkIndex, true);
if (pProp->Type() == eCharacterProperty) if (pProp->Type() == EPropertyTypeNew::AnimationSet)
SetCharacterEditorData(pEditor, rkIndex); SetCharacterEditorData(pEditor, rkIndex);
else if (pProp->Type() == eBitfieldProperty) else if (pProp->Type() == EPropertyTypeNew::Flags)
{ {
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor); QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor);
TBitfieldProperty *pBitfield = static_cast<TBitfieldProperty*>(pProp); CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
u32 Mask = static_cast<CBitfieldTemplate*>(pBitfield->Template())->FlagMask(rkIndex.row()); u32 Mask = pFlags->FlagMask(rkIndex.row());
bool Set = (pBitfield->Get() & Mask) != 0; bool Set = (pFlags->Value(pData) & Mask) != 0;
pCheckBox->setChecked(Set); 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 (!mpModel) return;
if (!pEditor) return; if (!pEditor) return;
IProperty *pProp = mpModel->PropertyForIndex(rkIndex, false); //FIXME
IPropertyValue *pOldValue = nullptr; /* 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) if (pProp)
{ {
IPropertyValue *pRawValue = pProp->RawValue();
pOldValue = pRawValue ? pRawValue->Clone() : nullptr;
switch (pProp->Type()) switch (pProp->Type())
{ {
case eBoolProperty: case EPropertyTypeNew::Bool:
{ {
QCheckBox *pCheckBox = static_cast<QCheckBox*>(pEditor); 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); TBoolProperty *pBool = static_cast<TBoolProperty*>(pProp);
pBool->Set(pCheckBox->isChecked()); pBool->Set(pCheckBox->isChecked());
break; break;
@ -567,7 +536,7 @@ void CPropertyDelegate::setModelData(QWidget *pEditor, QAbstractItemModel* /*pMo
else else
delete pOldValue; delete pOldValue;
} }*/
} }
bool CPropertyDelegate::eventFilter(QObject *pObject, QEvent *pEvent) 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 // 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 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(); CAnimationParameters Params = pProp->Get();
// Determine property type // Determine property type
@ -632,13 +602,15 @@ QWidget* CPropertyDelegate::CreateCharacterEditor(QWidget *pParent, const QModel
WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent); WIntegralSpinBox *pSpinBox = new WIntegralSpinBox(pParent);
CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int)); CONNECT_RELAY(pSpinBox, rkIndex, valueChanged(int));
return pSpinBox; return pSpinBox;
} }*/
return nullptr; return nullptr;
} }
void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const
{ {
//FIXME
/*
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true)); TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pProp->Get(); CAnimationParameters Params = pProp->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex); EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
@ -659,12 +631,15 @@ void CPropertyDelegate::SetCharacterEditorData(QWidget *pEditor, const QModelInd
u32 Value = Params.Unknown(UnkIndex); u32 Value = Params.Unknown(UnkIndex);
static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value); static_cast<WIntegralSpinBox*>(pEditor)->setValue(Value);
} }
*/
} }
void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelIndex& rkIndex) const
{ {
TCharacterProperty *pProp = static_cast<TCharacterProperty*>(mpModel->PropertyForIndex(rkIndex, true)); //FIXME
CAnimationParameters Params = pProp->Get(); /*
CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(mpModel->PropertyForIndex(rkIndex, true));
CAnimationParameters Params = pAnimSet->Get();
EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex); EPropertyType Type = DetermineCharacterPropType(Params.Version(), rkIndex);
if (Type == eAssetProperty) if (Type == eAssetProperty)
@ -693,27 +668,28 @@ void CPropertyDelegate::SetCharacterModelData(QWidget *pEditor, const QModelInde
QModelIndex ParentIndex = rkIndex.parent(); QModelIndex ParentIndex = rkIndex.parent();
mpModel->dataChanged(mpModel->index(1, 1, ParentIndex), mpModel->index(mpModel->rowCount(ParentIndex) - 1, 1, ParentIndex)); 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 (Game <= eEchoes)
{ {
if (rkIndex.row() == 0) return eAssetProperty; if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() == 1) return eEnumProperty; else if (rkIndex.row() == 1) return EPropertyTypeNew::Choice;
else if (rkIndex.row() == 2) return eLongProperty; else if (rkIndex.row() == 2) return EPropertyTypeNew::Int;
} }
else if (Game <= eCorruption) else if (Game <= eCorruption)
{ {
if (rkIndex.row() == 0) return eAssetProperty; if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() == 1) return eLongProperty; else if (rkIndex.row() == 1) return EPropertyTypeNew::Int;
} }
else else
{ {
if (rkIndex.row() == 0) return eAssetProperty; if (rkIndex.row() == 0) return EPropertyTypeNew::Asset;
else if (rkIndex.row() <= 2) return eLongProperty; else if (rkIndex.row() <= 2) return EPropertyTypeNew::Int;
} }
return eUnknownProperty; return EPropertyTypeNew::Invalid;
} }
// ************ PUBLIC SLOTS ************ // ************ PUBLIC SLOTS ************

View File

@ -28,7 +28,7 @@ public:
QWidget* CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const; QWidget* CreateCharacterEditor(QWidget *pParent, const QModelIndex& rkIndex) const;
void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const; void SetCharacterEditorData(QWidget *pEditor, const QModelIndex& rkIndex) const;
void SetCharacterModelData(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: public slots:
void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex); void WidgetEdited(QWidget *pWidget, const QModelIndex& rkIndex);

View File

@ -8,77 +8,111 @@
CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/) CPropertyModel::CPropertyModel(QObject *pParent /*= 0*/)
: QAbstractItemModel(pParent) : QAbstractItemModel(pParent)
, mpBaseStruct(nullptr) , mpProject(nullptr)
, mpRootProperty(nullptr)
, mpPropertyData(nullptr)
, mBoldModifiedProperties(true) , mBoldModifiedProperties(true)
, mShowNameValidity(false) , 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(); beginResetModel();
mpBaseStruct = pBaseStruct;
mpProject = pProject;
mpObject = nullptr;
mpRootProperty = pRootProperty;
mpPropertyData = pPropertyData;
mProperties.clear();
mPropertyToIDMap.clear();
if (pRootProperty)
RecursiveBuildArrays(pRootProperty, -1);
endResetModel(); 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) if (HandleFlaggedIndices)
{ Index &= ~0x80000000;
void *pID = (void*) (rkIndex.internalId() & ~0x1);
return static_cast<IProperty*>(pID);
}
else else
return nullptr; 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(); // 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.
QVector<u32> RowNumbers; if (pProp->IsArrayArchetype())
IProperty *pChild = pProp;
CPropertyStruct *pParent = pProp->Parent();
while (pParent)
{ {
// Check for array with one sub-property while (pProp && pProp->IsArrayArchetype())
CPropertyStruct *pGrandparent = pParent->Parent(); pProp = pProp->Parent();
if (pGrandparent && pGrandparent->Type() == eArrayProperty && pParent->Count() == 1)
{
pChild = pParent;
pParent = pGrandparent;
continue;
}
// Find row index for this child property ASSERT(pProp != nullptr && pProp->Type() == EPropertyTypeNew::Array);
for (u32 iChild = 0; iChild < pParent->Count(); iChild++)
{
if (pParent->PropertyByIndex(iChild) == pChild)
{
RowNumbers << iChild;
break;
}
}
pChild = pParent;
pParent = pGrandparent;
} }
// Find the corresponding QModelIndex in the same spot if (pProp == mpRootProperty) return QModelIndex();
QModelIndex Index = QModelIndex();
for (int iChild = RowNumbers.size() - 1; iChild >= 0; iChild--) int ID = mPropertyToIDMap[pProp];
Index = index(RowNumbers[iChild], 0, Index); ASSERT(ID >= 0);
return Index; return mProperties[ID].Index;
} }
int CPropertyModel::columnCount(const QModelIndex& /*rkParent*/) const 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 int CPropertyModel::rowCount(const QModelIndex& rkParent) const
{ {
if (!mpBaseStruct) return 0; if (!mpRootProperty) return 0;
if (!rkParent.isValid()) return mpBaseStruct->Count(); if (!rkParent.isValid()) return mpRootProperty->NumChildren();
if (rkParent.column() != 0) return 0; 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()) switch (pProp->Type())
{ {
case eStructProperty: case EPropertyTypeNew::Flags:
case eArrayProperty: return TPropCast<CFlagsProperty>(pProp)->NumFlags();
return static_cast<CPropertyStruct*>(pProp)->Count();
case eBitfieldProperty: case EPropertyTypeNew::AnimationSet:
return static_cast<CBitfieldTemplate*>(pProp->Template())->NumFlags();
case eVector3Property:
return 3;
case eColorProperty:
return 4;
case eCharacterProperty:
{ {
CAnimationParameters Params = static_cast<TCharacterProperty*>(pProp)->Get(); CAnimationParameters Params = TPropCast<CAnimationSetProperty>(pProp)->Value(mpPropertyData);
if (Params.Version() <= eEchoes) return 3; if (Params.Version() <= eEchoes) return 3;
if (Params.Version() <= eCorruption) return 2; if (Params.Version() <= eCorruption) return 2;
return 4; return 4;
} }
default: 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) 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) CFlagsProperty* pFlags = TPropCast<CFlagsProperty>(pProp);
{
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());
if (rkIndex.column() == 0) if (rkIndex.column() == 0)
return TO_QSTRING(pBitfield->FlagName(rkIndex.row())); return TO_QSTRING( pFlags->FlagName(rkIndex.row()) );
if (rkIndex.column() == 1) if (rkIndex.column() == 1)
{ {
if (Role == Qt::DisplayRole) if (Role == Qt::DisplayRole)
return ""; return "";
else 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); CAnimationSetProperty* pAnimSet = TPropCast<CAnimationSetProperty>(pProp);
CAnimationParameters Params = pChar->Get(); CAnimationParameters Params = pAnimSet->Value(mpPropertyData);
// There are three different layouts for this property - one for MP1/2, one for MP3, and one for DKCR // There are three different layouts for this property - one for MP1/2, one for MP3, and one for DKCR
if (Params.Version() <= eEchoes) if (Params.Version() <= eEchoes)
@ -255,28 +237,18 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
else else
{ {
IProperty *pProp = PropertyForIndex(rkIndex, false); IPropertyNew *pProp = PropertyForIndex(rkIndex, false);
if (rkIndex.column() == 0) if (rkIndex.column() == 0)
{ {
// Check for arrays // 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) // For direct array sub-properties, display the element index after the name
if (pProp->Type() == eStructProperty && pParent->Type() == eArrayProperty) TString ElementName = pParent->Name();
{ return QString("%1 %2").arg( TO_QSTRING(ElementName) ).arg(rkIndex.row() + 1);
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);
}
} }
// Display property name for everything else // Display property name for everything else
@ -288,19 +260,20 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
switch (pProp->Type()) switch (pProp->Type())
{ {
// Enclose vector property text in parentheses // Enclose vector property text in parentheses
case eVector3Property: case EPropertyTypeNew::Vector:
return "(" + TO_QSTRING(pProp->ToString()) + ")"; {
CVector3f Value = TPropCast<CVectorProperty>(pProp)->Value(mpPropertyData);
return TO_QSTRING("(" + Value.ToString() + ")");
}
// Display the AGSC/sound name for sounds // Display the AGSC/sound name for sounds
case eSoundProperty: case EPropertyTypeNew::Sound:
{ {
TSoundProperty *pSound = static_cast<TSoundProperty*>(pProp); CSoundProperty* pSound = TPropCast<CSoundProperty>(pProp);
u32 SoundID = pSound->Get(); u32 SoundID = pSound->Value(mpPropertyData);
if (SoundID == -1) return "[None]"; if (SoundID == -1) return "[None]";
CGameProject *pProj = pSound->Instance()->Area()->Entry()->Project(); SSoundInfo SoundInfo = mpProject->AudioManager()->GetSoundInfo(SoundID);
SSoundInfo SoundInfo = pProj->AudioManager()->GetSoundInfo(SoundID);
QString Out = QString::number(SoundID); QString Out = QString::number(SoundID);
if (SoundInfo.DefineID == -1) if (SoundInfo.DefineID == -1)
@ -320,40 +293,47 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
} }
// Display character name for characters // Display character name for characters
case eCharacterProperty: case EPropertyTypeNew::AnimationSet:
return TO_QSTRING(static_cast<TCharacterProperty*>(pProp)->Get().GetCurrentCharacterName()); return TO_QSTRING(TPropCast<CAnimationSetProperty>(pProp)->Value(mpPropertyData).GetCurrentCharacterName());
// Display enumerator name for enums (but only on ToolTipRole) // Display enumerator name for enums (but only on ToolTipRole)
case eEnumProperty: case EPropertyTypeNew::Choice:
case EPropertyTypeNew::Enum:
if (Role == Qt::ToolTipRole) if (Role == Qt::ToolTipRole)
{ {
TEnumProperty *pEnum = static_cast<TEnumProperty*>(pProp); CEnumProperty *pEnum = TPropCast<CEnumProperty>(pProp);
CEnumTemplate *pTemp = static_cast<CEnumTemplate*>(pEnum->Template()); u32 ValueID = pEnum->Value(mpPropertyData);
return TO_QSTRING(pTemp->EnumeratorName( pTemp->EnumeratorIndex(pEnum->Get()) )); u32 ValueIndex = pEnum->ValueIndex(ValueID);
return TO_QSTRING( pEnum->ValueName(ValueIndex) );
} }
else return ""; else return "";
// Display the element count for arrays // 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" : ""); return QString("%1 element%2").arg(Count).arg(Count != 1 ? "s" : "");
} }
// Display "[MayaSpline]" for MayaSplines (todo: proper support) // Display "[spline]" for splines (todo: proper support)
case eMayaSplineProperty: case EPropertyTypeNew::Spline:
return "[MayaSpline]"; return "[spline]";
// No display text on properties with persistent editors // No display text on properties with persistent editors
case eBoolProperty: case EPropertyTypeNew::Bool:
case eAssetProperty: if (Role == Qt::DisplayRole)
case eColorProperty: return TPropCast<CBoolProperty>(pProp)->Value(mpPropertyData) ? "True" : "False";
else
return "";
case EPropertyTypeNew::Asset:
case EPropertyTypeNew::Color:
if (Role == Qt::DisplayRole) if (Role == Qt::DisplayRole)
return ""; return "";
// fall through // fall through
// Display property value to string for everything else // Display property value to string for everything else
default: 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)) if (!(rkIndex.internalId() & 0x1))
{ {
// Add name // Add name
IProperty *pProp = PropertyForIndex(rkIndex, false); IPropertyNew *pProp = PropertyForIndex(rkIndex, false);
QString DisplayText = data(rkIndex, Qt::DisplayRole).toString(); QString DisplayText = data(rkIndex, Qt::DisplayRole).toString();
QString Text = QString("<b>%1</b> <i>(%2)</i>").arg(DisplayText).arg(TO_QSTRING(PropEnumToPropString(pProp->Type()))); QString Text = QString("<b>%1</b> <i>(%2)</i>").arg(DisplayText).arg(TO_QSTRING(PropEnumToPropString(pProp->Type())));
// Add uncooked notification // Add uncooked notification
if (pProp->Template()->CookPreference() == eNeverCook) if (pProp->CookPreference() == ECookPreferenceNew::Never)
{ {
Text.prepend("<i>[uncooked]</i>"); Text.prepend("<i>[uncooked]</i>");
} }
// Add description // Add description
TString Desc = pProp->Template()->Description(); TString Desc = pProp->Description();
if (!Desc.IsEmpty()) Text += "<br/>" + TO_QSTRING(Desc); if (!Desc.IsEmpty()) Text += "<br/>" + TO_QSTRING(Desc);
// MayaSpline notification // Spline notification
if (pProp->Type() == eMayaSplineProperty) if (pProp->Type() == EPropertyTypeNew::Spline)
Text += "<br/><i>(NOTE: MayaSpline properties are currently unsupported for editing)</i>"; Text += "<br/><i>(NOTE: Spline properties are currently unsupported for editing)</i>";
return Text; return Text;
} }
@ -393,45 +373,12 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (mBoldModifiedProperties) if (mBoldModifiedProperties)
{ {
IProperty *pProp = PropertyForIndex(rkIndex, true); IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
if (!pProp->IsInArray()) if (!pProp->IsArrayArchetype())
{ {
if (rkIndex.internalId() & 0x1) Bold = !pProp->MatchesDefault(mpPropertyData);
{ }
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();
}
}
} }
Font.setBold(Bold); Font.setBold(Bold);
@ -445,17 +392,16 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const
if (Role == Qt::ForegroundRole) if (Role == Qt::ForegroundRole)
{ {
if (mShowNameValidity && mpBaseStruct->Template()->Game() >= eEchoesDemo) if (mShowNameValidity && mpRootProperty->ScriptTemplate()->Game() >= eEchoesDemo)
{ {
IProperty *pProp = PropertyForIndex(rkIndex, true); IPropertyNew *pProp = PropertyForIndex(rkIndex, true);
IPropertyTemplate *pTemp = (pProp ? pProp->Template() : nullptr);
// Don't highlight the name of the root property // 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 skRightColor = QColor(128, 255, 128);
static const QColor skWrongColor = QColor(255, 128, 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(); return QModelIndex();
// Check property for children // 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 (ParentType == EPropertyTypeNew::Flags || ParentType == EPropertyTypeNew::AnimationSet)
if (pParent->Type() == eStructProperty)
{ {
IProperty *pProp = static_cast<CPropertyStruct*>(pParent)->PropertyByIndex(Row); return createIndex(Row, Column, ParentID | 0x80000000);
return createIndex(Row, Column, pProp);
} }
else
// Array
if (pParent->Type() == eArrayProperty)
{ {
IProperty *pProp = static_cast<CArrayProperty*>(pParent)->PropertyByIndex(Row); int ChildID = mProperties[ParentID].ChildIDs[Row];
return createIndex(Row, Column, ChildID);
// 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);
} }
// 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 QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
@ -505,39 +437,14 @@ QModelIndex CPropertyModel::parent(const QModelIndex& rkChild) const
if (!rkChild.isValid()) if (!rkChild.isValid())
return QModelIndex(); return QModelIndex();
// Find parent property int ID = int(rkChild.internalId());
IProperty *pParent;
if (rkChild.internalId() & 0x1) if (ID & 0x80000000)
pParent = PropertyForIndex(rkChild, true); ID &= ~0x80000000;
else else
pParent = PropertyForIndex(rkChild, false)->Parent(); ID = mProperties[ID].ParentID;
if (pParent == mpBaseStruct) return mProperties[ID].Index;
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();
} }
Qt::ItemFlags CPropertyModel::flags(const QModelIndex& rkIndex) const 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); else return (Qt::ItemIsEnabled | Qt::ItemIsEditable);
} }
void CPropertyModel::NotifyPropertyModified(class CScriptObject*, IProperty *pProp) void CPropertyModel::NotifyPropertyModified(class CScriptObject*, IPropertyNew* pProp)
{ {
NotifyPropertyModified(IndexForProperty(pProp)); NotifyPropertyModified(IndexForProperty(pProp));
} }
@ -556,7 +463,7 @@ void CPropertyModel::NotifyPropertyModified(const QModelIndex& rkIndex)
if (rowCount(rkIndex) != 0) if (rowCount(rkIndex) != 0)
emit dataChanged( index(0, 0, rkIndex), index(rowCount(rkIndex) - 1, 1, rkIndex)); 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 Parent = rkIndex.parent();
QModelIndex Col0 = Parent.sibling(Parent.row(), 0); 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) 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)); CArrayProperty *pArray = static_cast<CArrayProperty*>(PropertyForIndex(Index, false));
if (pArray && pArray->Type() == eArrayProperty) if (pArray && pArray->Type() == eArrayProperty)
@ -587,12 +495,13 @@ void CPropertyModel::ArrayAboutToBeResized(const QModelIndex& rkIndex, u32 NewSi
else else
beginRemoveRows(Index, NewSize, OldSize - 1); beginRemoveRows(Index, NewSize, OldSize - 1);
} }
} }*/
} }
void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize) 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(); u32 NewSize = pArray->Count();
if (NewSize != OldSize) if (NewSize != OldSize)
@ -601,7 +510,7 @@ void CPropertyModel::ArrayResized(const QModelIndex& rkIndex, u32 OldSize)
endInsertRows(); endInsertRows();
else else
endRemoveRows(); endRemoveRows();
} }*/
} }
void CPropertyModel::SetShowPropertyNameValidity(bool Enable) void CPropertyModel::SetShowPropertyNameValidity(bool Enable)

View File

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

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