// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.Runtime.CompilerServices;
// ReSharper disable UnassignedReadonlyField
// ReSharper disable InconsistentNaming
#pragma warning disable 649
namespace FlaxEngine
{
///
/// Base class for all objects Flax can reference. Every object has unique identifier.
///
[Serializable]
public abstract class Object
{
///
/// The pointer to the unmanaged object (native C++ instance).
///
[NonSerialized]
protected readonly IntPtr __unmanagedPtr;
///
/// The object unique identifier.
///
[NonSerialized]
protected readonly Guid __internalId;
///
/// Gets the unique object ID.
///
public Guid ID => __internalId;
///
/// Gets a full name of the object type including leading namespace and any nested types names. Uniquely identifies the object type and can be used to find it via name.
///
public string TypeName => Internal_GetTypeName(__unmanagedPtr);
///
/// Initializes a new instance of the .
///
protected Object()
{
// Construct missing native object if managed objects gets created in managed world
if (__unmanagedPtr == IntPtr.Zero)
{
Internal_ManagedInstanceCreated(this);
if (__unmanagedPtr == IntPtr.Zero)
throw new Exception($"Failed to create native instance for object of type {GetType().FullName} (assembly: {GetType().Assembly.FullName}).");
}
}
///
/// Notifies the unmanaged interop object that the managed instance was finalized.
///
~Object()
{
// Inform unmanaged world that managed instance has been deleted
if (__unmanagedPtr != IntPtr.Zero)
{
Internal_ManagedInstanceDeleted(__unmanagedPtr);
}
}
///
/// Casts this object instance to the given object type.
///
/// object actor type.
/// The object instance cast to the given actor type.
public T As() where T : Actor
{
return (T)this;
}
///
/// Creates the new instance of the C# object.
///
/// Type of the object.
/// Created object.
public static object NewValue([TypeReference(typeof(object))] Type type)
{
return Activator.CreateInstance(type);
}
///
/// Creates the new instance of the Object.
/// All unused objects should be released using .
///
/// Full name of the type of the object.
/// Created object.
public static Object New([TypeReference(typeof(Object))] string typeName)
{
return Internal_Create2(typeName);
}
///
/// Creates the new instance of the Object.
/// All unused objects should be released using .
///
/// Type of the object.
/// Created object.
[HideInEditor]
public static T New() where T : Object
{
return Internal_Create1(typeof(T)) as T;
}
///
/// Creates the new instance of the Object.
/// All unused objects should be released using .
///
/// Type of the object.
/// Created object.
[HideInEditor]
public static Object New(Type type)
{
return Internal_Create1(type);
}
///
/// Finds the object with the given ID. Searches registered scene objects and assets.
///
/// Unique ID of the object.
/// Type of the object.
/// Found object or null if missing.
public static T Find(ref Guid id) where T : Object
{
return Internal_FindObject(ref id, typeof(T)) as T;
}
///
/// Finds the object with the given ID. Searches registered scene objects and assets.
///
/// Unique ID of the object.
/// Type of the object.
/// Found object or null if missing.
public static Object Find(ref Guid id, Type type)
{
return Internal_FindObject(ref id, type);
}
///
/// Tries to find the object by the given identifier. Searches only registered scene objects.
///
/// Unique ID of the object.
/// Type of the object.
/// Found object or null if missing.
public static T TryFind(ref Guid id) where T : Object
{
return Internal_TryFindObject(ref id, typeof(T)) as T;
}
///
/// Tries to find the object by the given identifier. Searches only registered scene objects.
///
/// Unique ID of the object.
/// Type of the object.
/// Found object or null if missing.
public static Object TryFind(ref Guid id, Type type)
{
return Internal_TryFindObject(ref id, type);
}
///
/// Destroys the specified object and clears the reference variable.
/// The object obj will be destroyed now or after the time specified in seconds from now.
/// If obj is a Script it will be removed from the Actor and deleted.
/// If obj is an Actor it will be removed from the Scene and deleted as well as all its Scripts and all children of the Actor.
/// Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.
///
/// The object to destroy.
/// The time left to destroy object (in seconds).
public static void Destroy(Object obj, float timeLeft = 0.0f)
{
Internal_Destroy(GetUnmanagedPtr(obj), timeLeft);
}
///
/// Destroys the specified object and clears the reference variable.
/// The object obj will be destroyed now or after the time specified in seconds from now.
/// If obj is a Script it will be removed from the Actor and deleted.
/// If obj is an Actor it will be removed from the Scene and deleted as well as all its Scripts and all children of the Actor.
/// Actual object destruction is always delayed until after the current Update loop, but will always be done before rendering.
///
/// The object to destroy.
/// The time left to destroy object (in seconds).
public static void Destroy(ref T obj, float timeLeft = 0.0f) where T : Object
{
if (obj)
{
Internal_Destroy(obj.__unmanagedPtr, timeLeft);
obj = null;
}
}
///
/// Checks if the object exists (reference is not null and the unmanaged object pointer is valid).
///
/// The object to check.
/// True if object is valid, otherwise false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator bool(Object obj)
{
return obj != null && obj.__unmanagedPtr != IntPtr.Zero;
}
///
/// Checks whether the two objects are equal.
///
///
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Object left, Object right)
{
IntPtr leftPtr = (object)left != null ? left.__unmanagedPtr : IntPtr.Zero;
IntPtr rightPtr = (object)right != null ? right.__unmanagedPtr : IntPtr.Zero;
return leftPtr == rightPtr;
}
///
/// Checks whether the two objects are not equal.
///
///
///
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Object left, Object right)
{
IntPtr leftPtr = (object)left != null ? left.__unmanagedPtr : IntPtr.Zero;
IntPtr rightPtr = (object)right != null ? right.__unmanagedPtr : IntPtr.Zero;
return leftPtr != rightPtr;
}
///
public override bool Equals(object obj)
{
if (obj is FlaxEngine.Object o)
return o.__unmanagedPtr == __unmanagedPtr;
return false;
}
///
/// Gets the pointer to the native object. Handles null object reference (returns zero).
///
/// The object.
/// The native object pointer.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IntPtr GetUnmanagedPtr(Object obj)
{
return obj?.__unmanagedPtr ?? IntPtr.Zero;
}
internal static IntPtr GetUnmanagedPtr(SoftObjectReference reference)
{
return GetUnmanagedPtr(reference.Get