// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingObject.h" // Don't include Scripting.h but just FindObject method extern FLAXENGINE_API ScriptingObject* FindObject(const Guid& id, MClass* type); /// /// The scripting object soft reference. Objects gets referenced on use (ID reference is resolving it). /// class FLAXENGINE_API SoftObjectReferenceBase { public: typedef Delegate<> EventType; protected: ScriptingObject* _object = nullptr; Guid _id = Guid::Empty; public: /// /// Action fired when reference gets changed. /// EventType Changed; public: /// /// Initializes a new instance of the class. /// SoftObjectReferenceBase() { } /// /// Initializes a new instance of the class. /// /// The object to link. SoftObjectReferenceBase(ScriptingObject* obj) { OnSet(obj); } /// /// Finalizes an instance of the class. /// ~SoftObjectReferenceBase() { if (_object) _object->Deleted.Unbind(this); } public: /// /// Gets the object ID. /// /// The object ID or Guid::Empty if nothing assigned. Guid GetID() const { return _object ? _object->GetID() : _id; } protected: /// /// Sets the object. /// /// The object. void OnSet(ScriptingObject* object) { auto e = _object; if (e != object) { if (e) e->Deleted.Unbind(this); _object = e = object; _id = e ? e->GetID() : Guid::Empty; if (e) e->Deleted.Bind(this); Changed(); } } void OnDeleted(ScriptingObject* obj) { ASSERT(_object == obj); _object->Deleted.Unbind(this); _object = nullptr; Changed(); } }; /// /// The scripting object soft reference. Objects gets referenced on use (ID reference is resolving it). /// template API_CLASS(InBuild) class SoftObjectReference : public SoftObjectReferenceBase { public: typedef SoftObjectReference Type; public: /// /// Initializes a new instance of the class. /// SoftObjectReference() { } /// /// Initializes a new instance of the class. /// /// The object to link. SoftObjectReference(T* obj) : SoftObjectReferenceBase(obj) { } /// /// Initializes a new instance of the class. /// /// The other property. SoftObjectReference(const SoftObjectReference& other) : SoftObjectReferenceBase(other.Get()) { } /// /// Finalizes an instance of the class. /// ~SoftObjectReference() { } public: /// /// Compares the property value with the given object. /// /// The other. /// True if property object equals the given value. FORCE_INLINE bool operator==(T* other) { return Get() == other; } /// /// Compares the property value with the other property value. /// /// The other property. /// True if properties are equal. FORCE_INLINE bool operator==(const SoftObjectReference& other) { return _id == other._id; } /// /// Compares the property value with the given object. /// /// The other. /// True if property object not equals the given value. FORCE_INLINE bool operator!=(T* other) { return Get() != other; } /// /// Compares the property value with the other property value. /// /// The other property. /// True if properties are not equal. FORCE_INLINE bool operator!=(const SoftObjectReference& other) { return _id != other._id; } /// /// Sets the property to the given property value. /// /// The other property. /// The reference to this property. SoftObjectReference& operator=(const SoftObjectReference& other) { if (this != &other) OnSet(other.Get()); return *this; } /// /// Sets the property to the given value. /// /// The object. /// The reference to this property. FORCE_INLINE SoftObjectReference& operator=(const T& other) { OnSet(&other); return *this; } /// /// Sets the property to the given value. /// /// The object. /// The reference to this property. FORCE_INLINE SoftObjectReference& operator=(T* other) { OnSet(other); return *this; } /// /// Sets the property to the object of the given ID. /// /// The object ID. /// The reference to this property. FORCE_INLINE SoftObjectReference& operator=(const Guid& id) { Set(id); return *this; } /// /// Implicit conversion to the object. /// /// The object reference. FORCE_INLINE operator T*() const { return (T*)Get(); } /// /// Implicit conversion to boolean value. /// /// True if object has been assigned, otherwise false FORCE_INLINE operator bool() const { return _object != nullptr || _id.IsValid(); } /// /// Object accessor. /// /// The object reference. FORCE_INLINE T* operator->() const { return (T*)Get(); } /// /// Gets the object pointer. /// /// The object reference. T* Get() const { if (!_object) const_cast(this)->OnSet(FindObject(_id, T::GetStaticClass())); return (T*)_object; } /// /// Gets the object as a given type (static cast). /// /// Asset template FORCE_INLINE U* As() const { return static_cast(Get()); } public: /// /// Gets managed instance object (or null if no object linked). /// /// The managed object instance. MonoObject* GetManagedInstance() const { auto object = Get(); return object ? object->GetOrCreateManagedInstance() : nullptr; } /// /// Determines whether object is assigned and managed instance of the object is alive. /// /// True if managed object has been created and exists, otherwise false. bool HasManagedInstance() const { auto object = Get(); return object && object->HasManagedInstance(); } /// /// Gets the managed instance object or creates it if missing or null if not assigned. /// /// The Mono managed object. MonoObject* GetOrCreateManagedInstance() const { auto object = Get(); return object ? object->GetOrCreateManagedInstance() : nullptr; } /// /// Sets the object. /// /// The object ID. Uses Scripting to find the registered object of the given ID. void Set(const Guid& id) { _id = id; _object = nullptr; } /// /// Sets the object. /// /// The object. FORCE_INLINE void Set(T* object) { OnSet(object); } }; template uint32 GetHash(const SoftObjectReference& key) { return GetHash(key.GetID()); }