0.2.0: Moved into inspector drawer from module.toolbox to module.inspector
This commit is contained in:
parent
5671c2c754
commit
ffec2abdf4
227 changed files with 5306 additions and 29 deletions
233
Editor/Utilities/EditorMethodUtility.cs
Normal file
233
Editor/Utilities/EditorMethodUtility.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Module.Inspector.Editor.Utilities
|
||||
{
|
||||
internal static class EditorMethodUtility
|
||||
{
|
||||
private static Dictionary<Type, ResultPrimary[]> CACHED_TYPE_TO_PRIMARIES;
|
||||
private static Dictionary<MethodInfo, 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(AbstractMethodDrawer);
|
||||
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 ResultPrimary[] QueryPrimary(Object target)
|
||||
{
|
||||
InitializeCache();
|
||||
|
||||
if (CACHED_TYPE_TO_PRIMARIES == null)
|
||||
CACHED_TYPE_TO_PRIMARIES = new Dictionary<Type, ResultPrimary[]>();
|
||||
|
||||
Type type = target.GetType();
|
||||
|
||||
if (CACHED_TYPE_TO_PRIMARIES.TryGetValue(type, out ResultPrimary[] primaries))
|
||||
return primaries;
|
||||
|
||||
primaries = InternalFetchPrimary(type);
|
||||
CACHED_TYPE_TO_PRIMARIES.Add(type, primaries);
|
||||
return primaries;
|
||||
}
|
||||
|
||||
public static Result Query(MethodInfo methodInfo)
|
||||
{
|
||||
InitializeCache();
|
||||
|
||||
if (CACHED_RESULTS == null)
|
||||
CACHED_RESULTS = new Dictionary<MethodInfo, Result>();
|
||||
|
||||
if (CACHED_RESULTS.TryGetValue(methodInfo, out Result result))
|
||||
return result;
|
||||
|
||||
result = InternalFetchProperties(methodInfo);
|
||||
|
||||
if (result != null)
|
||||
CACHED_RESULTS.Add(methodInfo, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ResultPrimary[] InternalFetchPrimary(Type type)
|
||||
{
|
||||
const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
MethodInfo[] methods = type.GetMethods(FLAGS)
|
||||
.Where(m => m.GetParameters().Length == 0)
|
||||
.ToArray();
|
||||
|
||||
var list = new List<ResultPrimary>(methods.Length);
|
||||
|
||||
for (var i = 0; i < methods.Length; i++)
|
||||
{
|
||||
Result result = Query(methods[i]);
|
||||
|
||||
if (result != null)
|
||||
list.Add(new ResultPrimary(methods[i], result));
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
private static Result InternalFetchProperties(MethodInfo methodInfo)
|
||||
{
|
||||
ResultValue<DrawerMethodAttribute, DrawerMethodDrawer> drawer = null;
|
||||
ResultValue<DecoratorMethodAttribute, DecoratorMethodDrawer> decorator = null;
|
||||
var accessModifiers = new List<ResultValue<AccessModifierMethodAttribute, AccessModifierMethodDrawer>>(2);
|
||||
object[] attributes = methodInfo.GetCustomAttributes(false);
|
||||
|
||||
for (var i = 0; i < attributes.Length; i++)
|
||||
{
|
||||
object att = attributes[i];
|
||||
|
||||
if (att is DrawerMethodAttribute attDrawer)
|
||||
{
|
||||
if (drawer != null)
|
||||
continue;
|
||||
|
||||
var prop = InternalCreateInstanceOf<DrawerMethodDrawer>(attDrawer);
|
||||
|
||||
if (prop != null)
|
||||
drawer = new ResultValue<DrawerMethodAttribute, DrawerMethodDrawer>(attDrawer, prop);
|
||||
}
|
||||
else if (att is AccessModifierMethodAttribute accessModifier)
|
||||
{
|
||||
var prop = InternalCreateInstanceOf<AccessModifierMethodDrawer>(accessModifier);
|
||||
|
||||
if (prop != null)
|
||||
accessModifiers.Add(new ResultValue<AccessModifierMethodAttribute, AccessModifierMethodDrawer>(accessModifier, prop));
|
||||
}
|
||||
else if (att is DecoratorMethodAttribute attDecorator)
|
||||
{
|
||||
if (decorator != null)
|
||||
continue;
|
||||
|
||||
var prop = InternalCreateInstanceOf<DecoratorMethodDrawer>(attDecorator);
|
||||
|
||||
if (prop != null)
|
||||
decorator = new ResultValue<DecoratorMethodAttribute, DecoratorMethodDrawer>(attDecorator, prop);
|
||||
}
|
||||
}
|
||||
|
||||
if (drawer == null && decorator == null && accessModifiers.Count == 0)
|
||||
return null;
|
||||
|
||||
return new Result(drawer, decorator, accessModifiers);
|
||||
}
|
||||
|
||||
private static T InternalCreateInstanceOf<T>(AbstractMethodAttribute att) where T : AbstractMethodDrawer
|
||||
{
|
||||
if (CACHED_ATT_TO_DRAWER.TryGetValue(att.GetType(), out Type drawerType))
|
||||
return Activator.CreateInstance(drawerType) as T;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class: Result from method query
|
||||
/// </summary>
|
||||
public sealed class Result
|
||||
{
|
||||
public readonly ResultValue<DrawerMethodAttribute, DrawerMethodDrawer> draw;
|
||||
public readonly ResultValue<DecoratorMethodAttribute, DecoratorMethodDrawer> decorator;
|
||||
public readonly List<ResultValue<AccessModifierMethodAttribute, AccessModifierMethodDrawer>> accessModifiers;
|
||||
|
||||
public Result(ResultValue<DrawerMethodAttribute, DrawerMethodDrawer> draw,
|
||||
ResultValue<DecoratorMethodAttribute, DecoratorMethodDrawer> decorator,
|
||||
List<ResultValue<AccessModifierMethodAttribute, AccessModifierMethodDrawer>> accessModifiers)
|
||||
{
|
||||
this.draw = draw;
|
||||
this.decorator = decorator;
|
||||
this.accessModifiers = accessModifiers;
|
||||
}
|
||||
|
||||
public T GetAccessModifier<T>() where T : AccessModifierMethodAttribute
|
||||
{
|
||||
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 : AbstractMethodAttribute
|
||||
where T1 : AbstractMethodDrawer
|
||||
{
|
||||
public readonly T0 attribute;
|
||||
public readonly T1 drawer;
|
||||
|
||||
public ResultValue(T0 attribute, T1 drawer)
|
||||
{
|
||||
this.attribute = attribute;
|
||||
this.drawer = drawer;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Class: Contains primary method info and drawer for a specific method
|
||||
/// </summary>
|
||||
public sealed class ResultPrimary
|
||||
{
|
||||
public readonly MethodInfo methodInfo;
|
||||
public readonly AbstractMethodDrawer drawer;
|
||||
|
||||
public ResultPrimary(MethodInfo methodInfo, AbstractMethodDrawer drawer)
|
||||
{
|
||||
this.methodInfo = methodInfo;
|
||||
this.drawer = drawer;
|
||||
}
|
||||
|
||||
public ResultPrimary(MethodInfo methodInfo, Result result)
|
||||
{
|
||||
this.methodInfo = methodInfo;
|
||||
|
||||
if (result.draw != null)
|
||||
drawer = result.draw.drawer;
|
||||
else if (result.decorator != null)
|
||||
drawer = result.decorator.drawer;
|
||||
else if (result.accessModifiers != null && result.accessModifiers.Count > 0)
|
||||
drawer = result.accessModifiers[0].drawer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Editor/Utilities/EditorMethodUtility.cs.meta
Normal file
11
Editor/Utilities/EditorMethodUtility.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8084cb44127a2464ab72b4d104b7b622
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Editor/Utilities/EditorNamingUtility.cs
Normal file
76
Editor/Utilities/EditorNamingUtility.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Module.Inspector.Editor.Utilities
|
||||
{
|
||||
public static class EditorNamingUtility
|
||||
{
|
||||
public static string ConvertTo(Naming.EPatternType type, string str)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Naming.EPatternType.CamelCasing:
|
||||
return ToCamel(str);
|
||||
case Naming.EPatternType.PascalCasing:
|
||||
return ToPascal(str);
|
||||
case Naming.EPatternType.SnakeCasing:
|
||||
return ToSnake(str);
|
||||
case Naming.EPatternType.SnakeCasingAllCaps:
|
||||
return ToSnake(str).ToUpper();
|
||||
case Naming.EPatternType.KebabCasing:
|
||||
return ToKebab(str);
|
||||
case Naming.EPatternType.KebabCasingAllCaps:
|
||||
return ToKebab(str).ToUpper();
|
||||
default:
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToPascal(string str)
|
||||
{
|
||||
var pattern = new Regex(@"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+");
|
||||
MatchCollection matches = pattern.Matches(str);
|
||||
|
||||
if (matches.Count != 0)
|
||||
str = matches.Cast<Match>().Select(c => c.Value).Aggregate(( a, b ) => a + " " + b);
|
||||
|
||||
var culture = new CultureInfo("en-US", false);
|
||||
str = culture.TextInfo.ToTitleCase(str);
|
||||
str = str.Replace(@" ", "");
|
||||
return str;
|
||||
}
|
||||
|
||||
public static string ToCamel(string str)
|
||||
{
|
||||
str = ToPascal(str);
|
||||
|
||||
if (str.Length > 0)
|
||||
str = char.ToLower(str[0]) + str.Substring(1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static string ToSnake(string str)
|
||||
{
|
||||
var pattern = new Regex(@"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+");
|
||||
MatchCollection matches = pattern.Matches(str);
|
||||
|
||||
if (matches.Count != 0)
|
||||
str = matches.Cast<Match>().Select(c => c.Value).Aggregate(( a, b ) => a + "_" + b);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public static string ToKebab(string str)
|
||||
{
|
||||
var pattern = new Regex(@"[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+");
|
||||
MatchCollection matches = pattern.Matches(str);
|
||||
|
||||
if (matches.Count != 0)
|
||||
str = matches.Cast<Match>().Select(c => c.Value).Aggregate(( a, b ) => a + "-" + b);
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Editor/Utilities/EditorNamingUtility.cs.meta
Normal file
3
Editor/Utilities/EditorNamingUtility.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cbf1a9393f7c4425b846686ccc5445e0
|
||||
timeCreated: 1625650972
|
||||
208
Editor/Utilities/EditorPropertyUtility.cs
Normal file
208
Editor/Utilities/EditorPropertyUtility.cs
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Editor/Utilities/EditorPropertyUtility.cs.meta
Normal file
11
Editor/Utilities/EditorPropertyUtility.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dd20b0ba8f5857e4d89bd475e38b7c13
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
56
Editor/Utilities/EditorSerializedPropertyUtility.cs
Normal file
56
Editor/Utilities/EditorSerializedPropertyUtility.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Module.Inspector.Editor.Utilities
|
||||
{
|
||||
internal static class EditorSerializedPropertyUtility
|
||||
{
|
||||
public static bool IsValue(Object obj, string fieldName, object value, bool useFieldValue)
|
||||
{
|
||||
if (obj == null || string.IsNullOrEmpty(fieldName))
|
||||
return false;
|
||||
|
||||
var so = new SerializedObject(obj);
|
||||
SerializedProperty sp = so.FindProperty(fieldName);
|
||||
return IsValue(sp, value, useFieldValue);
|
||||
}
|
||||
|
||||
public static bool IsValue(SerializedProperty sp, object value, bool useFieldValue)
|
||||
{
|
||||
if (sp == null)
|
||||
return false;
|
||||
|
||||
if (useFieldValue)
|
||||
{
|
||||
switch (sp.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.Generic:
|
||||
return value == (object)sp.objectReferenceValue;
|
||||
case SerializedPropertyType.Integer:
|
||||
return value is int i && sp.intValue == i;
|
||||
case SerializedPropertyType.Boolean:
|
||||
return value is bool b && sp.boolValue == b;
|
||||
case SerializedPropertyType.Float:
|
||||
return value is float f && Mathf.Approximately(sp.floatValue, f);
|
||||
case SerializedPropertyType.String:
|
||||
return value is string s && sp.stringValue == s;
|
||||
case SerializedPropertyType.LayerMask:
|
||||
return value is LayerMask l && sp.intValue == l;
|
||||
case SerializedPropertyType.Enum:
|
||||
return value is Enum && sp.intValue == Convert.ToInt32(value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sp.propertyType == SerializedPropertyType.Boolean)
|
||||
return sp.boolValue;
|
||||
if (sp.propertyType == SerializedPropertyType.ObjectReference)
|
||||
return sp.objectReferenceValue != null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Editor/Utilities/EditorSerializedPropertyUtility.cs.meta
Normal file
3
Editor/Utilities/EditorSerializedPropertyUtility.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9c65105e5014222be899656c09dceef
|
||||
timeCreated: 1610022228
|
||||
198
Editor/Utilities/EditorTypeUtility.cs
Normal file
198
Editor/Utilities/EditorTypeUtility.cs
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Module.Inspector.Editor
|
||||
{
|
||||
internal static class EditorTypeUtility
|
||||
{
|
||||
private const BindingFlags FIELD_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
private static readonly Dictionary<Type, Type[]> DICT_AS_TYPES = new Dictionary<Type, Type[]>();
|
||||
private static readonly Dictionary<Type, string[]> DICT_AS_STRS = new Dictionary<Type, string[]>();
|
||||
private static readonly Dictionary<Type, string[]> DICT_AS_DESCS = new Dictionary<Type, string[]>();
|
||||
|
||||
private static readonly Dictionary<Type, FieldInfo[]> DICT_AS_FIELDS = new Dictionary<Type, FieldInfo[]>();
|
||||
private static readonly Dictionary<Type, string[]> DICT_FIELDS_AS_STRS = new Dictionary<Type, string[]>();
|
||||
private static readonly Dictionary<Type, string[]> DICT_FIELDS_AS_DESCS = new Dictionary<Type, string[]>();
|
||||
|
||||
public static Type GetType(string fullname)
|
||||
{
|
||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
for (var i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
Assembly assembly = assemblies[i];
|
||||
Type type = assembly.GetType(fullname);
|
||||
|
||||
if (type != null)
|
||||
return type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FieldInfo GetField(object target, string fieldName)
|
||||
{
|
||||
return GetFieldByName(target.GetType(), fieldName);
|
||||
}
|
||||
|
||||
public static bool SetFieldValue(object target, string fieldName, object value, bool allowDuplicate)
|
||||
{
|
||||
if (InternalTrySetUnityObject(target, fieldName, value, allowDuplicate))
|
||||
return true;
|
||||
|
||||
FieldInfo field = GetField(target, fieldName);
|
||||
|
||||
if (field == null)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
field.SetValue(target, value);
|
||||
|
||||
if (target is Object o)
|
||||
EditorUtility.SetDirty(o);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool InternalTrySetUnityObject(object target, string fieldName, object value, bool allowDuplicate)
|
||||
{
|
||||
if (!(target is Object o))
|
||||
return false;
|
||||
|
||||
var so = new SerializedObject(o);
|
||||
SerializedProperty sp = so.FindProperty(fieldName);
|
||||
bool success = sp?.TrySetValueTo(value, allowDuplicate) ?? false;
|
||||
|
||||
if (success)
|
||||
so.ApplyModifiedProperties();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
internal static Type[] GetAssignableFrom(Type type)
|
||||
{
|
||||
if (!DICT_AS_TYPES.ContainsKey(type))
|
||||
InternalFetch(type);
|
||||
|
||||
return DICT_AS_TYPES[type];
|
||||
}
|
||||
|
||||
internal static string[] GetAssignableFromAsStrings(Type type)
|
||||
{
|
||||
if (!DICT_AS_STRS.ContainsKey(type))
|
||||
InternalFetch(type);
|
||||
|
||||
return DICT_AS_STRS[type];
|
||||
}
|
||||
|
||||
internal static string[] GetAssignableFromAsDescriptions(Type type)
|
||||
{
|
||||
if (!DICT_AS_DESCS.ContainsKey(type))
|
||||
InternalFetch(type);
|
||||
|
||||
return DICT_AS_DESCS[type];
|
||||
}
|
||||
|
||||
internal static FieldInfo[] GetFields(Type type)
|
||||
{
|
||||
if (!DICT_AS_FIELDS.ContainsKey(type))
|
||||
InternalFetchFields(type);
|
||||
|
||||
return DICT_AS_FIELDS[type];
|
||||
}
|
||||
|
||||
internal static FieldInfo GetFieldByName(Type type, string fieldName)
|
||||
{
|
||||
FieldInfo[] fields = GetFields(type);
|
||||
|
||||
for (var i = 0; i < fields.Length; i++)
|
||||
{
|
||||
if (fields[i].Name.Equals(fieldName))
|
||||
return fields[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static string[] GetFieldsAsStrings(Type type)
|
||||
{
|
||||
if (!DICT_FIELDS_AS_STRS.ContainsKey(type))
|
||||
InternalFetchFields(type);
|
||||
|
||||
return DICT_FIELDS_AS_STRS[type];
|
||||
}
|
||||
|
||||
internal static string[] GetFieldsAsDescriptions(Type type)
|
||||
{
|
||||
if (!DICT_FIELDS_AS_DESCS.ContainsKey(type))
|
||||
InternalFetchFields(type);
|
||||
|
||||
return DICT_FIELDS_AS_DESCS[type];
|
||||
}
|
||||
|
||||
private static void InternalFetch(Type assignableFrom)
|
||||
{
|
||||
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
var listTypes = new List<Type>(32);
|
||||
|
||||
for (var i = 0; i < assemblies.Length; i++)
|
||||
{
|
||||
Assembly assembly = assemblies[i];
|
||||
Type[] types = assembly.GetTypes();
|
||||
|
||||
for (var j = 0; j < types.Length; j++)
|
||||
{
|
||||
Type type = types[j];
|
||||
|
||||
if (!type.IsAbstract && assignableFrom.IsAssignableFrom(type))
|
||||
listTypes.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
listTypes.Sort((t0, t1) => string.Compare(t0.Name, t1.Name, StringComparison.Ordinal));
|
||||
var fullnames = new string[listTypes.Count];
|
||||
var descs = new string[listTypes.Count];
|
||||
|
||||
for (var i = 0; i < fullnames.Length; i++)
|
||||
{
|
||||
fullnames[i] = listTypes[i].FullName;
|
||||
descs[i] = $"{listTypes[i].Name} (<i>{fullnames[i]}</i>)";
|
||||
}
|
||||
|
||||
DICT_AS_TYPES.Add(assignableFrom, listTypes.ToArray());
|
||||
DICT_AS_STRS.Add(assignableFrom, fullnames);
|
||||
DICT_AS_DESCS.Add(assignableFrom, descs);
|
||||
}
|
||||
|
||||
private static void InternalFetchFields(Type type)
|
||||
{
|
||||
FieldInfo[] fields = type.GetFields(FIELD_FLAGS);
|
||||
Array.Sort(fields, (f0, f1) => string.Compare(f0.Name, f1.Name, StringComparison.Ordinal));
|
||||
|
||||
var names = new string[fields.Length];
|
||||
var descs = new string[fields.Length];
|
||||
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
names[i] = fields[i].Name;
|
||||
descs[i] = $"{fields[i].Name} (<i>{fields[i].FieldType.Name}</i>)";
|
||||
}
|
||||
|
||||
DICT_AS_FIELDS.Add(type, fields);
|
||||
DICT_FIELDS_AS_STRS.Add(type, names);
|
||||
DICT_FIELDS_AS_DESCS.Add(type, descs);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Editor/Utilities/EditorTypeUtility.cs.meta
Normal file
3
Editor/Utilities/EditorTypeUtility.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 762ec4eaaaf08a745929731d2379bed8
|
||||
timeCreated: 1590404966
|
||||
Loading…
Add table
Add a link
Reference in a new issue