From 2ddefb7f4a10d114f7217b497f607a80967dc5b3 Mon Sep 17 00:00:00 2001 From: Oliver Biwer Date: Fri, 3 Nov 2023 22:33:04 +0100 Subject: [PATCH] implements "Auto DragAndDrop UsageTypeDetection" for reference fields based on PR from @toasterhead-master - contains only changes regarding to the feature itself without any of the refactoring - reduces the amount of boilerplate classes Closes: #441 Co-authored-by: ToasterHead --- .../AtomCollectionReferenceDrawer.cs | 2 +- .../Collections/AtomListReferenceDrawer.cs | 2 +- ...tomBaseVariableBaseEventReferenceDrawer.cs | 2 +- .../VoidBaseEventReferenceDrawer.cs | 2 +- .../Editor/Drawers/AtomBaseReferenceDrawer.cs | 67 ++++++++++++++++++- .../Drawers/AtomEventReferenceDrawer.cs | 2 +- .../Editor/Drawers/AtomReferenceDrawer.cs | 2 +- .../EventInstancers/AtomEventInstancer.cs | 7 +- .../AtomBaseVariableInstancer.cs | 23 ++++++- .../FiniteStateMachineReferenceDrawer.cs | 2 +- 10 files changed, 99 insertions(+), 12 deletions(-) diff --git a/Packages/BaseAtoms/Editor/Drawers/Collections/AtomCollectionReferenceDrawer.cs b/Packages/BaseAtoms/Editor/Drawers/Collections/AtomCollectionReferenceDrawer.cs index 472ac29e..836c800a 100644 --- a/Packages/BaseAtoms/Editor/Drawers/Collections/AtomCollectionReferenceDrawer.cs +++ b/Packages/BaseAtoms/Editor/Drawers/Collections/AtomCollectionReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor /// A custom property drawer for AtomCollectionReference. Makes it possible to choose between a Collection or a Collection Instancer. /// [CustomPropertyDrawer(typeof(AtomCollectionReference), true)] - public class AtomCollectionReferenceDrawer : AtomBaseReferenceDrawer + public class AtomCollectionReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageCollection : UsageData { diff --git a/Packages/BaseAtoms/Editor/Drawers/Collections/AtomListReferenceDrawer.cs b/Packages/BaseAtoms/Editor/Drawers/Collections/AtomListReferenceDrawer.cs index dc16f5a6..acccfccd 100644 --- a/Packages/BaseAtoms/Editor/Drawers/Collections/AtomListReferenceDrawer.cs +++ b/Packages/BaseAtoms/Editor/Drawers/Collections/AtomListReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor /// A custom property drawer for AtomListReference. Makes it possible to choose between a List or a List Instancer. /// [CustomPropertyDrawer(typeof(AtomListReference), true)] - public class AtomListReferenceDrawer : AtomBaseReferenceDrawer + public class AtomListReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageList : UsageData { diff --git a/Packages/BaseAtoms/Editor/Drawers/EventReference/AtomBaseVariableBaseEventReferenceDrawer.cs b/Packages/BaseAtoms/Editor/Drawers/EventReference/AtomBaseVariableBaseEventReferenceDrawer.cs index 0df3d854..4ec6125d 100644 --- a/Packages/BaseAtoms/Editor/Drawers/EventReference/AtomBaseVariableBaseEventReferenceDrawer.cs +++ b/Packages/BaseAtoms/Editor/Drawers/EventReference/AtomBaseVariableBaseEventReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor /// A custom property drawer for AtomBaseVariable BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Added, Collection Removed, List Added, List Removed, Collection Instancer Added, Collection Instancer Removed, List Instancer Added or List Instancer Removed. /// [CustomPropertyDrawer(typeof(AtomBaseVariableBaseEventReference), true)] - public class AtomBaseVariableBaseEventReferenceDrawer : AtomBaseReferenceDrawer + public class AtomBaseVariableBaseEventReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageEvent : UsageData { diff --git a/Packages/BaseAtoms/Editor/Drawers/EventReference/VoidBaseEventReferenceDrawer.cs b/Packages/BaseAtoms/Editor/Drawers/EventReference/VoidBaseEventReferenceDrawer.cs index 0589ab66..82687ee2 100644 --- a/Packages/BaseAtoms/Editor/Drawers/EventReference/VoidBaseEventReferenceDrawer.cs +++ b/Packages/BaseAtoms/Editor/Drawers/EventReference/VoidBaseEventReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.BaseAtoms.Editor /// A custom property drawer for Void BaseEventReferences. Makes it possible to choose between an Event, Event Instancer, Collection Cleared, List Cleared, Collection Instancer Cleared or List Instancer Cleared. /// [CustomPropertyDrawer(typeof(VoidBaseEventReference), true)] - public class VoidBaseEventReferenceDrawer : AtomBaseReferenceDrawer + public class VoidBaseEventReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageEvent : UsageData { diff --git a/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs b/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs index f1b82f5a..71da31ef 100644 --- a/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs +++ b/Packages/Core/Editor/Drawers/AtomBaseReferenceDrawer.cs @@ -8,7 +8,8 @@ namespace UnityAtoms.Editor /// A custom property drawer for References (Events and regular). Makes it possible to reference a resources (Variable or Event) through multiple options. /// - public abstract class AtomBaseReferenceDrawer : PropertyDrawer + public abstract class AtomBaseReferenceDrawer : PropertyDrawer + where TInstancerType : MonoBehaviour { protected abstract class UsageData { @@ -16,6 +17,7 @@ namespace UnityAtoms.Editor public abstract string PropertyName { get; } public abstract string DisplayName { get; } } + const string USAGE_PROPERTY_NAME = "_usage"; protected abstract UsageData[] GetUsages(SerializedProperty prop = null); @@ -24,7 +26,7 @@ namespace UnityAtoms.Editor public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { - var usageIntVal = property.FindPropertyRelative("_usage").intValue; + var usageIntVal = property.FindPropertyRelative(USAGE_PROPERTY_NAME).intValue; var usageData = GetUsages(property)[0]; for (var i = 0; i < GetUsages(property).Length; ++i) { @@ -67,8 +69,9 @@ namespace UnityAtoms.Editor int indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; - var currentUsage = property.FindPropertyRelative("_usage"); + var currentUsage = property.FindPropertyRelative(USAGE_PROPERTY_NAME); var newUsageValue = EditorGUI.Popup(buttonRect, currentUsage.intValue, GetPopupOptions(property), _popupStyle); + DetermineDragAndDropFieldReferenceType(position, property, ref newUsageValue); currentUsage.intValue = newUsageValue; var usageTypePropertyName = GetUsages(property)[newUsageValue].PropertyName; @@ -100,5 +103,63 @@ namespace UnityAtoms.Editor EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } + + #region Auto DragAndDrop UsageTypeDetection + private void DetermineDragAndDropFieldReferenceType(in Rect position, SerializedProperty property, + ref int newUsageValue) + { + EventType mouseEventType = Event.current.type; + + if (mouseEventType != EventType.DragUpdated && mouseEventType != EventType.DragPerform) + return; + + if (!IsMouseHoveringOverProperty(position)) + return; + + var draggedObjects = DragAndDrop.objectReferences; + + if (draggedObjects.Length < 1) + return; + + Object draggedObject = draggedObjects[0]; + + if (draggedObject is GameObject gameObject) + draggedObject = gameObject.GetComponent(); + + UpdateConfigurationOption(property, draggedObject, ref newUsageValue); + } + + private void UpdateConfigurationOption(SerializedProperty property, Object draggedObject, ref int newUsageValue) + { + if (!draggedObject) + return; + + var usages = GetUsages(property); + + for (int index = 0; index < usages.Length; index++) + { + var usage = usages[index]; + SerializedProperty fieldProperty = property.FindPropertyRelative(usage.PropertyName); + string draggedObjectType = draggedObject.GetType().Name; + string fieldPropertyType = fieldProperty.type.Replace("PPtr<$", "").Replace(">", ""); + + if (draggedObjectType == fieldPropertyType) + { + newUsageValue = index; + break; + } + } + } + + private static bool IsMouseHoveringOverProperty(Rect rectPosition) + { + const int HEIGHT_OFFSET_TO_AVOID_OVERLAP = 1; + Rect controlRect = rectPosition; + controlRect.height -= HEIGHT_OFFSET_TO_AVOID_OVERLAP; + + return controlRect.Contains(Event.current.mousePosition); + } + #endregion + } } diff --git a/Packages/Core/Editor/Drawers/AtomEventReferenceDrawer.cs b/Packages/Core/Editor/Drawers/AtomEventReferenceDrawer.cs index 5f61288c..e9626942 100644 --- a/Packages/Core/Editor/Drawers/AtomEventReferenceDrawer.cs +++ b/Packages/Core/Editor/Drawers/AtomEventReferenceDrawer.cs @@ -6,7 +6,7 @@ namespace UnityAtoms.Editor /// A custom property drawer for Event References. Makes it possible to choose between an Event, Event Instancer, Variable or a Variable Instancer. /// [CustomPropertyDrawer(typeof(AtomBaseEventReference), true)] - public class AtomEventReferenceDrawer : AtomBaseReferenceDrawer + public class AtomEventReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageEvent : UsageData { diff --git a/Packages/Core/Editor/Drawers/AtomReferenceDrawer.cs b/Packages/Core/Editor/Drawers/AtomReferenceDrawer.cs index 4d528ce7..303dd1fa 100644 --- a/Packages/Core/Editor/Drawers/AtomReferenceDrawer.cs +++ b/Packages/Core/Editor/Drawers/AtomReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.Editor /// [CustomPropertyDrawer(typeof(AtomBaseReference), true)] - public class AtomReferenceDrawer : AtomBaseReferenceDrawer + public class AtomReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageValue : UsageData { diff --git a/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs b/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs index ad6ebdae..b5d387ca 100644 --- a/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs +++ b/Packages/Core/Runtime/EventInstancers/AtomEventInstancer.cs @@ -5,6 +5,11 @@ using UnityEngine.Assertions; namespace UnityAtoms { + public abstract class AtomEventInstancer : MonoBehaviour + { + + } + /// /// An Event Instancer is a MonoBehaviour that takes an Event as a base and creates an in memory copy of it on OnEnable. /// This is handy when you want to use Events for prefabs that are instantiated at runtime. @@ -13,7 +18,7 @@ namespace UnityAtoms /// Event of type T. [EditorIcon("atom-icon-sign-blue")] [DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)] - public abstract class AtomEventInstancer : MonoBehaviour, IGetEvent, ISetEvent + public abstract class AtomEventInstancer : AtomEventInstancer, IGetEvent, ISetEvent where E : AtomEvent { public T InspectorRaiseValue { get => _inspectorRaiseValue; } diff --git a/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs b/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs index fd38a01e..ee49e710 100644 --- a/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs +++ b/Packages/Core/Runtime/VariableInstancers/AtomBaseVariableInstancer.cs @@ -4,6 +4,11 @@ using UnityEngine.Assertions; namespace UnityAtoms { + public abstract class AtomBaseVariableInstancer : MonoBehaviour + { + + } + /// /// A Variable Instancer is a MonoBehaviour that takes a variable as a base and creates an in memory copy of it OnEnable. /// This is handy when you want to use atoms for prefabs that are instantiated at runtime. Use together with AtomCollection to @@ -17,7 +22,7 @@ namespace UnityAtoms /// Function of type T => T [EditorIcon("atom-icon-hotpink")] [DefaultExecutionOrder(Runtime.ExecutionOrder.VARIABLE_INSTANCER)] - public abstract class AtomBaseVariableInstancer : MonoBehaviour, IVariable + public abstract class AtomBaseVariableInstancer : AtomBaseVariableInstancer, IVariable where V : AtomBaseVariable { /// @@ -25,6 +30,22 @@ namespace UnityAtoms /// public V Variable { get => _inMemoryCopy; } + public void SetSource(V variable) + { + _base = variable; + if (Application.isPlaying) + { + Debug.LogWarning("Setting the underlying variable of an instancers at runtime can result in hard to find issues. be careful."); + if (_inMemoryCopy != null) + { + Destroy(_inMemoryCopy); + _inMemoryCopy = null; + } + OnEnable(); + } + + } + /// /// Getter for retrieving the value of the in memory runtime variable. /// diff --git a/Packages/FSM/Editor/Drawers/FiniteStateMachineReferenceDrawer.cs b/Packages/FSM/Editor/Drawers/FiniteStateMachineReferenceDrawer.cs index d87abd69..874e42f7 100644 --- a/Packages/FSM/Editor/Drawers/FiniteStateMachineReferenceDrawer.cs +++ b/Packages/FSM/Editor/Drawers/FiniteStateMachineReferenceDrawer.cs @@ -7,7 +7,7 @@ namespace UnityAtoms.FSM.Editor /// A custom property drawer for FiniteStateMachineReference. Makes it possible to choose between a FSM or a FSM Instancer. /// [CustomPropertyDrawer(typeof(FiniteStateMachineReference), true)] - public class FiniteStateMachineReferenceDrawer : AtomBaseReferenceDrawer + public class FiniteStateMachineReferenceDrawer : AtomBaseReferenceDrawer { protected class UsageFSM : UsageData {