// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.Marshalling; // 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] [NativeMarshalling(typeof(ObjectMarshaller))] public abstract partial 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; } /// /// 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()); } /// /// Gets the pointer to the native interface implementation. Handles null object reference or invalid cast (returns zero). /// /// The object. /// The interface type. /// The native interface pointer. public static IntPtr GetUnmanagedInterface(object obj, Type type) { return obj is Object o ? Internal_GetUnmanagedInterface(o.__unmanagedPtr, type) : IntPtr.Zero; } /// /// Gets the managed object from the native object pointer. /// /// The pointer to the unmanaged (native) object. /// The object. [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::FromUnmanagedPtr", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] public static partial Object FromUnmanagedPtr(IntPtr ptr); /// public override int GetHashCode() { return __unmanagedPtr.GetHashCode(); } #region Internal Calls [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create1", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial Object Internal_Create1([MarshalUsing(typeof(SystemTypeMarshaller))] Type type); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Create2", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial Object Internal_Create2(string typeName); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceCreated", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial void Internal_ManagedInstanceCreated(Object managedInstance); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ManagedInstanceDeleted", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial void Internal_ManagedInstanceDeleted(IntPtr nativeInstance); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_Destroy", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial void Internal_Destroy(IntPtr obj, float timeLeft); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetTypeName", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial string Internal_GetTypeName(IntPtr obj); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_FindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial Object Internal_FindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_TryFindObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial Object Internal_TryFindObject(ref Guid id, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_ChangeID", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial void Internal_ChangeID(IntPtr obj, ref Guid id); [LibraryImport("FlaxEngine", EntryPoint = "FlaxEngine.Object::Internal_GetUnmanagedInterface", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.StringMarshaller))] internal static partial IntPtr Internal_GetUnmanagedInterface(IntPtr obj, [MarshalUsing(typeof(SystemTypeMarshaller))] Type type); #endregion } }