using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; namespace NaughtyAttributes.Editor { [CanEditMultipleObjects] [CustomEditor(typeof(UnityEngine.Object), true)] public class NaughtyInspector : UnityEditor.Editor { private List _serializedProperties = new List(); private IEnumerable _nonSerializedFields; private IEnumerable _nativeProperties; private IEnumerable _methods; private Dictionary _foldouts = new Dictionary(); protected virtual void OnEnable() { _nonSerializedFields = ReflectionUtility.GetAllFields( target, f => f.GetCustomAttributes(typeof(ShowNonSerializedFieldAttribute), true).Length > 0); _nativeProperties = ReflectionUtility.GetAllProperties( target, p => p.GetCustomAttributes(typeof(ShowNativePropertyAttribute), true).Length > 0); _methods = ReflectionUtility.GetAllMethods( target, m => m.GetCustomAttributes(typeof(ButtonAttribute), true).Length > 0); } protected virtual void OnDisable() { ReorderableListPropertyDrawer.Instance.ClearCache(); } public override void OnInspectorGUI() { GetSerializedProperties(ref _serializedProperties); bool anyNaughtyAttribute = _serializedProperties.Any(p => PropertyUtility.GetAttribute(p) != null); if (!anyNaughtyAttribute) { DrawDefaultInspector(); } else { DrawSerializedProperties(); } DrawNonSerializedFields(); DrawNativeProperties(); DrawButtons(); } protected void GetSerializedProperties(ref List outSerializedProperties) { outSerializedProperties.Clear(); using (var iterator = serializedObject.GetIterator()) { if (iterator.NextVisible(true)) { do { outSerializedProperties.Add(serializedObject.FindProperty(iterator.name)); } while (iterator.NextVisible(false)); } } } protected void DrawSerializedProperties() { serializedObject.Update(); // Draw non-grouped serialized properties foreach (var property in GetNonGroupedProperties(_serializedProperties)) { if (property.name.Equals("m_Script", System.StringComparison.Ordinal)) { using (new EditorGUI.DisabledScope(disabled: true)) { EditorGUILayout.PropertyField(property); } } else { NaughtyEditorGUI.PropertyField_Layout(property, includeChildren: true); } } // Draw grouped serialized properties foreach (var group in GetGroupedProperties(_serializedProperties)) { IEnumerable visibleProperties = group.Where(p => PropertyUtility.IsVisible(p)); if (!visibleProperties.Any()) { continue; } NaughtyEditorGUI.BeginBoxGroup_Layout(group.Key); foreach (var property in visibleProperties) { NaughtyEditorGUI.PropertyField_Layout(property, includeChildren: true); } NaughtyEditorGUI.EndBoxGroup_Layout(); } // Draw foldout serialized properties foreach (var group in GetFoldoutProperties(_serializedProperties)) { IEnumerable visibleProperties = group.Where(p => PropertyUtility.IsVisible(p)); if (!visibleProperties.Any()) { continue; } if (!_foldouts.ContainsKey(group.Key)) { _foldouts[group.Key] = new SavedBool($"{target.GetInstanceID()}.{group.Key}", false); } _foldouts[group.Key].Value = EditorGUILayout.Foldout(_foldouts[group.Key].Value, group.Key, true); if (_foldouts[group.Key].Value) { foreach (var property in visibleProperties) { NaughtyEditorGUI.PropertyField_Layout(property, true); } } } serializedObject.ApplyModifiedProperties(); } protected void DrawNonSerializedFields(bool drawHeader = false) { if (_nonSerializedFields.Any()) { if (drawHeader) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Non-Serialized Fields", GetHeaderGUIStyle()); NaughtyEditorGUI.HorizontalLine( EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor()); } foreach (var field in _nonSerializedFields) { NaughtyEditorGUI.NonSerializedField_Layout(serializedObject.targetObject, field); } } } protected void DrawNativeProperties(bool drawHeader = false) { if (_nativeProperties.Any()) { if (drawHeader) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Native Properties", GetHeaderGUIStyle()); NaughtyEditorGUI.HorizontalLine( EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor()); } foreach (var property in _nativeProperties) { NaughtyEditorGUI.NativeProperty_Layout(serializedObject.targetObject, property); } } } protected void DrawButtons(bool drawHeader = false) { if (_methods.Any()) { if (drawHeader) { EditorGUILayout.Space(); EditorGUILayout.LabelField("Buttons", GetHeaderGUIStyle()); NaughtyEditorGUI.HorizontalLine( EditorGUILayout.GetControlRect(false), HorizontalLineAttribute.DefaultHeight, HorizontalLineAttribute.DefaultColor.GetColor()); } foreach (var method in _methods) { NaughtyEditorGUI.Button(serializedObject.targetObject, method); } } } private static IEnumerable GetNonGroupedProperties(IEnumerable properties) { return properties.Where(p => PropertyUtility.GetAttribute(p) == null); } private static IEnumerable> GetGroupedProperties(IEnumerable properties) { return properties .Where(p => PropertyUtility.GetAttribute(p) != null) .GroupBy(p => PropertyUtility.GetAttribute(p).Name); } private static IEnumerable> GetFoldoutProperties(IEnumerable properties) { return properties .Where(p => PropertyUtility.GetAttribute(p) != null) .GroupBy(p => PropertyUtility.GetAttribute(p).Name); } private static GUIStyle GetHeaderGUIStyle() { GUIStyle style = new GUIStyle(EditorStyles.centeredGreyMiniLabel); style.fontStyle = FontStyle.Bold; style.alignment = TextAnchor.UpperCenter; return style; } } }