// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Scripting/ScriptingObject.h" 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 { protected: ScriptingObject* _object = nullptr; Guid _id = Guid::Empty; public: /// /// Action fired when reference gets changed. /// Delegate<> Changed; public: NON_COPYABLE(SoftObjectReferenceBase); /// /// Initializes a new instance of the class. /// SoftObjectReferenceBase() { } /// /// Finalizes an instance of the class. /// ~SoftObjectReferenceBase() { if (_object) _object->Deleted.Unbind(this); } public: /// /// Gets the object ID. /// Guid GetID() const { return _id; } protected: void OnSet(ScriptingObject* object) { if (_object == object) return; if (_object) _object->Deleted.Unbind(this); _object = object; _id = object ? object->GetID() : Guid::Empty; if (object) object->Deleted.Bind(this); Changed(); } void OnSet(const Guid& id) { if (_id == id) return; if (_object) _object->Deleted.Unbind(this); _object = nullptr; _id = id; Changed(); } void OnResolve(MClass* type) { ASSERT(!_object); _object = FindObject(_id, type); if (_object) _object->Deleted.Bind(this); } void OnDeleted(ScriptingObject* obj) { ASSERT(_object == obj); _object->Deleted.Unbind(this); _object = nullptr; _id = Guid::Empty; 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) { OnSet((ScriptingObject*)obj); } /// /// Initializes a new instance of the class. /// /// The other property. SoftObjectReference(const SoftObjectReference& other) { OnSet(other.GetID()); } /// /// Initializes a new instance of the class. /// /// The other property. SoftObjectReference(SoftObjectReference&& other) { OnSet(other.GetID()); other.OnSet(nullptr); } /// /// Finalizes an instance of the class. /// ~SoftObjectReference() { } public: FORCE_INLINE bool operator==(T* other) { return Get() == other; } FORCE_INLINE bool operator==(const SoftObjectReference& other) { return GetID() == other.GetID(); } FORCE_INLINE bool operator!=(T* other) { return Get() != other; } FORCE_INLINE bool operator!=(const SoftObjectReference& other) { return GetID() != other.GetID(); } SoftObjectReference& operator=(const SoftObjectReference& other) { if (this != &other) OnSet(other.GetID()); return *this; } SoftObjectReference& operator=(SoftObjectReference&& other) { if (this != &other) { OnSet(other.GetID()); other.OnSet(nullptr); } return *this; } FORCE_INLINE SoftObjectReference& operator=(const T& other) { OnSet(&other); return *this; } FORCE_INLINE SoftObjectReference& operator=(T* other) { OnSet(other); return *this; } FORCE_INLINE SoftObjectReference& operator=(const Guid& id) { OnSet(id); return *this; } FORCE_INLINE operator T*() const { return (T*)Get(); } FORCE_INLINE operator bool() const { return Get() != nullptr; } FORCE_INLINE T* operator->() const { return (T*)Get(); } template FORCE_INLINE U* As() const { return static_cast(Get()); } public: /// /// Gets the object (or null if unassigned). /// T* Get() const { if (!_object) const_cast(this)->OnResolve(T::GetStaticClass()); return (T*)_object; } /// /// Gets managed instance object (or null if no object linked). /// MObject* GetManagedInstance() const { auto object = Get(); return object ? object->GetOrCreateManagedInstance() : nullptr; } /// /// Determines whether object is assigned and managed instance of the object is alive. /// 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. /// MObject* 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. FORCE_INLINE void Set(const Guid& id) { OnSet(id); } /// /// Sets the object. /// /// The object. FORCE_INLINE void Set(T* object) { OnSet(object); } }; template uint32 GetHash(const SoftObjectReference& key) { return GetHash(key.GetID()); }