// 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());
}