// Copyright (c) Wojciech Figat. All rights reserved. using System; #if FLAX_EDITOR using System.Globalization; using System.ComponentModel; #endif namespace FlaxEngine { /// /// The scripting object reference with interface. /// /// The type of the scripting interface. #if FLAX_EDITOR [CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.ScriptingObjectInterfaceReferenceEditor))] [TypeConverter(typeof(TypeConverters.ScriptingObjectInterfaceReferenceConverter))] #endif public struct ScriptingObjectInterfaceReference : IComparable, IComparable> where T : class { private Object _object; /// /// Gets or sets the referenced object that implements the interface. /// public Object Object { get => _object; set => _object = value != null && value is T ? value : null; } /// /// Gets or sets the referenced object that implements the interface. /// [NoSerialize] public T Interface { get => _object as T; set { var obj = value as Object; if (value == null || obj != null) _object = obj; else throw new InvalidCastException($"Cannot use object of type {value.GetType().FullName} for ScriptingObjectInterfaceReference<{typeof(T).FullName}>. It needs to inherit from {typeof(Object).FullName}."); } } /// /// Initializes a new instance of the structure. /// /// The object to link. public ScriptingObjectInterfaceReference(Object obj) { Object = obj; } /// /// Initializes a new instance of the structure. /// /// The interface object to link. public ScriptingObjectInterfaceReference(T interfaceObj) { Interface = interfaceObj; } /// /// Implicit cast operator to typed interface. /// /// Reference /// Interface public static explicit operator T(ScriptingObjectInterfaceReference value) { return value._object as T; } /// /// Implicit cast operator from object to reference. /// /// The object to link. /// Reference public static explicit operator ScriptingObjectInterfaceReference(T obj) { return new ScriptingObjectInterfaceReference(obj); } /// /// Implicit cast operator to object. /// /// Reference /// Object public static implicit operator Object(ScriptingObjectInterfaceReference value) { return value._object; } /// /// Implicit cast operator from object to reference. /// /// Object /// Reference public static implicit operator ScriptingObjectInterfaceReference(Object obj) { return new ScriptingObjectInterfaceReference(obj); } /// public override string ToString() { return _object?.ToString() ?? ""; } /// public override int GetHashCode() { return Object.GetUnmanagedPtr(_object).GetHashCode(); } /// public int CompareTo(object obj) { if (obj is ScriptingObjectInterfaceReference other) return CompareTo(other); return 0; } /// public int CompareTo(ScriptingObjectInterfaceReference other) { return Object.GetUnmanagedPtr(_object).CompareTo(Object.GetUnmanagedPtr(other._object)); } } } #if FLAX_EDITOR namespace FlaxEngine.TypeConverters { internal class ScriptingObjectInterfaceReferenceConverter : TypeConverter { /// public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { if (sourceType == typeof(string)) return true; return base.CanConvertFrom(context, sourceType); } /// public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { if (destinationType == typeof(string)) return false; return base.CanConvertTo(context, destinationType); } /// public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value is string str && context is DummyTypeDescriptorContext internalContext) { var type = internalContext.CurrentType; Json.JsonSerializer.ParseID(str, out var id); var obj = Object.Find(ref id, type.GetGenericArguments()[0]); var objectField = type.GetField("_object", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); value = Activator.CreateInstance(type); objectField.SetValue(value, obj); return value; } return base.ConvertFrom(context, culture, value); } /// public override unsafe object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == typeof(string)) { var objectField = value.GetType().GetField("_object", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); var obj = objectField.GetValue(value) as Object; if (obj == null) return string.Empty; var id = obj.ID; return Json.JsonSerializer.GetStringID(&id); } return base.ConvertTo(context, culture, value, destinationType); } } } #endif