#pragma once #include #include #include #include "BsPrerequisitesUtil.h" #include "BsManagedDataBlock.h" #include "BsRTTIField.h" #include "BsRTTIPlainField.h" #include "BsRTTIReflectableField.h" #include "BsRTTIReflectablePtrField.h" #include "BsRTTIManagedDataBlockField.h" #include "BsIReflectable.h" #include "BsBinaryDiff.h" /** @addtogroup RTTI * @{ */ namespace BansheeEngine { #define BS_PLAIN_MEMBER(name) \ decltype(OwnerType::##name)& get##name(OwnerType* obj) { return obj->##name; } \ void set##name(OwnerType* obj, decltype(OwnerType::##name)& val) { obj->##name = val; } #define BS_REFL_MEMBER(name) \ decltype(OwnerType::##name)& get##name(OwnerType* obj) { return obj->##name; } \ void set##name(OwnerType* obj, decltype(OwnerType::##name)& val) { obj->##name = val; } #define BS_REFLPTR_MEMBER(name) \ decltype(OwnerType::##name) get##name(OwnerType* obj) { return obj->##name; } \ void set##name(OwnerType* obj, decltype(OwnerType::##name) val) { obj->##name = val; } #define BS_ADD_PLAIN_FIELD(name, id) \ addPlainField(#name, id##, &MyType::get##name, &MyType::set##name); #define BS_ADD_REFL_FIELD(name, id) \ addReflectableField(#name, id##, &MyType::get##name, &MyType::set##name); #define BS_ADD_REFLPTR_FIELD(name, id) \ addReflectablePtrField(#name, id##, &MyType::get##name, &MyType::set##name); #define BS_PLAIN_MEMBER_VEC(name) \ std::common_type::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->##name[idx]; } \ void set##name(OwnerType* obj, UINT32 idx, std::common_type::type::value_type& val) { obj->##name[idx] = val; } \ UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->##name.size(); } \ void setSize##name(OwnerType* obj, UINT32 val) { obj->##name.resize(val); } #define BS_REFL_MEMBER_VEC(name) \ std::common_type::type::value_type& get##name(OwnerType* obj, UINT32 idx) { return obj->##name[idx]; } \ void set##name(OwnerType* obj, UINT32 idx, std::common_type::type::value_type& val) { obj->##name[idx] = val; } \ UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->##name.size(); } \ void setSize##name(OwnerType* obj, UINT32 val) { obj->##name.resize(val); } #define BS_REFLPTR_MEMBER_VEC(name) \ std::common_type::type::value_type get##name(OwnerType* obj, UINT32 idx) { return obj->##name[idx]; } \ void set##name(OwnerType* obj, UINT32 idx, std::common_type::type::value_type val) { obj->##name[idx] = val; } \ UINT32 getSize##name(OwnerType* obj) { return (UINT32)obj->##name.size(); } \ void setSize##name(OwnerType* obj, UINT32 val) { obj->##name.resize(val); } #define BS_ADD_PLAIN_FIELD_ARR(name, id) \ addPlainArrayField(#name, id##, &MyType::get##name, &MyType::getSize##name, \ &MyType::set##name, &MyType::setSize##name); #define BS_ADD_REFL_FIELD_ARR(name, id) \ addReflectableArrayField(#name, id##, &MyType::get##name, &MyType::getSize##name, \ &MyType::set##name, &MyType::setSize##name); #define BS_ADD_REFLPTR_FIELD_ARR(name, id) \ addReflectablePtrArrayField(#name, id##, &MyType::get##name, &MyType::getSize##name, \ &MyType::set##name, &MyType::setSize##name); /** @cond INTERNAL */ /** * Provides an interface for accessing fields of a certain class. * Data can be easily accessed by getter and setter methods. * * Supported data types: * - Plain types - All types defined in BsRTTIField.h, mostly native types and POD (plain old data) structs. Data is parsed byte by byte. * No pointers to plain types are supported. Data is passed around by value. * - Reflectable types - Any class deriving from IReflectable. Data is parsed based on fields in its RTTI class. Can be pointer or value type. * - Arrays of both plain and reflectable types are supported * - Data blocks - A managed or unmanaged block of data. See ManagedDataBlock. */ class BS_UTILITY_EXPORT RTTITypeBase { public: RTTITypeBase(); virtual ~RTTITypeBase(); /** Returns RTTI type information for all classes that derive from the class that owns this RTTI type. */ virtual Vector& getDerivedClasses() = 0; /** * Returns RTTI type information for the class that owns this RTTI type. If the class has not base type, null is * returned instead. */ virtual RTTITypeBase* getBaseClass() = 0; /** Returns true if current RTTI class is derived from @p base. (Or if it is the same type as base) */ virtual bool isDerivedFrom(RTTITypeBase* base) = 0; /** * Called by the RTTI system when a class is first found in order to form child/parent class hierarchy. * * @note Internal method. */ virtual void _registerDerivedClass(RTTITypeBase* derivedClass) = 0; /** Creates a new instance of the class owning this RTTI type. */ virtual std::shared_ptr newRTTIObject() = 0; /** Returns the name of the class owning this RTTI type. */ virtual const String& getRTTIName() = 0; /** Returns an RTTI id that uniquely represents each class in the RTTI system. */ virtual UINT32 getRTTIId() = 0; /** * Called by the serializers when serialization for this object has started. Use this to do any preprocessing on * data you might need during serialization itself. */ virtual void onSerializationStarted(IReflectable* obj) {} /** * Called by the serializers when serialization for this object has ended. After serialization has ended you can * be sure that the type has been fully serialized, and you may clean up any temporary data. */ virtual void onSerializationEnded(IReflectable* obj) {} /** * Called by the serializers when deserialization for this object has started. Use this to do any preprocessing * on data you might need during deserialization itself. */ virtual void onDeserializationStarted(IReflectable* obj) {} /** * Called by the serializers when deserialization for this object has ended. At this point you can be sure the * instance has been fully deserialized and you may safely use it. * * One exception being are fields you marked with RTTI_Flag_WeakRef, as they might be resolved only after * deserialization has fully completed for all objects. */ virtual void onDeserializationEnded(IReflectable* obj) {} /** * Returns a handler that determines how are "diffs" generated and applied when it comes to objects of this RTTI * type. A "diff" is a list of differences between two objects that may be saved, viewed or applied to another * object to transform it. */ virtual IDiff& getDiffHandler() const { static BinaryDiff diffHandler; return diffHandler; } /** * Allows you to assign a value to a plain field with the specified name on the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setPlainValue(ObjectType* object, const String& name, DataType& value) { RTTIField* genericField = findField(name); genericField->checkIsPlain(false); RTTIPlainFieldBase* field = static_cast(genericField); UINT32 typeSize = 0; if(RTTIPlainType::hasDynamicSize) typeSize = RTTIPlainType::getDynamicSize(value); else typeSize = sizeof(DataType); UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize); RTTIPlainType::toMemory(value, (char*)tempBuffer); field->fromBuffer(object, tempBuffer); bs_stack_free(tempBuffer); } /** * Allows you to assign a value to a plain field array element with the specified name and index on the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setPlainArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value) { RTTIField* genericField = findField(name); genericField->checkIsPlain(true); RTTIPlainFieldBase* field = static_cast(genericField); UINT32 typeSize = 0; if(RTTIPlainType::hasDynamicSize) typeSize = RTTIPlainType::getDynamicSize(value); else typeSize = sizeof(DataType); UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize); RTTIPlainType::toMemory(value, (char*)tempBuffer); field->arrayElemFromBuffer(object, index, tempBuffer); bs_stack_free(tempBuffer); } /** * Allows you to assign a value to a reflectable field with the specified name on the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setReflectableValue(ObjectType* object, const String& name, DataType& value) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIField* genericField = findField(name); genericField->checkIsComplex(false); RTTIReflectableFieldBase* field = static_cast(genericField); field->setValue(object, value); } /** * Allows you to assign a value to a reflectable field array element with the specified name and index on the * provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setReflectableArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIField* genericField = findField(name); genericField->checkIsComplex(true); RTTIReflectableFieldBase* field = static_cast(genericField); field->setArrayValue(object, index, value); } /** * Allows you to assign a value to a managed data block field with the specified name on the provided instance. * * @note Caller must ensure instance type is valid for this field. */ template void setDataBlockValue(ObjectType* object, const String& name, ManagedDataBlock value) { RTTIField* genericField = findField(name); genericField->checkIsDataBlock(); RTTIManagedDataBlockFieldBase* field = static_cast(genericField); field->setValue(object, value); } /** * Allows you to assign a value to a reflectable pointer field with the specified name on the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setReflectablePtrValue(ObjectType* object, const String& name, std::shared_ptr value) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIField* genericField = findField(name); genericField->checkIsComplexPtr(false); RTTIReflectablePtrFieldBase* field = static_cast(genericField); field->setValue(object, value); } /** * Allows you to assign a value to a reflectable pointer field array element with the specified name and index on * the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void setReflectablePtrArrayValue(ObjectType* object, const String& name, UINT32 index, std::shared_ptr value) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIField* genericField = findField(name); genericField->checkIsComplexPtr(true); RTTIReflectablePtrFieldBase* field = static_cast(genericField); field->setArrayValue(object, index, value); } /** * Reads a value from a plain field with the specified name from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void getPlainValue(ObjectType* object, const String& name, DataType& value) { RTTIField* genericField = findField(name); genericField->checkIsPlain(false); RTTIPlainFieldBase* field = static_cast(genericField); UINT32 typeSize = 0; if(field->hasDynamicSize()) typeSize = field->getDynamicSize(object); else typeSize = field->getTypeSize(); UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize); field->toBuffer(object, tempBuffer); RTTIPlainType::fromMemory(value, (char*)tempBuffer); bs_stack_free(tempBuffer); } /** * Reads a value from a plain array field with the specified name and index from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template void getPlainArrayValue(ObjectType* object, const String& name, UINT32 index, DataType& value) { RTTIField* genericField = findField(name); genericField->checkIsPlain(true); RTTIPlainFieldBase* field = static_cast(genericField); UINT32 typeSize = 0; if(field->hasDynamicSize()) typeSize = field->getArrayElemDynamicSize(object, arrIdx); else typeSize = field->getTypeSize(); UINT8* tempBuffer = (UINT8*)bs_stack_alloc(typeSize); field->arrayElemToBuffer(object, index, tempBuffer); RTTIPlainType::fromMemory(value, (char*)tempBuffer); bs_stack_free(tempBuffer); } /** * Reads a value from a reflectable object field with the specified name from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template IReflectable& getReflectableValue(ObjectType* object, const String& name) { RTTIField* genericField = findField(name); genericField->checkIsComplex(false); RTTIReflectableFieldBase* field = static_cast(genericField); return field->getValue(object); } /** * Reads a value from a reflectable object array field with the specified name and index from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template IReflectable& getReflectableArrayValue(ObjectType* object, const String& name, UINT32 index) { RTTIField* genericField = findField(name); genericField->checkIsComplex(true); RTTIReflectableFieldBase* field = static_cast(genericField); return field->getArrayValue(object, index); } /** * Reads a managed data block field with the specified name from the provided instance. * * @note Caller must ensure instance type is valid for this field. */ template ManagedDataBlock getDataBlockValue(ObjectType* object, const String& name) { RTTIField* genericField = findField(name); genericField->checkIsDataBlock(); RTTIManagedDataBlockFieldBase* field = static_cast(genericField); return field->getValue(object); } /** * Reads a value from a reflectable object pointer field with the specified name from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template std::shared_ptr getReflectablePtrValue(ObjectType* object, const String& name) { RTTIField* genericField = findField(name); genericField->checkIsComplexPtr(false); RTTIReflectablePtrFieldBase* field = static_cast(genericField); return field->getValue(object); } /** * Reads a value from a reflectable pointer array field with the specified name and index from the provided instance. * * @note Caller must ensure instance and value types are valid for this field. */ template std::shared_ptr getReflectablePtrArrayValue(ObjectType* object, const String& name, UINT32 index) { RTTIField* genericField = findField(name); genericField->checkIsComplexPtr(true); RTTIReflectablePtrFieldBase* field = static_cast(genericField); return field->getArrayValue(object, index); } /** * Returns the size of the array of the field with the specified name on the provided instance. * * @note Caller must ensure instance type is valid and that the field as an array. */ template UINT32 getArraySize(ObjectType* object, const String& name) { RTTIField* field = findField(name); return field->getArraySize(object); } /** * Sets the size of the array of the field with the specified name on the provided instance. * * @note * Caller must ensure instance type is valid and that the field as an array. This might clear any existing data * from the array. */ template void setArraySize(ObjectType* object, const String& name, UINT32 size) { RTTIField* field = findField(name); field->setArraySize(object, size); } /** Returns the total number of fields in this RTTI type. */ UINT32 getNumFields() const { return (UINT32)mFields.size(); } /** Returns a field based on the field index. Use getNumFields() to get total number of fields available. */ RTTIField* getField(UINT32 idx) { return mFields.at(idx); } /** * Tries to find a field with the specified name. Throws an exception if it can't. * * @param name The name of the field. */ RTTIField* findField(const String& name); /** * Tries to find a field with the specified unique ID. Doesn't throw an exception if it can't find the field * (Unlike findField(const String&)). * * @param uniqueFieldId Unique identifier for the field. * * @return nullptr if it can't find the field. */ RTTIField* findField(int uniqueFieldId); protected: /** * Tries to add a new field to the fields array, and throws an exception if a field with the same name or id * already exists. * * @param[in] field Field, must be non-null. */ void addNewField(RTTIField* field); private: Vector mFields; }; /** Used for initializing a certain type as soon as the program is loaded. */ template struct InitRTTIOnStart { public: InitRTTIOnStart() { BaseType::getRTTIStatic()->_registerDerivedClass(Type::getRTTIStatic()); } void makeSureIAmInstantiated() { } }; /** Specialization for root class of RTTI hierarchy - IReflectable */ template struct InitRTTIOnStart { public: InitRTTIOnStart() { IReflectable::_registerDerivedClass(Type::getRTTIStatic()); } void makeSureIAmInstantiated() { } }; /** * Template that returns RTTI type of the specified type, unless the specified type is IReflectable in which case it * returns a null. */ template struct GetRTTIType { RTTITypeBase* operator()() { return Type::getRTTIStatic(); } }; /** Specialization for root class of RTTI hierarchy - IReflectable. */ template<> struct GetRTTIType { RTTITypeBase* operator()() { return nullptr; } }; /** @endcond */ /** * Allows you to provide a run-time type information for a specific class, along with support for * serialization/deserialization. * * Derive from this class and return the that class from IReflectable::getRTTI. This way you can separate serialization * logic from the actual class you're serializing. * * This class will provide a way to register individual fields in the class, together with ways to read and write them, * as well a providing information about class hierarchy, and run-time type checking. */ template class RTTIType : public RTTITypeBase { protected: /************************************************************************/ /* RTTI CLASS META DATA */ /************************************************************************/ static InitRTTIOnStart initOnStart; public: RTTIType() { // Compiler will only generate code for stuff that is directly used, including static data members, // so we fool it here like we're using the class directly. Otherwise compiler won't generate the code for the member // and our type won't get initialized on start (Actual behavior is a bit more random) initOnStart.makeSureIAmInstantiated(); } virtual ~RTTIType() {} /** Returns a singleton of this RTTI type. */ static MyRTTIType* instance() { static MyRTTIType inst; return &inst; } /** @copydoc RTTITypeBase::getDerivedClasses */ Vector& getDerivedClasses() override { static Vector mRTTIDerivedClasses; return mRTTIDerivedClasses; } /** @copydoc RTTITypeBase::getBaseClass */ RTTITypeBase* getBaseClass() override { return GetRTTIType()(); } /** @copydoc RTTITypeBase::isDerivedFrom */ bool isDerivedFrom(RTTITypeBase* base) override { assert(base != nullptr); Stack todo; todo.push(base); while (!todo.empty()) { RTTITypeBase* currentType = todo.top(); todo.pop(); if (currentType->getRTTIId() == getRTTIId()) return true; const Vector& derivedClasses = currentType->getDerivedClasses(); for (auto iter = derivedClasses.begin(); iter != derivedClasses.end(); ++iter) todo.push(*iter); } return false; } /** @copydoc RTTITypeBase::_registerDerivedClass */ void _registerDerivedClass(RTTITypeBase* derivedClass) override { if(IReflectable::_isTypeIdDuplicate(derivedClass->getRTTIId())) { BS_EXCEPT(InternalErrorException, "RTTI type \"" + derivedClass->getRTTIName() + "\" has a duplicate ID: " + toString(derivedClass->getRTTIId())); } getDerivedClasses().push_back(derivedClass); } /************************************************************************/ /* FIELDS OPERATING DIRECTLY ON SERIALIZABLE OBJECT */ /************************************************************************/ /** * Registers a new plain field. This field can then be accessed dynamically from the RTTI system and used for * automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving the value of this field. * @param[in] setter Method used for setting the value of this field. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addPlainField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(), void (ObjectType::*setter)(DataType&) = nullptr, UINT64 flags = 0) { addPlainField(name, uniqueId, std::function(getter), std::function(setter), flags); } /** * Registers a new reflectable object field. This field can then be accessed dynamically from the RTTI system and * used for automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving the value of this field. * @param[in] setter Method used for setting the value of this field. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addReflectableField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(), void (ObjectType::*setter)(DataType&) = nullptr, UINT64 flags = 0) { addReflectableField(name, uniqueId, std::function(getter), std::function(setter), flags); } /** * Registers a new reflectable object pointer field. This field can then be accessed dynamically from the RTTI * system and used for automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving the value of this field. * @param[in] setter Method used for setting the value of this field. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addReflectablePtrField(const String& name, UINT32 uniqueId, std::shared_ptr (ObjectType::*getter)(), void (ObjectType::*setter)(std::shared_ptr) = nullptr, UINT64 flags = 0) { addReflectablePtrField(name, uniqueId, std::function(ObjectType*)>(getter), std::function)>(setter), flags); } /** * Registers a new field containg an array of plain values. This field can then be accessed dynamically from the * RTTI system and used for automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving a single element of the array. * @param[in] getSize Getter method that returns the size of the array. * @param[in] setter Method used for setting the a single element of the field. * @param[in] setSize Setter method that allows you to resize the array. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addPlainArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), void (ObjectType::*setter)(UINT32, DataType&) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0) { addPlainArrayField(name, uniqueId, std::function(getter), std::function(getSize), std::function(setter), std::function(setSize), flags); } /** * Registers a new field containg an array of reflectable object values. This field can then be accessed dynamically * from the RTTI system and used for automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving a single element of the array. * @param[in] getSize Getter method that returns the size of the array. * @param[in] setter Method used for setting the a single element of the field. * @param[in] setSize Setter method that allows you to resize the array. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addReflectableArrayField(const String& name, UINT32 uniqueId, DataType& (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), void (ObjectType::*setter)(UINT32, DataType&) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0) { addReflectableArrayField(name, uniqueId, std::function(getter), std::function(getSize), std::function(setter), std::function(setSize), flags); } /** * Registers a new field containg an array of reflectable obejct pointers. This field can then be accessed * dynamically from the RTTI system and used for automatic serialization. See RTTIField for more information * about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving a single element of the array. * @param[in] getSize Getter method that returns the size of the array. * @param[in] setter Method used for setting the a single element of the field. * @param[in] setSize Setter method that allows you to resize the array. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, std::shared_ptr (ObjectType::*getter)(UINT32), UINT32 (ObjectType::*getSize)(), void (ObjectType::*setter)(UINT32, std::shared_ptr) = nullptr, void(ObjectType::*setSize)(UINT32) = nullptr, UINT64 flags = 0) { addReflectablePtrArrayField(name, uniqueId, std::function(ObjectType*, UINT32)>(getter), std::function(getSize), std::function)>(setter), std::function(setSize), flags); } /** * Registers a new managed data block field. This field can then be accessed dynamically from the RTTI system and * used for automatic serialization. See RTTIField for more information about field types. * * @param[in] name Name of the field. * @param[in] uniqueId Unique identifier for this field. Although name is also a unique identifier we want a * small data type that can be used for efficiently serializing data to disk and similar. * It is primarily used for compatibility between different versions of serialized data. * @param[in] getter Method used for retrieving the value of this field. * @param[in] setter Method used for setting the value of this field. * @param[in] flags Various flags you can use to specialize how systems handle this field. See RTTIFieldFlag. */ template void addDataBlockField(const String& name, UINT32 uniqueId, ManagedDataBlock (ObjectType::*getter)(), void (ObjectType::*setter)(ManagedDataBlock) = nullptr, UINT64 flags = 0, UINT8* (customAllocator)(ObjectType*, UINT32) = 0) { addDataBlockField(name, uniqueId, std::function(getter), std::function(setter), flags, customAllocator); } protected: typedef Type OwnerType; typedef MyRTTIType MyType; virtual void initSerializableFields() {} /************************************************************************/ /* FIELDS OPERATING ON DERIVED SERIALIZATION INTERFACE */ /* (Needs an extra pointer to the actual object) */ /************************************************************************/ template void addPlainField(const String& name, UINT32 uniqueId, DataType& (InterfaceType::*getter)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, DataType&), UINT64 flags = 0) { using namespace std::placeholders; static_assert((std::is_base_of, InterfaceType>::value), "Class with the get/set methods must derive from BansheeEngine::RTTIType."); static_assert(!(std::is_base_of::value), "Data type derives from IReflectable but it is being added as a plain field."); addPlainField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2)), flags); } template void addReflectableField(const String& name, UINT32 uniqueId, DataType& (InterfaceType::*getter)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, DataType&), UINT64 flags = 0) { using namespace std::placeholders; addReflectableField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2)), flags); } template void addReflectablePtrField(const String& name, UINT32 uniqueId, std::shared_ptr (InterfaceType::*getter)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, std::shared_ptr), UINT64 flags = 0) { using namespace std::placeholders; addReflectablePtrField(name, uniqueId, std::function(ObjectType*)>(std::bind(getter, static_cast(this), _1)), std::function)>(std::bind(setter, static_cast(this), _1, _2)), flags); } template void addPlainArrayField(const String& name, UINT32 uniqueId, DataType& (InterfaceType::*getter)(ObjectType*, UINT32), UINT32 (InterfaceType::*getSize)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&), void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0) { using namespace std::placeholders; static_assert((std::is_base_of, InterfaceType>::value), "Class with the get/set methods must derive from BansheeEngine::RTTIType."); static_assert(!(std::is_base_of::value), "Data type derives from IReflectable but it is being added as a plain field."); addPlainArrayField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1, _2)), std::function(std::bind(getSize, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2, _3)), std::function(std::bind(setSize, static_cast(this), _1, _2)), flags); } template void addReflectableArrayField(const String& name, UINT32 uniqueId, DataType& (InterfaceType::*getter)(ObjectType*, UINT32), UINT32 (InterfaceType::*getSize)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, UINT32, DataType&), void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0) { using namespace std::placeholders; addReflectableArrayField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1, _2)), std::function(std::bind(getSize, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2, _3)), std::function(std::bind(setSize, static_cast(this), _1, _2)), flags); } template void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, std::shared_ptr (InterfaceType::*getter)(ObjectType*, UINT32), UINT32 (InterfaceType::*getSize)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, UINT32, std::shared_ptr), void(InterfaceType::*setSize)(ObjectType*, UINT32), UINT64 flags = 0) { using namespace std::placeholders; addReflectablePtrArrayField(name, uniqueId, std::function(ObjectType*, UINT32)>(std::bind(getter, static_cast(this), _1, _2)), std::function(std::bind(getSize, static_cast(this), _1)), std::function)>(std::bind(setter, static_cast(this), _1, _2, _3)), std::function(std::bind(setSize, static_cast(this), _1, _2)), flags); } template void addDataBlockField(const String& name, UINT32 uniqueId, ManagedDataBlock (InterfaceType::*getter)(ObjectType*), void (InterfaceType::*setter)(ObjectType*, ManagedDataBlock), UINT64 flags = 0, UINT8* (customAllocator)(ObjectType*, UINT32) = 0) { using namespace std::placeholders; if(customAllocator != 0) { std::function customAllocFunc = std::bind(customAllocator, _1, _2); addDataBlockField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2)), flags, customAllocFunc); } else { addDataBlockField(name, uniqueId, std::function(std::bind(getter, static_cast(this), _1)), std::function(std::bind(setter, static_cast(this), _1, _2)), flags); } } private: template void addPlainField(const String& name, UINT32 uniqueId, Any getter, Any setter, UINT64 flags) { RTTIPlainField* newField = bs_new>(); newField->initSingle(name, uniqueId, getter, setter, flags); addNewField(newField); } template void addReflectableField(const String& name, UINT32 uniqueId, Any getter, Any setter, UINT64 flags) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIReflectableField* newField = bs_new>(); newField->initSingle(name, uniqueId, getter, setter, flags); addNewField(newField); } template void addReflectablePtrField(const String& name, UINT32 uniqueId, Any getter, Any setter, UINT64 flags) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIReflectablePtrField* newField = bs_new>(); newField->initSingle(name, uniqueId, getter, setter, flags); addNewField(newField); } template void addPlainArrayField(const String& name, UINT32 uniqueId, Any getter, Any getSize, Any setter, Any setSize, UINT64 flags) { RTTIPlainField* newField = bs_new>(); newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags); addNewField(newField); } template void addReflectableArrayField(const String& name, UINT32 uniqueId, Any getter, Any getSize, Any setter, Any setSize, UINT64 flags) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIReflectableField* newField = bs_new>(); newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags); addNewField(newField); } template void addReflectablePtrArrayField(const String& name, UINT32 uniqueId, Any getter, Any getSize, Any setter, Any setSize, UINT64 flags) { static_assert((std::is_base_of::value), "Invalid data type for complex field. It needs to derive from BansheeEngine::IReflectable."); RTTIReflectablePtrField* newField = bs_new>(); newField->initArray(name, uniqueId, getter, getSize, setter, setSize, flags); addNewField(newField); } template void addDataBlockField(const String& name, UINT32 uniqueId, Any getter, Any setter, UINT64 flags, Any customAllocator = Any()) { RTTIManagedDataBlockField* newField = bs_new>(); newField->initSingle(name, uniqueId, getter, setter, flags, customAllocator); addNewField(newField); } }; template InitRTTIOnStart RTTIType::initOnStart; /** Returns true if the provided object can be safely cast into type T. */ template bool rtti_is_of_type(IReflectable* object) { static_assert((std::is_base_of::value), "Invalid data type for type checking. It needs to derive from BansheeEngine::IReflectable."); return object->getTypeId() == T::getRTTIStatic()->getRTTIId(); } /** Returns true if the provided object can be safely cast into type T. */ template bool rtti_is_of_type(std::shared_ptr object) { static_assert((std::is_base_of::value), "Invalid data type for type checking. It needs to derive from BansheeEngine::IReflectable."); return object->getTypeId() == T::getRTTIStatic()->getRTTIId(); } /** Creates a new object just from its type ID. */ std::shared_ptr rtti_create(UINT32 rttiId); /** Checks is the current object a subclass of some type. */ template bool rtti_is_subclass(IReflectable* object) { static_assert((std::is_base_of::value), "Invalid data type for type checking. It needs to derive from BansheeEngine::IReflectable."); return object->isDerivedFrom(T::getRTTIStatic()); } /** @} */ }