/
redgpu
/
ezEngine
Обзор
Документация
Войти
/
redgpu
/
ezEngine
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
Code/Engine/Foundation/Reflection/Implementation/AbstractProperty.h
704 строки
27 KB
Jan Krassnigg
Improved documentation of the Foundation library (#1664)
20 сен 2025, 19:53
Не верифицирован
20 сен 2025, 19:53
0e28096
Код
Авторство
О чём код?
#pragma once /// \file #include <Foundation/Basics.h> #include <Foundation/Containers/HashSet.h> #include <Foundation/Containers/HashTable.h> #include <Foundation/Containers/Map.h> #include <Foundation/Containers/Set.h> #include <Foundation/Containers/SmallArray.h> #include <Foundation/Containers/StaticArray.h> #include <Foundation/Reflection/Implementation/RTTI.h> #include <Foundation/Types/Bitflags.h> #include <Foundation/Types/Enum.h> class ezRTTI; class ezPropertyAttribute; /// \brief Determines whether a type is ezIsBitflags. template <typename T> struct ezIsBitflags { static constexpr bool value = false; }; template <typename T> struct ezIsBitflags<ezBitflags<T>> { static constexpr bool value = true; }; /// \brief Determines whether a type is ezIsBitflags. template <typename T> struct ezIsEnum { static constexpr bool value = std::is_enum<T>::value; }; template <typename T> struct ezIsEnum<ezEnum<T>> { static constexpr bool value = true; }; /// \brief Flags used to describe a property and its type. struct ezPropertyFlags { using StorageType = ezUInt16; enum Enum : ezUInt16 { StandardType = EZ_BIT(0), ///< Anything that can be stored inside an ezVariant except for pointers and containers. IsEnum = EZ_BIT(1), ///< enum property, cast to ezAbstractEnumerationProperty. Bitflags = EZ_BIT(2), ///< Bitflags property, cast to ezAbstractEnumerationProperty. Class = EZ_BIT(3), ///< A struct or class. All of the above are mutually exclusive. Const = EZ_BIT(4), ///< Property value is const. Reference = EZ_BIT(5), ///< Property value is a reference. Pointer = EZ_BIT(6), ///< Property value is a pointer. PointerOwner = EZ_BIT(7), ///< This pointer property takes ownership of the passed pointer. ReadOnly = EZ_BIT(8), ///< Can only be read but not modified. Hidden = EZ_BIT(9), ///< This property should not appear in the UI. Phantom = EZ_BIT(10), ///< Phantom types are mirrored types on the editor side. Ie. they do not exist as actual classes in the process. Also used ///< for data driven types, e.g. by the Visual Shader asset. VarOut = EZ_BIT(11), ///< Tag for non-const-ref function parameters to indicate usage 'out' VarInOut = EZ_BIT(12), ///< Tag for non-const-ref function parameters to indicate usage 'inout' PureFunction = Const, ///< The visual script function doesn't need an execution pin. Default = 0, Void = 0 }; struct Bits { StorageType StandardType : 1; StorageType IsEnum : 1; StorageType Bitflags : 1; StorageType Class : 1; StorageType Const : 1; StorageType Reference : 1; StorageType Pointer : 1; StorageType PointerOwner : 1; StorageType ReadOnly : 1; StorageType Hidden : 1; StorageType Phantom : 1; StorageType VarOut : 1; StorageType VarInOut : 1; StorageType PureFunction : 1; }; template <class Type> static ezBitflags<ezPropertyFlags> GetParameterFlags() { using CleanType = typename ezTypeTraits<Type>::NonConstReferencePointerType; ezBitflags<ezPropertyFlags> flags; constexpr ezVariantType::Enum type = static_cast<ezVariantType::Enum>(ezVariantTypeDeduction<CleanType>::value); if constexpr (std::is_same<CleanType, ezVariant>::value || std::is_same<Type, const char*>::value || // We treat const char* as a basic type and not a pointer. (type >= ezVariantType::FirstStandardType && type <= ezVariantType::LastStandardType)) flags.Add(ezPropertyFlags::StandardType); else if constexpr (ezIsEnum<CleanType>::value) flags.Add(ezPropertyFlags::IsEnum); else if constexpr (ezIsBitflags<CleanType>::value) flags.Add(ezPropertyFlags::Bitflags); else flags.Add(ezPropertyFlags::Class); if constexpr (std::is_const<typename ezTypeTraits<Type>::NonReferencePointerType>::value) flags.Add(ezPropertyFlags::Const); if constexpr (std::is_pointer<Type>::value && !std::is_same<Type, const char*>::value) flags.Add(ezPropertyFlags::Pointer); if constexpr (std::is_reference<Type>::value) flags.Add(ezPropertyFlags::Reference); return flags; } }; template <> inline ezBitflags<ezPropertyFlags> ezPropertyFlags::GetParameterFlags<void>() { return ezBitflags<ezPropertyFlags>(); } EZ_DECLARE_FLAGS_OPERATORS(ezPropertyFlags) /// \brief Describes what category a property belongs to. struct ezPropertyCategory { using StorageType = ezUInt8; enum Enum { Constant, ///< The property is a constant value that is stored inside the RTTI data. Member, ///< The property is a 'member property', i.e. it represents some accessible value. Cast to ezAbstractMemberProperty. Function, ///< The property is a function which can be called. Cast to ezAbstractFunctionProperty. Array, ///< The property is actually an array of values. The array dimensions might be changeable. Cast to ezAbstractArrayProperty. Set, ///< The property is actually a set of values. Cast to ezAbstractSetProperty. Map, ///< The property is actually a map from string to values. Cast to ezAbstractMapProperty. Default = Member }; }; /// \brief Base interface for all properties in the reflection system. /// /// Properties represent accessible data members, functions, or virtual data in reflected types. /// This base class provides the common interface and metadata for property introspection. /// /// Property categories: /// - Constant: Compile-time constant values stored in RTTI data /// - Member: Object data members with getter/setter access /// - Function: Callable methods with parameters and return values /// - Array: Container properties with indexed access /// - Set: Collection properties with unique elements /// - Map: Key-value pair collections /// /// Key features: /// - Property flags for type information (const, reference, pointer, etc.) /// - Attribute system for metadata (UI hints, validation, etc.) /// - Type-safe casting to specific property interfaces /// - Hierarchical property introspection /// /// Usage: Properties are typically registered through reflection macros rather than created manually. class EZ_FOUNDATION_DLL ezAbstractProperty { public: /// \brief The constructor must get the name of the property. The string must be a compile-time constant. ezAbstractProperty(const char* szPropertyName) { m_szPropertyName = szPropertyName; } virtual ~ezAbstractProperty(); /// \brief Returns the name of the property. const char* GetPropertyName() const { return m_szPropertyName; } /// \brief Returns the type information of the constant property. Use this to cast this property to a specific version of /// ezTypedConstantProperty. virtual const ezRTTI* GetSpecificType() const = 0; /// \brief Returns the category of this property. Cast this property to the next higher type for more information. virtual ezPropertyCategory::Enum GetCategory() const = 0; // [tested] /// \brief Returns the flags of the property. const ezBitflags<ezPropertyFlags>& GetFlags() const { return m_Flags; }; /// \brief Adds flags to the property. Returns itself to allow to be called during initialization. ezAbstractProperty* AddFlags(ezBitflags<ezPropertyFlags> flags) { m_Flags.Add(flags); return this; }; /// \brief Adds attributes to the property. Returns itself to allow to be called during initialization. Allocate an attribute using /// standard 'new'. ezAbstractProperty* AddAttributes(ezPropertyAttribute* pAttrib1, ezPropertyAttribute* pAttrib2 = nullptr, ezPropertyAttribute* pAttrib3 = nullptr, ezPropertyAttribute* pAttrib4 = nullptr, ezPropertyAttribute* pAttrib5 = nullptr, ezPropertyAttribute* pAttrib6 = nullptr) { EZ_ASSERT_DEV(pAttrib1 != nullptr, "invalid attribute"); m_Attributes.PushBack(pAttrib1); if (pAttrib2) m_Attributes.PushBack(pAttrib2); if (pAttrib3) m_Attributes.PushBack(pAttrib3); if (pAttrib4) m_Attributes.PushBack(pAttrib4); if (pAttrib5) m_Attributes.PushBack(pAttrib5); if (pAttrib6) m_Attributes.PushBack(pAttrib6); return this; }; /// \brief Returns the array of property attributes. ezArrayPtr<const ezPropertyAttribute* const> GetAttributes() const { return m_Attributes; } /// \brief Returns the first attribute that derives from the given type, or nullptr if nothing is found. template <typename Type> const Type* GetAttributeByType() const; protected: ezBitflags<ezPropertyFlags> m_Flags; const char* m_szPropertyName; ezHybridArray<const ezPropertyAttribute*, 2, ezStaticsAllocatorWrapper> m_Attributes; // Do not track RTTI data. }; /// \brief This is the base class for all constant properties that are stored inside the RTTI data. class EZ_FOUNDATION_DLL ezAbstractConstantProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractConstantProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } /// \brief Returns ezPropertyCategory::Constant. virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Constant; } // [tested] /// \brief Returns a pointer to the constant data or nullptr. See ezAbstractMemberProperty::GetPropertyPointer for more information. virtual void* GetPropertyPointer() const = 0; /// \brief Returns the constant value as an ezVariant virtual ezVariant GetConstant() const = 0; }; /// \brief Base class for properties that represent data members of a class or struct. /// /// Member properties provide access to object data through getter/setter mechanisms or direct memory access. /// They support both simple types (int, float) and complex types (classes, structs) with proper type safety. /// /// Access patterns: /// - Direct pointer access: GetPropertyPointer() for in-place modification /// - Value access: GetValuePtr()/SetValuePtr() for type-safe copying /// - Variant access: Through ezReflectionUtils for dynamic typing /// /// Important: If ezPropertyFlags::Pointer is set, you must use GetValuePtr/SetValuePtr instead of casting /// to ezTypedMemberProperty, because pointer properties have different type semantics. /// /// Performance considerations: /// - Direct pointer access is fastest but requires type knowledge /// - Value copying is safer but involves memory operations /// - Custom accessors (functions) add virtual call overhead class EZ_FOUNDATION_DLL ezAbstractMemberProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractMemberProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } /// \brief Returns ezPropertyCategory::Member. virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Member; } /// \brief Returns a pointer to the property data or nullptr. If a valid pointer is returned, that pointer and the information from /// GetSpecificType() can be used to step deeper into the type (if required). /// /// You need to pass the pointer to an object on which you are operating. This function is mostly of interest when the property itself is /// a compound type (a struct or class). If it is a simple type (int, float, etc.) it doesn't make much sense to retrieve the pointer. /// /// For example GetSpecificType() might return that a property is of type ezVec3. In that case one might either stop and just use the code /// to handle ezVec3 types, or one might continue and enumerate all sub-properties (x, y and z) as well. /// /// \note There is no guarantee that this function returns a non-nullptr pointer, independent of the type. When a property uses custom /// 'accessors' (functions to get / set the property value), it is not possible (or useful) to get the property pointer. virtual void* GetPropertyPointer(const void* pInstance) const = 0; /// \brief Writes the value of this property in pInstance to pObject. /// pObject needs to point to an instance of this property's type. virtual void GetValuePtr(const void* pInstance, void* out_pObject) const = 0; /// \brief Sets the value of pObject to the property in pInstance. /// pObject needs to point to an instance of this property's type. virtual void SetValuePtr(void* pInstance, const void* pObject) const = 0; }; /// \brief Base class for properties that represent arrays or sequential containers. /// /// Array properties provide indexed access to collections of elements with dynamic or fixed sizing. /// They support all standard container operations: access, insertion, removal, and resizing. /// /// Supported container types: /// - ezDynamicArray, ezHybridArray, ezStaticArray /// - Standard arrays (T[N]) /// - Custom containers implementing the array interface /// /// Key operations: /// - Indexed access: GetValue()/SetValue() by index /// - Dynamic sizing: SetCount(), Insert(), Remove() /// - Bulk operations: Clear() for efficiency /// /// Performance considerations: /// - GetCount() may involve virtual calls for dynamic containers /// - Insert/Remove operations may require element shifting /// - SetCount() can be expensive for complex element types /// - GetValuePointer() provides direct access when available class EZ_FOUNDATION_DLL ezAbstractArrayProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractArrayProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } /// \brief Returns ezPropertyCategory::Array. virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Array; } /// \brief Returns number of elements. virtual ezUInt32 GetCount(const void* pInstance) const = 0; /// \brief Writes element at index uiIndex to the target of pObject. virtual void GetValue(const void* pInstance, ezUInt32 uiIndex, void* pObject) const = 0; /// \brief Writes the target of pObject to the element at index uiIndex. virtual void SetValue(void* pInstance, ezUInt32 uiIndex, const void* pObject) const = 0; /// \brief Inserts the target of pObject into the array at index uiIndex. virtual void Insert(void* pInstance, ezUInt32 uiIndex, const void* pObject) const = 0; /// \brief Removes the element in the array at index uiIndex. virtual void Remove(void* pInstance, ezUInt32 uiIndex) const = 0; /// \brief Clears the array. virtual void Clear(void* pInstance) const = 0; /// \brief Resizes the array to uiCount. virtual void SetCount(void* pInstance, ezUInt32 uiCount) const = 0; virtual void* GetValuePointer(void* pInstance, ezUInt32 uiIndex) const { EZ_IGNORE_UNUSED(pInstance); EZ_IGNORE_UNUSED(uiIndex); return nullptr; } }; /// \brief Base class for properties that represent sets or unique value collections. /// /// Set properties provide collection semantics with unique elements and no ordering guarantees. /// They support standard set operations: insertion, removal, membership testing, and enumeration. /// /// Supported set types: /// - ezSet (tree-based, ordered) /// - ezHashSet (hash-based, unordered) /// - Custom containers implementing the set interface /// /// Element type restrictions: /// - Standard types (int, float, string, etc.) /// - Pointer types (for object references) /// - Types with proper equality and hash operations /// /// Performance characteristics: /// - Contains(): O(log n) for ezSet, O(1) average for ezHashSet /// - Insert/Remove: O(log n) for ezSet, O(1) average for ezHashSet /// - GetValues(): O(n) - creates a copy of all elements class EZ_FOUNDATION_DLL ezAbstractSetProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractSetProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } /// \brief Returns ezPropertyCategory::Set. virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Set; } /// \brief Returns whether the set is empty. virtual bool IsEmpty(const void* pInstance) const = 0; /// \brief Clears the set. virtual void Clear(void* pInstance) const = 0; /// \brief Inserts the target of pObject into the set. virtual void Insert(void* pInstance, const void* pObject) const = 0; /// \brief Removes the target of pObject from the set. virtual void Remove(void* pInstance, const void* pObject) const = 0; /// \brief Returns whether the target of pObject is in the set. virtual bool Contains(const void* pInstance, const void* pObject) const = 0; /// \brief Writes the content of the set to out_keys. virtual void GetValues(const void* pInstance, ezDynamicArray<ezVariant>& out_keys) const = 0; }; /// \brief Base class for properties that represent maps or key-value collections. /// /// Map properties provide associative container semantics with string keys and typed values. /// They support standard map operations: key-based access, insertion, removal, and enumeration. /// /// Supported map types: /// - ezMap (tree-based, ordered by key) /// - ezHashTable (hash-based, unordered) /// - Custom containers implementing the map interface /// /// Key restrictions: /// - Keys are always strings (const char*) /// - Keys must be valid UTF-8 strings /// - Key comparison is case-sensitive /// /// Value type restrictions: /// - Standard types (int, float, string, etc.) /// - Pointer types (for object references) /// - Complex types supported through reflection /// /// Performance characteristics: /// - GetValue/Contains: O(log n) for ezMap, O(1) average for ezHashTable /// - Insert/Remove: O(log n) for ezMap, O(1) average for ezHashTable /// - GetKeys: O(n) - creates a copy of all key strings class EZ_FOUNDATION_DLL ezAbstractMapProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractMapProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } /// \brief Returns ezPropertyCategory::Map. virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Map; } /// \brief Returns whether the set is empty. virtual bool IsEmpty(const void* pInstance) const = 0; /// \brief Clears the set. virtual void Clear(void* pInstance) const = 0; /// \brief Inserts the target of pObject into the set. virtual void Insert(void* pInstance, const char* szKey, const void* pObject) const = 0; /// \brief Removes the target of pObject from the set. virtual void Remove(void* pInstance, const char* szKey) const = 0; /// \brief Returns whether the target of pObject is in the set. virtual bool Contains(const void* pInstance, const char* szKey) const = 0; /// \brief Writes element at index uiIndex to the target of pObject. virtual bool GetValue(const void* pInstance, const char* szKey, void* pObject) const = 0; /// \brief Writes the content of the set to out_keys. virtual void GetKeys(const void* pInstance, ezHybridArray<ezString, 16>& out_keys) const = 0; }; /// \brief Use getArgument<N, Args...>::Type to get the type of the Nth argument in Args. template <int _Index, class... Args> struct getArgument; template <class Head, class... Tail> struct getArgument<0, Head, Tail...> { using Type = Head; }; template <int _Index, class Head, class... Tail> struct getArgument<_Index, Head, Tail...> { using Type = typename getArgument<_Index - 1, Tail...>::Type; }; /// \brief Template that allows to probe a function for a parameter and return type. template <int I, typename FUNC> struct ezFunctionParameterTypeResolver { }; template <int I, typename R, typename... P> struct ezFunctionParameterTypeResolver<I, R (*)(P...)> { enum Constants { Arguments = sizeof...(P), }; static_assert(I < Arguments, "I needs to be smaller than the number of function parameters."); using ParameterType = typename getArgument<I, P...>::Type; using ReturnType = R; }; template <int I, class Class, typename R, typename... P> struct ezFunctionParameterTypeResolver<I, R (Class::*)(P...)> { enum Constants { Arguments = sizeof...(P), }; static_assert(I < Arguments, "I needs to be smaller than the number of function parameters."); using ParameterType = typename getArgument<I, P...>::Type; using ReturnType = R; }; template <int I, class Class, typename R, typename... P> struct ezFunctionParameterTypeResolver<I, R (Class::*)(P...) const> { enum Constants { Arguments = sizeof...(P), }; static_assert(I < Arguments, "I needs to be smaller than the number of function parameters."); using ParameterType = typename getArgument<I, P...>::Type; using ReturnType = R; }; /// \brief Template that allows to probe a single parameter function for parameter and return type. template <typename FUNC> struct ezMemberFunctionParameterTypeResolver { }; template <class Class, typename R, typename P> struct ezMemberFunctionParameterTypeResolver<R (Class::*)(P)> { using ParameterType = P; using ReturnType = R; }; /// \brief Template that allows to probe a container for its element type. template <typename CONTAINER> struct ezContainerSubTypeResolver { }; template <typename T> struct ezContainerSubTypeResolver<ezArrayPtr<T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T> struct ezContainerSubTypeResolver<ezDynamicArray<T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T, ezUInt32 Size> struct ezContainerSubTypeResolver<ezHybridArray<T, Size>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T, ezUInt32 Size> struct ezContainerSubTypeResolver<ezStaticArray<T, Size>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T, ezUInt16 Size> struct ezContainerSubTypeResolver<ezSmallArray<T, Size>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T> struct ezContainerSubTypeResolver<ezDeque<T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T> struct ezContainerSubTypeResolver<ezSet<T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename T> struct ezContainerSubTypeResolver<ezHashSet<T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename K, typename T> struct ezContainerSubTypeResolver<ezHashTable<K, T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; template <typename K, typename T> struct ezContainerSubTypeResolver<ezMap<K, T>> { using Type = typename ezTypeTraits<T>::NonConstReferenceType; }; /// \brief Describes what kind of function a property is. struct ezFunctionType { using StorageType = ezUInt8; enum Enum { Member, ///< A normal member function, a valid instance pointer must be provided to call. StaticMember, ///< A static member function, instance pointer will be ignored. Constructor, ///< A constructor. Return value is a void* pointing to the new instance allocated with the default allocator. Default = Member }; }; /// \brief Base class for properties that represent callable functions or methods. /// /// Function properties enable runtime invocation of methods with type-safe parameter passing /// and return value handling. They support member functions, static functions, and constructors. /// /// Function types: /// - Member: Instance methods requiring a valid object pointer /// - StaticMember: Static methods, instance pointer ignored /// - Constructor: Special functions that create new objects /// /// Parameter handling: /// - Standard types: Passed by value, exact type matching required /// - Enums/Bitflags: Passed as ezInt64 values through ezEnum/ezBitflags /// - Classes: Always passed by pointer regardless of declaration /// - Out parameters: Written back to source variants after execution /// - Null values: Represented as invalid variants (except for ezVariant parameters) /// /// Performance considerations: /// - Function calls involve virtual dispatch and parameter marshaling /// - Parameter conversion can be expensive for complex types /// - Out parameter writeback requires variant assignments /// - Constructor calls include allocation overhead class EZ_FOUNDATION_DLL ezAbstractFunctionProperty : public ezAbstractProperty { public: /// \brief Passes the property name through to ezAbstractProperty. ezAbstractFunctionProperty(const char* szPropertyName) : ezAbstractProperty(szPropertyName) { } virtual ezPropertyCategory::Enum GetCategory() const override { return ezPropertyCategory::Function; } /// \brief Returns the type of function, see ezFunctionPropertyType::Enum. virtual ezFunctionType::Enum GetFunctionType() const = 0; /// \brief Returns the type of the return value. virtual const ezRTTI* GetReturnType() const = 0; /// \brief Returns property flags of the return value. virtual ezBitflags<ezPropertyFlags> GetReturnFlags() const = 0; /// \brief Returns the number of arguments. virtual ezUInt32 GetArgumentCount() const = 0; /// \brief Returns the type of the given argument. virtual const ezRTTI* GetArgumentType(ezUInt32 uiParamIndex) const = 0; /// \brief Returns the property flags of the given argument. virtual ezBitflags<ezPropertyFlags> GetArgumentFlags(ezUInt32 uiParamIndex) const = 0; /// \brief Calls the function. Provide the instance on which the function is supposed to be called. /// /// arguments must be the size of GetArgumentCount, the following rules apply for both arguments and return value: /// Any standard type must be provided by value, even if it is a pointer to one. Types must match exactly, no ConvertTo is called. /// enum and bitflags are supported if ezEnum / ezBitflags is used, value must be provided as ezInt64. /// Out values (&, *) are written back to the variant they were read from. /// Any class is provided by pointer, regardless of whether it is a pointer or not. /// The returnValue must only be valid if the return value is a ref or by value class. In that case /// returnValue must be a ptr to a valid class instance of the returned type. /// An invalid variant is equal to a nullptr, except for if the argument is of type ezVariant, in which case /// it is impossible to pass along a nullptr. virtual void Execute(void* pInstance, ezArrayPtr<ezVariant> arguments, ezVariant& out_returnValue) const = 0; virtual const ezRTTI* GetSpecificType() const override { return GetReturnType(); } /// \brief Adds flags to the property. Returns itself to allow to be called during initialization. ezAbstractFunctionProperty* AddFlags(ezBitflags<ezPropertyFlags> flags) { return static_cast<ezAbstractFunctionProperty*>(ezAbstractProperty::AddFlags(flags)); } /// \brief Adds attributes to the property. Returns itself to allow to be called during initialization. Allocate an attribute using /// standard 'new'. ezAbstractFunctionProperty* AddAttributes(ezPropertyAttribute* pAttrib1, ezPropertyAttribute* pAttrib2 = nullptr, ezPropertyAttribute* pAttrib3 = nullptr, ezPropertyAttribute* pAttrib4 = nullptr, ezPropertyAttribute* pAttrib5 = nullptr, ezPropertyAttribute* pAttrib6 = nullptr) { return static_cast<ezAbstractFunctionProperty*>(ezAbstractProperty::AddAttributes(pAttrib1, pAttrib2, pAttrib3, pAttrib4, pAttrib5, pAttrib6)); } };