using System; using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; namespace Module.Inspector.Editor.Utilities { internal static class EditorHiddenFieldUtility { private static Dictionary CACHED_TYPE_TO_PRIMARIES; public static EditableFieldInfo[] Query(Object target) { Type type = target.GetType(); var att = type.GetCustomAttribute(); if (att == null) return new EditableFieldInfo[0]; if (CACHED_TYPE_TO_PRIMARIES == null) CACHED_TYPE_TO_PRIMARIES = new Dictionary(); if (CACHED_TYPE_TO_PRIMARIES.TryGetValue(type, out EditableFieldInfo[] fields)) return fields; fields = InternalFetch(type, att.UseFieldProperty); CACHED_TYPE_TO_PRIMARIES.Add(type, fields); return fields; } public static float CalculateHeight(EditableFieldInfo[] fields) { return EditorGUIUtility.singleLineHeight * fields.Length; } public static void Draw(Rect rect, EditableFieldInfo field, Object target) { bool prevEnabled = GUI.enabled; GUI.enabled = field.editable; string nicifiedName = ObjectNames.NicifyVariableName(field.Name); if (field.IsType()) { float temp = EditorGUI.FloatField(rect, nicifiedName, field.GetValue(target)); if (field.editable) field.SetValue(target, temp); } else if (field.IsType()) { int temp = EditorGUI.IntField(rect, nicifiedName, field.GetValue(target)); if (field.editable) field.SetValue(target, temp); } else if (field.IsType()) { double temp = EditorGUI.DoubleField(rect, nicifiedName, field.GetValue(target)); if (field.editable) field.SetValue(target, temp); } else if (field.IsType()) { string temp = EditorGUI.TextField(rect, nicifiedName, field.GetValue(target)); if (field.editable) field.SetValue(target, temp); } else if (field.IsAssignableFrom()) { Object temp = EditorGUI.ObjectField(rect, nicifiedName, field.GetValue(target), typeof(Object), true); if (field.editable) field.SetValue(target, temp); } else { EditorGUI.LabelField(rect, ObjectNames.NicifyVariableName(field.Name), "Unsupported type"); } GUI.enabled = prevEnabled; } private static EditableFieldInfo[] InternalFetch(Type type, bool useFieldProperty) { const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo[] fields = type.GetFields(FLAGS); var list = new List(fields.Length); for (var i = 0; i < fields.Length; i++) { FieldInfo fi = fields[i]; if (fi.GetCustomAttribute() == null && fi.GetCustomAttribute() == null) continue; var att = fi.GetCustomAttribute(); if (!useFieldProperty || att != null) list.Add(new EditableFieldInfo(fi, att != null && att.editable)); } return list.ToArray(); } public sealed class EditableFieldInfo { public readonly FieldInfo fieldInfo; public readonly bool editable; public string Name => fieldInfo.Name; public EditableFieldInfo(FieldInfo fieldInfo, bool editable) { this.fieldInfo = fieldInfo; this.editable = editable; } public T GetValue(object target) { return (T)fieldInfo.GetValue(target); } public void SetValue(object target, T value) { fieldInfo.SetValue(target, value); } public bool IsType() { return fieldInfo.FieldType == typeof(T); } public bool IsAssignableFrom() { return typeof(T).IsAssignableFrom(fieldInfo.FieldType); } } } }