gzdoom-gles/src/dobjtype.h
Christoph Oelckers fc9e304189 - separated class descriptors from VM types.
Combining these two groups of data has been the cause of many hard to detect errors because it allowed liberal casting between types that are used for completely different things.
2017-04-12 22:46:49 +02:00

816 lines
25 KiB
C++

#ifndef DOBJTYPE_H
#define DOBJTYPE_H
#ifndef __DOBJECT_H__
#error You must #include "dobject.h" to get dobjtype.h
#endif
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
class PStruct;
// This is intentionally not in vm.h so that this file remains free of DObject pollution.
class VMException : public DObject
{
DECLARE_CLASS(VMException, DObject);
};
#include "vm.h"
// Variable/parameter/field flags -------------------------------------------
// Making all these different storage types use a common set of flags seems
// like the simplest thing to do.
enum
{
VARF_Optional = (1<<0), // func param is optional
VARF_Method = (1<<1), // func has an implied self parameter
VARF_Action = (1<<2), // func has implied owner and state parameters
VARF_Native = (1<<3), // func is native code, field is natively defined
VARF_ReadOnly = (1<<4), // field is read only, do not write to it
VARF_Private = (1<<5), // field is private to containing class
VARF_Protected = (1<<6), // field is only accessible by containing class and children.
VARF_Deprecated = (1<<7), // Deprecated fields should output warnings when used.
VARF_Virtual = (1<<8), // function is virtual
VARF_Final = (1<<9), // Function may not be overridden in subclasses
VARF_In = (1<<10),
VARF_Out = (1<<11),
VARF_Implicit = (1<<12), // implicitly created parameters (i.e. do not compare types when checking function signatures)
VARF_Static = (1<<13),
VARF_InternalAccess = (1<<14), // overrides VARF_ReadOnly for internal script code.
VARF_Override = (1<<15), // overrides a virtual function from the parent class.
VARF_Ref = (1<<16), // argument is passed by reference.
VARF_Transient = (1<<17), // don't auto serialize field.
VARF_Meta = (1<<18), // static class data (by necessity read only.)
VARF_VarArg = (1<<19), // [ZZ] vararg: don't typecheck values after ... in function signature
VARF_UI = (1<<20), // [ZZ] ui: object is ui-scope only (can't modify playsim)
VARF_Play = (1<<21), // [ZZ] play: object is playsim-scope only (can't access ui)
VARF_VirtualScope = (1<<22), // [ZZ] virtualscope: object should use the scope of the particular class it's being used with (methods only)
VARF_ClearScope = (1<<23), // [ZZ] clearscope: this method ignores the member access chain that leads to it and is always plain data.
};
// An action function -------------------------------------------------------
struct FState;
struct StateCallData;
class VMFrameStack;
struct VMValue;
struct VMReturn;
class VMFunction;
struct FNamespaceManager;
// Basic information shared by all types ------------------------------------
// Only one copy of a type is ever instantiated at one time.
// - Enums, classes, and structs are defined by their names and outer classes.
// - Pointers are uniquely defined by the type they point at.
// - ClassPointers are also defined by their class restriction.
// - Arrays are defined by their element type and count.
// - DynArrays are defined by their element type.
// - Maps are defined by their key and value types.
// - Prototypes are defined by the argument and return types.
// - Functions are defined by their names and outer objects.
// In table form:
// Outer Name Type Type2 Count
// Enum * *
// Class * *
// Struct * *
// Function * *
// Pointer *
// ClassPointer + *
// Array * *
// DynArray *
// Map * *
// Prototype *+ *+
struct ZCC_ExprConstant;
class PType : public PTypeBase
{
DECLARE_ABSTRACT_CLASS(PType, PTypeBase)
protected:
public:
PClass *TypeTableType; // The type to use for hashing into the type table
unsigned int Size; // this type's size
unsigned int Align; // this type's preferred alignment
PType *HashNext; // next type in this type table
PSymbolTable Symbols;
bool MemberOnly = false; // type may only be used as a struct/class member but not as a local variable or function argument.
FString mDescriptiveName;
VersionInfo mVersion = { 0,0,0 };
uint8_t loadOp, storeOp, moveOp, RegType, RegCount;
PType(unsigned int size = 1, unsigned int align = 1);
virtual ~PType();
virtual bool isNumeric() { return false; }
// Writes the value of a variable of this type at (addr) to an archive, preceded by
// a tag indicating its type. The tag is there so that variable types can be changed
// without completely breaking savegames, provided that the change isn't between
// totally unrelated types.
virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const;
// Returns true if the stored value was compatible. False otherwise.
// If the value was incompatible, then the memory at *addr is unchanged.
virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const;
// Sets the default value for this type at (base + offset)
// If the default value is binary 0, then this function doesn't need
// to do anything, because PClass::Extend() takes care of that.
//
// The stroffs array is so that types that need special initialization
// and destruction (e.g. strings) can add their offsets to it for special
// initialization when the object is created and destruction when the
// object is destroyed.
virtual void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL);
virtual void SetPointer(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL);
virtual void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const;
// Initialize the value, if needed (e.g. strings)
virtual void InitializeValue(void *addr, const void *def) const;
// Destroy the value, if needed (e.g. strings)
virtual void DestroyValue(void *addr) const;
// Sets the value of a variable of this type at (addr)
virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val);
// Gets the value of a variable of this type at (addr)
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
// Gets the opcode to store from a register to memory
int GetStoreOp() const
{
return storeOp;
}
// Gets the opcode to load from memory to a register
int GetLoadOp() const
{
return loadOp;
}
// Gets the opcode to move from register to another register
int GetMoveOp() const
{
return moveOp;
}
// Gets the register type for this type
int GetRegType() const
{
return RegType;
}
int GetRegCount() const
{
return RegCount;
}
// Returns true if this type matches the two identifiers. Referring to the
// above table, any type is identified by at most two characteristics. Each
// type that implements this function will cast these to the appropriate type.
// It is up to the caller to make sure they are the correct types. There is
// only one prototype for this function in order to simplify type table
// management.
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
// Get the type IDs used by IsMatch
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
const char *DescriptiveName() const;
static void StaticInit();
};
// Not-really-a-type types --------------------------------------------------
class PErrorType : public PType
{
DECLARE_CLASS(PErrorType, PType);
public:
PErrorType(int which = 1) : PType(0, which) {}
};
class PVoidType : public PType
{
DECLARE_CLASS(PVoidType, PType);
public:
PVoidType() : PType(0, 1) {}
};
// Some categorization typing -----------------------------------------------
class PBasicType : public PType
{
DECLARE_ABSTRACT_CLASS(PBasicType, PType);
public:
PBasicType();
PBasicType(unsigned int size, unsigned int align);
};
class PCompoundType : public PType
{
DECLARE_ABSTRACT_CLASS(PCompoundType, PType);
};
class PContainerType : public PCompoundType
{
DECLARE_ABSTRACT_CLASS(PContainerType, PCompoundType);
public:
PTypeBase *Outer; // object this type is contained within
FName TypeName; // this type's name
PContainerType() : Outer(NULL) {
mDescriptiveName = "NamedType";
}
PContainerType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {
mDescriptiveName = name.GetChars();
}
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
virtual PField *AddField(FName name, PType *type, uint32_t flags = 0) = 0;
virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) = 0;
};
// Basic types --------------------------------------------------------------
class PInt : public PBasicType
{
DECLARE_CLASS(PInt, PBasicType);
public:
PInt(unsigned int size, bool unsign, bool compatible = true);
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
virtual bool isNumeric() override { return IntCompatible; }
bool Unsigned;
bool IntCompatible;
protected:
PInt();
void SetOps();
};
class PBool : public PInt
{
DECLARE_CLASS(PBool, PInt);
public:
PBool();
virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
};
class PFloat : public PBasicType
{
DECLARE_CLASS(PFloat, PBasicType);
public:
PFloat(unsigned int size);
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val);
virtual int GetValueInt(void *addr) const;
virtual double GetValueFloat(void *addr) const;
virtual bool isNumeric() override { return true; }
protected:
PFloat();
void SetOps();
private:
struct SymbolInitF
{
ENamedName Name;
double Value;
};
struct SymbolInitI
{
ENamedName Name;
int Value;
};
void SetSingleSymbols();
void SetDoubleSymbols();
void SetSymbols(const SymbolInitF *syminit, size_t count);
void SetSymbols(const SymbolInitI *syminit, size_t count);
};
class PString : public PBasicType
{
DECLARE_CLASS(PString, PBasicType);
public:
PString();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
};
// Variations of integer types ----------------------------------------------
class PName : public PInt
{
DECLARE_CLASS(PName, PInt);
public:
PName();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
};
class PSound : public PInt
{
DECLARE_CLASS(PSound, PInt);
public:
PSound();
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
};
class PSpriteID : public PInt
{
DECLARE_CLASS(PSpriteID, PInt);
public:
PSpriteID();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PTextureID : public PInt
{
DECLARE_CLASS(PTextureID, PInt);
public:
PTextureID();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PColor : public PInt
{
DECLARE_CLASS(PColor, PInt);
public:
PColor();
};
class PStateLabel : public PInt
{
DECLARE_CLASS(PStateLabel, PInt);
public:
PStateLabel();
};
// Pointers -----------------------------------------------------------------
class PPointer : public PBasicType
{
DECLARE_CLASS(PPointer, PBasicType);
public:
typedef void(*WriteHandler)(FSerializer &ar, const char *key, const void *addr);
typedef bool(*ReadHandler)(FSerializer &ar, const char *key, void *addr);
PPointer();
PPointer(PType *pointsat, bool isconst = false);
PType *PointedType;
bool IsConst;
WriteHandler writer = nullptr;
ReadHandler reader = nullptr;
void InstallHandlers(WriteHandler w, ReadHandler r)
{
writer = w;
reader = r;
}
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
protected:
void SetOps();
};
class PStatePointer : public PPointer
{
DECLARE_CLASS(PStatePointer, PPointer);
public:
PStatePointer();
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
};
class PObjectPointer : public PPointer
{
DECLARE_CLASS(PObjectPointer, PPointer);
public:
PObjectPointer(PClass *pointedtype = nullptr, bool isconst = false);
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
PClass *PointedClass() const;
};
class PClassPointer : public PPointer
{
DECLARE_CLASS(PClassPointer, PPointer);
public:
PClassPointer(class PClass *restrict = nullptr);
class PClass *ClassRestriction;
bool isCompatible(PType *type);
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special = NULL) override;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
};
// Compound types -----------------------------------------------------------
class PEnum : public PInt
{
DECLARE_CLASS(PEnum, PInt);
public:
PEnum(FName name, PTypeBase *outer);
PTypeBase *Outer;
FName EnumName;
protected:
PEnum();
};
class PArray : public PCompoundType
{
DECLARE_CLASS(PArray, PCompoundType);
public:
PArray(PType *etype, unsigned int ecount);
PType *ElementType;
unsigned int ElementCount;
unsigned int ElementSize;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *special) override;
protected:
PArray();
};
class PStaticArray : public PArray
{
DECLARE_CLASS(PStaticArray, PArray);
public:
PStaticArray(PType *etype);
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
PStaticArray();
};
class PDynArray : public PCompoundType
{
DECLARE_CLASS(PDynArray, PCompoundType);
public:
PDynArray(PType *etype, PStruct *backing);
PType *ElementType;
PStruct *BackingType;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FSerializer &ar, const char *key, const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key, void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
void SetPointerArray(void *base, unsigned offset, TArray<size_t> *ptrofs = NULL) const override;
protected:
PDynArray();
};
class PMap : public PCompoundType
{
DECLARE_CLASS(PMap, PCompoundType);
public:
PMap(PType *keytype, PType *valtype);
PType *KeyType;
PType *ValueType;
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
PMap();
};
class PStruct : public PContainerType
{
DECLARE_CLASS(PStruct, PContainerType);
public:
PStruct(FName name, PTypeBase *outer, bool isnative = false);
bool isNative;
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it.
VMFunction *mConstructor = nullptr;
VMFunction *mDestructor = nullptr;
virtual PField *AddField(FName name, PType *type, uint32_t flags=0);
virtual PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0);
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) override;
void SetPointer(void *base, unsigned offset, TArray<size_t> *specials) override;
protected:
PStruct();
};
class PPrototype : public PCompoundType
{
DECLARE_CLASS(PPrototype, PCompoundType);
public:
PPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
TArray<PType *> ArgumentTypes;
TArray<PType *> ReturnTypes;
size_t PropagateMark();
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
protected:
PPrototype();
};
// Meta-info for every class derived from DObject ---------------------------
enum
{
TentativeClass = UINT_MAX,
};
class PClassType : public PContainerType
{
DECLARE_CLASS(PClassType, PContainerType);
private:
public:
PClass *Descriptor;
PClassType *ParentType;
PClassType(PClass *cls = nullptr);
PField *AddField(FName name, PType *type, uint32_t flags = 0) override;
PField *AddNativeField(FName name, PType *type, size_t address, uint32_t flags = 0, int bitvalue = 0) override;
};
class PClass
{
protected:
void Derive(PClass *newclass, FName name);
void InitializeSpecials(void *addr, void *defaults, TArray<FTypeAndOffset> PClass::*Inits);
void SetSuper();
public:
void WriteAllFields(FSerializer &ar, const void *addr) const;
bool ReadAllFields(FSerializer &ar, void *addr) const;
void InitializeDefaults();
int FindVirtualIndex(FName name, PPrototype *proto);
PSymbol *FindSymbol(FName symname, bool searchparents) const;
PField *AddField(FName name, PType *type, uint32_t flags);
static void StaticInit();
static void StaticShutdown();
static void StaticBootstrap();
// Per-class information -------------------------------------
PClass *ParentClass = nullptr; // the class this class derives from
const size_t *Pointers = nullptr; // object pointers defined by this class *only*
const size_t *FlatPointers = nullptr; // object pointers defined by this class and all its superclasses; not initialized by default
const size_t *ArrayPointers = nullptr; // dynamic arrays containing object pointers.
uint8_t *Defaults = nullptr;
uint8_t *Meta = nullptr; // Per-class static script data
unsigned Size = sizeof(DObject);
unsigned MetaSize = 0;
FName TypeName;
FName SourceLumpName;
bool bRuntimeClass = false; // class was defined at run-time, not compile-time
bool bDecorateClass = false; // may be subject to some idiosyncracies due to DECORATE backwards compatibility
bool bAbstract = false;
bool bOptional = false;
TArray<VMFunction*> Virtuals; // virtual function table
TArray<FTypeAndOffset> MetaInits;
TArray<FTypeAndOffset> SpecialInits;
TArray<PField *> Fields;
PClassType *VMType = nullptr;
void (*ConstructNative)(void *);
// The rest are all functions and static data ----------------
PClass();
~PClass();
void InsertIntoHash();
DObject *CreateNew();
PClass *CreateDerivedClass(FName name, unsigned int size);
void InitializeActorInfo();
void BuildFlatPointers();
void BuildArrayPointers();
void DestroySpecials(void *addr);
void DestroyMeta(void *addr);
const PClass *NativeClass() const;
// Returns true if this type is an ancestor of (or same as) the passed type.
bool IsAncestorOf(const PClass *ti) const
{
while (ti)
{
if (this == ti)
return true;
ti = ti->ParentClass;
}
return false;
}
inline bool IsDescendantOf(const PClass *ti) const
{
return ti->IsAncestorOf(this);
}
inline bool IsDescendantOf(FName ti) const
{
auto me = this;
while (me)
{
if (me->TypeName == ti)
return true;
me = me->ParentClass;
}
return false;
}
// Find a type, given its name.
const PClass *FindParentClass(FName name) const;
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); }
static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); }
static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); }
static PClass *FindClass(FName name);
static PClassActor *FindActor(const char *name) { return FindActor(FName(name, true)); }
static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); }
static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); }
static PClassActor *FindActor(FName name);
static VMFunction *FindFunction(FName cls, FName func);
static void FindFunction(VMFunction **pptr, FName cls, FName func);
PClass *FindClassTentative(FName name);
static TMap<FName, PClass*> ClassMap;
static TArray<PClass *> AllClasses;
static TArray<VMFunction**> FunctionPtrList;
static bool bShutdown;
static bool bVMOperational;
};
// Type tables --------------------------------------------------------------
struct FTypeTable
{
enum { HASH_SIZE = 1021 };
PType *TypeHash[HASH_SIZE];
PType *FindType(PClass *metatype, intptr_t parm1, intptr_t parm2, size_t *bucketnum);
void AddType(PType *type, PClass *metatype, intptr_t parm1, intptr_t parm2, size_t bucket);
void AddType(PType *type);
void Clear();
static size_t Hash(const PClass *p1, intptr_t p2, intptr_t p3);
};
extern FTypeTable TypeTable;
// Returns a type from the TypeTable. Will create one if it isn't present.
PMap *NewMap(PType *keytype, PType *valuetype);
PArray *NewArray(PType *type, unsigned int count);
PStaticArray *NewStaticArray(PType *type);
PDynArray *NewDynArray(PType *type);
PPointer *NewPointer(PType *type, bool isconst = false);
PPointer *NewPointer(PClass *type, bool isconst = false);
PClassPointer *NewClassPointer(PClass *restrict);
PEnum *NewEnum(FName name, PTypeBase *outer);
PStruct *NewStruct(FName name, PTypeBase *outer, bool native = false);
PPrototype *NewPrototype(const TArray<PType *> &rettypes, const TArray<PType *> &argtypes);
PClassType *NewClassType(PClass *cls);
// Built-in types -----------------------------------------------------------
extern PErrorType *TypeError;
extern PErrorType *TypeAuto;
extern PVoidType *TypeVoid;
extern PInt *TypeSInt8, *TypeUInt8;
extern PInt *TypeSInt16, *TypeUInt16;
extern PInt *TypeSInt32, *TypeUInt32;
extern PBool *TypeBool;
extern PFloat *TypeFloat32, *TypeFloat64;
extern PString *TypeString;
extern PName *TypeName;
extern PSound *TypeSound;
extern PColor *TypeColor;
extern PTextureID *TypeTextureID;
extern PSpriteID *TypeSpriteID;
extern PStruct *TypeVector2;
extern PStruct *TypeVector3;
extern PStruct *TypeColorStruct;
extern PStruct *TypeStringStruct;
extern PStatePointer *TypeState;
extern PPointer *TypeFont;
extern PStateLabel *TypeStateLabel;
extern PPointer *TypeNullPtr;
extern PPointer *TypeVoidPtr;
// Enumerations for serializing types in an archive -------------------------
inline bool &DObject::BoolVar(FName field)
{
return *(bool*)ScriptVar(field, TypeBool);
}
inline int &DObject::IntVar(FName field)
{
return *(int*)ScriptVar(field, TypeSInt32);
}
inline FSoundID &DObject::SoundVar(FName field)
{
return *(FSoundID*)ScriptVar(field, TypeSound);
}
inline PalEntry &DObject::ColorVar(FName field)
{
return *(PalEntry*)ScriptVar(field, TypeColor);
}
inline FName &DObject::NameVar(FName field)
{
return *(FName*)ScriptVar(field, TypeName);
}
inline double &DObject::FloatVar(FName field)
{
return *(double*)ScriptVar(field, TypeFloat64);
}
inline FString &DObject::StringVar(FName field)
{
return *(FString*)ScriptVar(field, TypeString);
}
template<class T>
inline T *&DObject::PointerVar(FName field)
{
return *(T**)ScriptVar(field, nullptr); // pointer check is more tricky and for the handful of uses in the DECORATE parser not worth the hassle.
}
void RemoveUnusedSymbols();
#endif