From 4c9fa6b348bbea16e75954f89f6caa6e37f69189 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 26 Oct 2023 20:39:13 +0900 Subject: [PATCH] fix: prefab blinks when we see editor of PrefabSafeSet of prefab asset --- .../PrefabSafeSet/Editor/BasicTypeEditors.cs | 171 ++++++++++ .../Editor/BasicTypeEditors.cs.meta | 3 + .../Editor/PrefabSafeSetEditor.cs | 307 ++---------------- 3 files changed, 208 insertions(+), 273 deletions(-) create mode 100644 Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs create mode 100644 Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs.meta diff --git a/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs b/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs new file mode 100644 index 000000000..43b7cb974 --- /dev/null +++ b/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs @@ -0,0 +1,171 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Anatawa12.AvatarOptimizer.PrefabSafeSet +{ + abstract class BasicEditorBase : EditorBase + { + private protected override float GetAddRegionSize() => EditorGUIUtility.singleLineHeight; + + private protected override void OnGUIAddRegion(Rect position) => + EditorGUI.LabelField(position, EditorStatics.ToAdd, EditorStatics.AddNotSupported); + + protected BasicEditorBase(SerializedProperty property, int nestCount) : base(property, nestCount) + { + } + } + + class IntegerEditorImpl : BasicEditorBase + { + public IntegerEditorImpl(SerializedProperty property, int nestCount) : base(property, nestCount) + { + } + + private protected override long GetValue(SerializedProperty prop) => prop.longValue; + private protected override void SetValue(SerializedProperty prop, long value) => prop.longValue = value; + + protected override float FieldHeight(GUIContent label) => + EditorGUI.GetPropertyHeight(SerializedPropertyType.Integer, label); + + protected override long Field(Rect position, GUIContent label, long value) => + EditorGUI.LongField(position, label, value); + } + + class StringEditorImpl : BasicEditorBase + { + public StringEditorImpl(SerializedProperty property, int nestCount) : base(property, nestCount) + { + } + + private protected override string GetValue(SerializedProperty prop) => prop.stringValue; + private protected override void SetValue(SerializedProperty prop, string value) => prop.stringValue = value; + + protected override float FieldHeight(GUIContent label) => + EditorGUI.GetPropertyHeight(SerializedPropertyType.String, label); + + protected override string Field(Rect position, GUIContent label, string value) => + EditorGUI.TextField(position, label, value); + } + + class ObjectEditorImpl : EditorBase + { + public ObjectEditorImpl(SerializedProperty property, int nestCount) : base(property, nestCount) + { + } + + private protected override Object GetValue(SerializedProperty prop) => prop.objectReferenceValue; + private protected override void SetValue(SerializedProperty prop, Object value) => + prop.objectReferenceValue = value; + + private protected override float GetAddRegionSize() => EditorGUIUtility.singleLineHeight; + + private protected override void OnGUIAddRegion(Rect position) + { + var current = Event.current; + var eventType = current.type; + switch (eventType) + { + case EventType.DragUpdated: + case EventType.DragPerform: + case EventType.DragExited: + { + var controlId = + GUIUtility.GetControlID("s_PPtrHash".GetHashCode(), FocusType.Keyboard, position); + position = EditorGUI.PrefixLabel(position, controlId, EditorStatics.ToAdd); + HandleDragEvent(position, controlId, current); + break; + } + default: + { + var addValue = Field(position, EditorStatics.ToAdd, null); + if (addValue != null) EditorUtil.GetElementOf(addValue).Add(); + break; + } + } + } + + protected override float FieldHeight(GUIContent label) => + EditorGUI.GetPropertyHeight(SerializedPropertyType.ObjectReference, label); + + protected override Object Field(Rect position, GUIContent label, Object value) + { + bool allowSceneObjects = false; + var targetObject = FakeSlot.serializedObject.targetObject; + if (targetObject != null && !EditorUtility.IsPersistent(targetObject)) + allowSceneObjects = true; + return EditorGUI.ObjectField(position, label, value, null, allowSceneObjects); + } + + public void HandleDragEvent(Rect position, int lastControlId, Event @event) + { + switch (@event.type) + { + case EventType.DragUpdated: + case EventType.DragPerform: + if (position.Contains(@event.mousePosition) && GUI.enabled) + { + var objectReferences = DragAndDrop.objectReferences; + var referencesCache = new Object[1]; + var flag3 = false; + foreach (var object1 in objectReferences) + { + referencesCache[0] = object1; + var object2 = ValidateObjectFieldAssignment(referencesCache, FakeSlot); + if (object2 == null) continue; + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + if (@event.type == EventType.DragPerform) + { + EditorUtil.GetElementOf(object2).EnsureAdded(); + flag3 = true; + DragAndDrop.activeControlID = 0; + } + else + DragAndDrop.activeControlID = lastControlId; + } + + if (flag3) + { + GUI.changed = true; + DragAndDrop.AcceptDrag(); + } + } + + break; + case EventType.DragExited: + if (GUI.enabled) + HandleUtility.Repaint(); + break; + } + } + + private static readonly MethodInfo ValidateObjectFieldAssignmentMethod = + typeof(EditorGUI).GetMethod("ValidateObjectFieldAssignment", BindingFlags.Static | BindingFlags.NonPublic); + + private static readonly Type ObjectFieldValidatorOptionsType = + typeof(EditorGUI).Assembly.GetType("UnityEditor.EditorGUI+ObjectFieldValidatorOptions"); + + private static Object ValidateObjectFieldAssignment(Object[] references, + SerializedProperty property) + { + if (ValidateObjectFieldAssignmentMethod == null) + { + Debug.LogError( + "Compatibility with Unity broke: can't find ValidateObjectFieldAssignment method in EditorGUI"); + return null; + } + + if (ObjectFieldValidatorOptionsType == null) + { + Debug.LogError( + "Compatibility with Unity broke: can't find ObjectFieldValidatorOptions type in EditorGUI"); + return null; + } + + return ValidateObjectFieldAssignmentMethod.Invoke(null, + new[] { references, null, property, Enum.ToObject(ObjectFieldValidatorOptionsType, 0) }) as Object; + } + } +} \ No newline at end of file diff --git a/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs.meta b/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs.meta new file mode 100644 index 000000000..f12968778 --- /dev/null +++ b/Internal/PrefabSafeSet/Editor/BasicTypeEditors.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d0ed527003804d7a8c3c6f60adacdb0d +timeCreated: 1698310231 \ No newline at end of file diff --git a/Internal/PrefabSafeSet/Editor/PrefabSafeSetEditor.cs b/Internal/PrefabSafeSet/Editor/PrefabSafeSetEditor.cs index abd78cde5..dff5c05d9 100644 --- a/Internal/PrefabSafeSet/Editor/PrefabSafeSetEditor.cs +++ b/Internal/PrefabSafeSet/Editor/PrefabSafeSetEditor.cs @@ -49,39 +49,35 @@ internal class ObjectsEditor : PropertyDrawer private int GetNestCount(Object obj) => _nestCountCache != -1 ? _nestCountCache : _nestCountCache = PrefabSafeSetUtil.PrefabNestCount(obj); - private readonly Dictionary _caches = - new Dictionary(); + private readonly Dictionary _caches = + new Dictionary(); [CanBeNull] - private Editor GetCache(SerializedProperty property) + private EditorBase GetCache(SerializedProperty property) { if (!_caches.TryGetValue(property.propertyPath, out var cached)) { var prop = property.FindPropertyRelative(Names.FakeSlot); - if (IsSupportedPropType(prop.propertyType)) - { - _caches[property.propertyPath] = cached = - new Editor(property, GetNestCount(property.serializedObject.targetObject)); - } - else - { - _caches[property.propertyPath] = cached = null; - } + _caches[property.propertyPath] = + cached = GetEditorImpl(prop.propertyType, property, GetNestCount(property.serializedObject.targetObject)); } return cached; } - private static bool IsSupportedPropType(SerializedPropertyType type) + private static EditorBase GetEditorImpl(SerializedPropertyType type, SerializedProperty property, int nestCount) { switch (type) { case SerializedPropertyType.Integer: + return new IntegerEditorImpl(property, nestCount); + case SerializedPropertyType.String: + return new StringEditorImpl(property, nestCount); + case SerializedPropertyType.ObjectReference: + return new ObjectEditorImpl(property, nestCount); case SerializedPropertyType.Boolean: case SerializedPropertyType.Float: - case SerializedPropertyType.String: case SerializedPropertyType.Color: - case SerializedPropertyType.ObjectReference: case SerializedPropertyType.LayerMask: case SerializedPropertyType.Enum: case SerializedPropertyType.Vector2: @@ -97,177 +93,8 @@ private static bool IsSupportedPropType(SerializedPropertyType type) case SerializedPropertyType.Vector3Int: case SerializedPropertyType.RectInt: case SerializedPropertyType.BoundsInt: - return true; default: - return false; - } - } - - private class Editor : EditorBase - { - public Editor(SerializedProperty property, int nestCount) : base(property, nestCount) - { - } - - public EditorUtil GetEditorUtil() => EditorUtil; - public SerializedProperty GetFakeSlot() => FakeSlot; - - private protected override object GetValue(SerializedProperty prop) - { - switch (prop.propertyType) - { - case SerializedPropertyType.Integer: - return prop.intValue; - case SerializedPropertyType.Boolean: - return prop.boolValue; - case SerializedPropertyType.Float: - return prop.floatValue; - case SerializedPropertyType.String: - return prop.stringValue; - case SerializedPropertyType.Color: - return prop.colorValue; - case SerializedPropertyType.ObjectReference: - return prop.objectReferenceValue; - case SerializedPropertyType.LayerMask: - return (LayerMask) prop.intValue; - case SerializedPropertyType.Enum: - return prop.enumValueIndex; - case SerializedPropertyType.Vector2: - return prop.vector2Value; - case SerializedPropertyType.Vector3: - return prop.vector3Value; - case SerializedPropertyType.Vector4: - return prop.vector4Value; - case SerializedPropertyType.Rect: - return prop.rectValue; - case SerializedPropertyType.ArraySize: - return prop.intValue; - case SerializedPropertyType.Character: - return (char) prop.intValue; - case SerializedPropertyType.AnimationCurve: - return prop.animationCurveValue; - case SerializedPropertyType.Bounds: - return prop.boundsValue; - case SerializedPropertyType.ExposedReference: - return prop.exposedReferenceValue; - case SerializedPropertyType.Vector2Int: - return prop.vector2IntValue; - case SerializedPropertyType.Vector3Int: - return prop.vector3IntValue; - case SerializedPropertyType.RectInt: - return prop.rectIntValue; - case SerializedPropertyType.BoundsInt: - return prop.boundsIntValue; - default: - throw new InvalidOperationException(); - } - } - - private protected override void SetValue(SerializedProperty prop, object value) - { - switch (prop.propertyType) - { - case SerializedPropertyType.Integer: - prop.intValue = (int)value; - break; - case SerializedPropertyType.Boolean: - prop.boolValue = (bool)value; - break; - case SerializedPropertyType.Float: - prop.floatValue = (float)value; - break; - case SerializedPropertyType.String: - prop.stringValue = (string)value; - break; - case SerializedPropertyType.Color: - prop.colorValue = (Color)value; - break; - case SerializedPropertyType.ObjectReference: - prop.objectReferenceValue = (Object)value; - break; - case SerializedPropertyType.LayerMask: - prop.intValue = (LayerMask)value; - break; - case SerializedPropertyType.Enum: - prop.enumValueIndex = (int)value; - break; - case SerializedPropertyType.Vector2: - prop.vector2Value = (Vector2)value; - break; - case SerializedPropertyType.Vector3: - prop.vector3Value = (Vector3)value; - break; - case SerializedPropertyType.Vector4: - prop.vector4Value = (Vector4)value; - break; - case SerializedPropertyType.Rect: - prop.rectValue = (Rect)value; - break; - case SerializedPropertyType.ArraySize: - prop.intValue = (int)value; - break; - case SerializedPropertyType.Character: - prop.intValue = (char)value; - break; - case SerializedPropertyType.AnimationCurve: - prop.animationCurveValue = (AnimationCurve)value; - break; - case SerializedPropertyType.Bounds: - prop.boundsValue = (Bounds)value; - break; - case SerializedPropertyType.ExposedReference: - prop.exposedReferenceValue = (Object)value; - break; - case SerializedPropertyType.Vector2Int: - prop.vector2IntValue = (Vector2Int)value; - break; - case SerializedPropertyType.Vector3Int: - prop.vector3IntValue = (Vector3Int)value; - break; - case SerializedPropertyType.RectInt: - prop.rectIntValue = (RectInt)value; - break; - case SerializedPropertyType.BoundsInt: - prop.boundsIntValue = (BoundsInt)value; - break; - default: - throw new InvalidOperationException(); - } - } - - private protected override float GetAddRegionSize() => EditorGUIUtility.singleLineHeight; - - private protected override void OnGUIAddRegion(Rect position) - { - if (FakeSlot.propertyType == SerializedPropertyType.ObjectReference) - { - var current = Event.current; - var eventType = current.type; - switch (eventType) - { - case EventType.DragUpdated: - case EventType.DragPerform: - case EventType.DragExited: - { - var controlId = GUIUtility.GetControlID("s_PPtrHash".GetHashCode(), FocusType.Keyboard, position); - position = EditorGUI.PrefixLabel(position, controlId, EditorStatics.ToAdd); - HandleDragEvent(position, controlId, current, this); - break; - } - default: - { - SetValue(FakeSlot, default); - EditorGUI.PropertyField(position, FakeSlot, EditorStatics.ToAdd); - var addValue = FakeSlot.objectReferenceValue; - if (addValue != null) EditorUtil.GetElementOf(addValue).Add(); - break; - } - } - } - else - { - EditorGUI.LabelField(position, EditorStatics.ToAdd, EditorStatics.AddNotSupported); - } + return null; } } @@ -311,9 +138,9 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten } } - private bool PropertyGUI(Rect position, SerializedProperty property, GUIContent label, Editor editor) + private bool PropertyGUI(Rect position, SerializedProperty property, GUIContent label, EditorBase editor) { - var hasOverride = editor.GetEditorUtil().HasPrefabOverride(); + var hasOverride = editor.HasPrefabOverride(); if (hasOverride) EditorGUI.BeginProperty(position, label, property); @@ -329,55 +156,13 @@ private bool PropertyGUI(Rect position, SerializedProperty property, GUIContent int lastControlId = GetLastControlId(); - HandleDragEvent(position, lastControlId, @event, editor); + (editor as ObjectEditorImpl)?.HandleDragEvent(position, lastControlId, @event); if (hasOverride) EditorGUI.EndProperty(); return isExpanded; } - private static void HandleDragEvent(Rect position, int lastControlId, Event @event, Editor editor) - { - switch (@event.type) - { - case EventType.DragUpdated: - case EventType.DragPerform: - if (position.Contains(@event.mousePosition) && GUI.enabled) - { - var objectReferences = DragAndDrop.objectReferences; - var referencesCache = new Object[1]; - var flag3 = false; - foreach (var object1 in objectReferences) - { - referencesCache[0] = object1; - var object2 = ValidateObjectFieldAssignment(referencesCache, editor.GetFakeSlot()); - if (object2 == null) continue; - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - if (@event.type == EventType.DragPerform) - { - editor.GetEditorUtil().GetElementOf(object2).EnsureAdded(); - flag3 = true; - DragAndDrop.activeControlID = 0; - } - else - DragAndDrop.activeControlID = lastControlId; - } - - if (flag3) - { - GUI.changed = true; - DragAndDrop.AcceptDrag(); - } - } - - break; - case EventType.DragExited: - if (GUI.enabled) - HandleUtility.Repaint(); - break; - } - } - private static readonly FieldInfo LastControlIdField = typeof(EditorGUIUtility).GetField("s_LastControlID", BindingFlags.Static | BindingFlags.NonPublic); @@ -391,34 +176,6 @@ private static int GetLastControlId() return (int)LastControlIdField.GetValue(null); } - - private static readonly MethodInfo ValidateObjectFieldAssignmentMethod = - typeof(EditorGUI).GetMethod("ValidateObjectFieldAssignment", BindingFlags.Static | BindingFlags.NonPublic); - - private static readonly Type ObjectFieldValidatorOptionsType = - typeof(EditorGUI).Assembly.GetType("UnityEditor.EditorGUI+ObjectFieldValidatorOptions"); - - private static Object ValidateObjectFieldAssignment(Object[] references, - SerializedProperty property) - { - if (ValidateObjectFieldAssignmentMethod == null) - { - Debug.LogError( - "Compatibility with Unity broke: can't find ValidateObjectFieldAssignment method in EditorGUI"); - return null; - } - - if (ObjectFieldValidatorOptionsType == null) - { - Debug.LogError( - "Compatibility with Unity broke: can't find ObjectFieldValidatorOptions type in EditorGUI"); - return null; - } - - return ValidateObjectFieldAssignmentMethod.Invoke(null, - new[] { references, null, property, Enum.ToObject(ObjectFieldValidatorOptionsType, 0) }) as Object; - } - } /// @@ -433,10 +190,17 @@ internal static class Names public const string Removes = nameof(PrefabLayer.removes); } - internal abstract class EditorBase + internal abstract class EditorBase + { + public abstract float GetPropertyHeight(); + public abstract void OnGUI(Rect position); + public abstract bool HasPrefabOverride(); + } + + internal abstract class EditorBase : EditorBase { [NotNull] protected readonly SerializedProperty FakeSlot; - protected readonly EditorUtil EditorUtil; + internal readonly EditorUtil EditorUtil; public EditorBase(SerializedProperty property, int nestCount) { @@ -452,12 +216,16 @@ public EditorBase(SerializedProperty property, int nestCount) private protected abstract float GetAddRegionSize(); private protected abstract void OnGUIAddRegion(Rect position); - public float GetPropertyHeight() => - EditorUtil.ElementsCount * (FieldHeight() + EditorGUIUtility.standardVerticalSpacing) + public override bool HasPrefabOverride() => EditorUtil.HasPrefabOverride(); + + private static readonly GUIContent content = new GUIContent("Element 0"); + + public override float GetPropertyHeight() => + EditorUtil.ElementsCount * (FieldHeight(content) + EditorGUIUtility.standardVerticalSpacing) + GetAddRegionSize(); // position is - public void OnGUI(Rect position) + public override void OnGUI(Rect position) { var elementI = 0; var newLabel = new GUIContent(""); @@ -511,7 +279,7 @@ public void OnGUI(Rect position) break; } - position.y += FieldHeight() + EditorGUIUtility.standardVerticalSpacing; + position.y += FieldHeight(newLabel) + EditorGUIUtility.standardVerticalSpacing; } action?.Invoke(); @@ -557,14 +325,7 @@ private ModificationKind OnePrefabElement(Rect position, GUIContent label, IElem return result; } - protected virtual float FieldHeight() => EditorGUI.GetPropertyHeight(FakeSlot); - - protected virtual T Field(Rect position, GUIContent label, T value) - { - SetValue(FakeSlot, value); - EditorGUI.PropertyField(position, FakeSlot, label); - value = GetValue(FakeSlot); - return value; - } + protected abstract float FieldHeight(GUIContent label); + protected abstract T Field(Rect position, GUIContent label, T value); } }