208 lines
8.1 KiB
C#
208 lines
8.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Reflection;
|
|
using UnityEngine;
|
|
|
|
namespace Module.Inspector.Editor.Utilities
|
|
{
|
|
public static class EditorPropertyUtility
|
|
{
|
|
private static Dictionary<FieldInfo, Result> CACHED_RESULTS;
|
|
private static Dictionary<Type, Type> CACHED_ATT_TO_DRAWER;
|
|
|
|
private static void InitializeCache()
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER != null)
|
|
return;
|
|
|
|
CACHED_ATT_TO_DRAWER = new Dictionary<Type, Type>();
|
|
|
|
Type baseDrawerType = typeof(AbstractPropertyDrawer);
|
|
var assembly = Assembly.GetAssembly(baseDrawerType);
|
|
Type[] types = assembly.GetTypes();
|
|
|
|
for (var i = 0; i < types.Length; i++)
|
|
{
|
|
Type type = types[i];
|
|
|
|
if (type.IsAbstract || !baseDrawerType.IsAssignableFrom(type))
|
|
continue;
|
|
|
|
IList<CustomAttributeData> attributes = type.GetCustomAttributesData();
|
|
|
|
for (var j = 0; j < attributes.Count; j++)
|
|
{
|
|
CustomAttributeData attData = attributes[j];
|
|
IList<CustomAttributeTypedArgument> arguments = attData.ConstructorArguments;
|
|
|
|
for (var k = 0; k < arguments.Count; k++)
|
|
{
|
|
if (arguments[k].Value is Type argType)
|
|
CACHED_ATT_TO_DRAWER.Add(argType, type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Result Query(FieldInfo fieldInfo)
|
|
{
|
|
InitializeCache();
|
|
|
|
if (CACHED_RESULTS == null)
|
|
CACHED_RESULTS = new Dictionary<FieldInfo, Result>();
|
|
|
|
if (CACHED_RESULTS.TryGetValue(fieldInfo, out Result result))
|
|
return result;
|
|
|
|
result = InternalFetchProperties(fieldInfo);
|
|
CACHED_RESULTS.Add(fieldInfo, result);
|
|
return result;
|
|
}
|
|
|
|
private static Result InternalFetchProperties(FieldInfo fieldInfo)
|
|
{
|
|
ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> drawer = null;
|
|
var typeDrawer = InternalCreateInstanceOf<DrawerPropertyDrawer>(fieldInfo);
|
|
|
|
if (typeDrawer != null)
|
|
drawer = new ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer>(null, typeDrawer);
|
|
|
|
var valueModifiers = new List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>>(2);
|
|
var accessModifiers = new List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>>(2);
|
|
object[] attributes = fieldInfo.GetCustomAttributes(false);
|
|
string tooltip = null;
|
|
var isObsolete = false;
|
|
string obsoleteText = null;
|
|
|
|
for (var i = 0; i < attributes.Length; i++)
|
|
{
|
|
object att = attributes[i];
|
|
|
|
if (att is DrawerPropertyAttribute attDrawer)
|
|
{
|
|
if (drawer != null)
|
|
continue;
|
|
|
|
var prop = InternalCreateInstanceOf<DrawerPropertyDrawer>(attDrawer);
|
|
|
|
if (prop != null)
|
|
drawer = new ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer>(attDrawer, prop);
|
|
}
|
|
else if (att is ValueModifierPropertyAttribute valueModifier)
|
|
{
|
|
var prop = InternalCreateInstanceOf<ValueModifierPropertyDrawer>(valueModifier);
|
|
|
|
if (prop != null)
|
|
valueModifiers.Add(new ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>(valueModifier, prop));
|
|
}
|
|
else if (att is AccessModifierPropertyAttribute accessModifier)
|
|
{
|
|
var prop = InternalCreateInstanceOf<AccessModifierPropertyDrawer>(accessModifier);
|
|
|
|
if (prop != null)
|
|
accessModifiers.Add(new ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>(accessModifier, prop));
|
|
}
|
|
else if (att is TooltipAttribute attTooltip)
|
|
{
|
|
tooltip = attTooltip.tooltip;
|
|
}
|
|
else if (att is ObsoleteAttribute attObsolete)
|
|
{
|
|
isObsolete = true;
|
|
obsoleteText = attObsolete.Message;
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(obsoleteText))
|
|
{
|
|
if (tooltip != null)
|
|
tooltip += $"\n[Obsolete: {obsoleteText}";
|
|
else
|
|
tooltip = $"Obsolete: {obsoleteText}";
|
|
}
|
|
|
|
return new Result(drawer, valueModifiers, accessModifiers, tooltip, isObsolete);
|
|
}
|
|
|
|
private static T InternalCreateInstanceOf<T>(AbstractPropertyAttribute att) where T : AbstractPropertyDrawer
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER.TryGetValue(att.GetType(), out Type drawerType))
|
|
return Activator.CreateInstance(drawerType) as T;
|
|
|
|
return null;
|
|
}
|
|
|
|
private static T InternalCreateInstanceOf<T>(FieldInfo fieldInfo) where T : AbstractPropertyDrawer
|
|
{
|
|
if (CACHED_ATT_TO_DRAWER.TryGetValue(fieldInfo.FieldType, out Type drawerType))
|
|
return Activator.CreateInstance(drawerType) as T;
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class: Result from property query
|
|
/// </summary>
|
|
public sealed class Result
|
|
{
|
|
public readonly ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> draw;
|
|
public readonly List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>> valueModifiers;
|
|
public readonly List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>> accessModifiers;
|
|
public readonly string tooltip;
|
|
public readonly bool isObsolete;
|
|
|
|
public Result(ResultValue<DrawerPropertyAttribute, DrawerPropertyDrawer> draw,
|
|
List<ResultValue<ValueModifierPropertyAttribute, ValueModifierPropertyDrawer>> valueModifiers,
|
|
List<ResultValue<AccessModifierPropertyAttribute, AccessModifierPropertyDrawer>> accessModifiers,
|
|
string tooltip,
|
|
bool isObsolete)
|
|
{
|
|
this.draw = draw;
|
|
this.valueModifiers = valueModifiers;
|
|
this.accessModifiers = accessModifiers;
|
|
this.tooltip = tooltip;
|
|
this.isObsolete = isObsolete;
|
|
}
|
|
|
|
public T GetValueModifier<T>() where T : ValueModifierPropertyAttribute
|
|
{
|
|
for (var i = 0; i < valueModifiers.Count; i++)
|
|
{
|
|
if (valueModifiers[i].attribute is T att)
|
|
return att;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public T GetAccessModifier<T>() where T : AccessModifierPropertyAttribute
|
|
{
|
|
for (var i = 0; i < accessModifiers.Count; i++)
|
|
{
|
|
if (accessModifiers[i].attribute is T att)
|
|
return att;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class: Contains attribute and drawer values
|
|
/// </summary>
|
|
/// <typeparam name="T0"></typeparam>
|
|
/// <typeparam name="T1"></typeparam>
|
|
public sealed class ResultValue<T0, T1> where T0 : AbstractPropertyAttribute
|
|
where T1 : AbstractPropertyDrawer
|
|
{
|
|
public readonly T0 attribute;
|
|
public readonly T1 drawer;
|
|
|
|
public ResultValue(T0 attribute, T1 drawer)
|
|
{
|
|
this.attribute = attribute;
|
|
this.drawer = drawer;
|
|
}
|
|
}
|
|
}
|
|
} |