using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
namespace Phantom.XRMOD.UnityFusion.Editor
{
///
/// Contains information about a single custom editor targeting a particular class.
///
/// Mirrors the internal UnityEditor.CustomEditorAttributes.MonoEditorType type.
///
///
public readonly struct CustomEditorInfo
{
internal readonly static Type monoEditorTypeType;
internal static readonly FieldInfo inspectorTypeField;
internal static readonly FieldInfo supportedRenderPipelineTypesField;
internal static readonly FieldInfo editorForChildClassesField;
internal static readonly FieldInfo isFallbackField;
internal readonly Type inspectorType;
internal readonly Type[] supportedRenderPipelineTypes;
internal readonly bool editorForChildClasses;
internal readonly bool isFallback;
///
/// Contains information about a single custom editor targeting a particular class.
///
/// Mirrors the internal UnityEditor.CustomEditorAttributes.MonoEditorType type.
///
///
static CustomEditorInfo()
{
monoEditorTypeType = GetInternalEditorType("UnityEditor.CustomEditorAttributes").GetNestedType("MonoEditorType", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
inspectorTypeField = monoEditorTypeType.GetField("inspectorType");
supportedRenderPipelineTypesField = monoEditorTypeType.GetField("supportedRenderPipelineTypes");
editorForChildClassesField = monoEditorTypeType.GetField("editorForChildClasses");
isFallbackField = monoEditorTypeType.GetField("isFallback");
#if DEV_MODE
Debug.Assert(inspectorTypeField != null, nameof(inspectorTypeField));
Debug.Assert(supportedRenderPipelineTypesField != null, nameof(supportedRenderPipelineTypesField));
Debug.Assert(editorForChildClassesField != null, nameof(editorForChildClassesField));
Debug.Assert(isFallbackField != null, nameof(isFallbackField));
#endif
}
public CustomEditorInfo(Type inspectorType, bool editorForChildClasses = false, bool isFallback = false)
{
this.inspectorType = inspectorType;
supportedRenderPipelineTypes = Type.EmptyTypes;
this.editorForChildClasses = editorForChildClasses;
this.isFallback = isFallback;
#if DEV_MODE
Debug.Assert(typeof(Editor).IsAssignableFrom(inspectorType), inspectorType.Name);
#endif
}
public CustomEditorInfo(Type inspectorType, Type[] supportedRenderPipelineTypes, bool editorForChildClasses, bool isFallback)
{
this.inspectorType = inspectorType;
this.supportedRenderPipelineTypes = supportedRenderPipelineTypes;
this.editorForChildClasses = editorForChildClasses;
this.isFallback = isFallback;
#if DEV_MODE
Debug.Assert(typeof(Editor).IsAssignableFrom(inspectorType), inspectorType.Name);
#endif
}
public CustomEditorInfo(object obj)
{
inspectorType = inspectorTypeField.GetValue(obj) as Type;
supportedRenderPipelineTypes = (Type[])supportedRenderPipelineTypesField.GetValue(obj) ?? Type.EmptyTypes;
editorForChildClasses = (bool)editorForChildClassesField.GetValue(obj);
isFallback = (bool)isFallbackField.GetValue(obj);
#if DEV_MODE
//Debug.Assert(typeof(Object).IsAssignableFrom(inspectedType), inspectedType.Name); // Fails for some classes when Odin Inspector is installed
//Debug.Assert(!typeof(Editor).IsAssignableFrom(inspectedType), inspectedType.Name); // Fails for internal AssetStoreAssetInspector
Debug.Assert(typeof(Editor).IsAssignableFrom(inspectorType), inspectorType.Name);
#endif
}
public static CustomEditorInfo[] Create(IList internalList) // List
{
int count = internalList.Count;
var result = new CustomEditorInfo[count];
for(int i = 0; i < count; i++)
{
result[i] = new CustomEditorInfo(internalList[i]);
}
return result;
}
public static Type ExtractInspectorType(object internalMonoEditorType) => inspectorTypeField.GetValue(internalMonoEditorType) as Type;
public object ToInternalType()
{
object instance;
try
{
instance = Activator.CreateInstance(monoEditorTypeType);
}
#if DEV_MODE
catch(Exception e)
{
Debug.LogError(e);
#else
catch
{
#endif
instance = FormatterServices.GetUninitializedObject(monoEditorTypeType);
}
inspectorTypeField.SetValue(instance, inspectorType);
supportedRenderPipelineTypesField.SetValue(instance, supportedRenderPipelineTypes);
editorForChildClassesField.SetValue(instance, editorForChildClasses);
isFallbackField.SetValue(instance, isFallback);
return instance;
}
public IList ToInternalTypeList()
{
var listType = typeof(List<>).MakeGenericType(monoEditorTypeType);
var list = Activator.CreateInstance(listType) as IList;
list.Add(ToInternalType());
return list;
}
private static Type GetInternalEditorType(string fullTypeName)
{
#if DEV_MODE
Debug.Assert(fullTypeName.IndexOf(".") != -1, fullTypeName);
#endif
var type = typeof(UnityEditor.Editor).Assembly.GetType(fullTypeName);
#if DEV_MODE
Debug.Assert(type != null, $"Type {fullTypeName} was not found in assembly {typeof(Editor).Assembly.GetName().Name}.");
#endif
return type;
}
}
}