diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..94618b6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. Windows] + +**Unity (please complete the following information):** + - Version [e.g. 2021.3.2f1] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bd16c81 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: Thundernerd + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..6e03820 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,39 @@ +## Proposed changes + +Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. + +## Types of changes + +_Put an `x` in the boxes that apply._ + +- [ ] Bugfix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Refactoring (no functional changes, no api changes) +- [ ] Code style update (formatting, renaming) +- [ ] Build related changes (workflow changes) +- [ ] Documentation Update (readme, changelog) +- [ ] Other, please describe: + + +## Issue +Include a link to the issue if applicable, otherwise you can remove this section. + +## What is the current behavior? +Please describe the current behavior that you are modifying. + +## What is the new behavior? +Please describe the behavior or changes that are being added by this PR. + +## Checklist + +_Put an `x` in the boxes that apply._ + +- [ ] The code compiles +- [ ] I have tested that this doesn't break existing code (unless it is an explicit breaking change) +- [ ] I have tested that the (new) functionality/fix works as intended +- [ ] I have added necessary documentation (if appropriate) + +## Further comments + +If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... diff --git a/CHANGELOG.md b/CHANGELOG.md index d64f140..4032010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +## [1.10.0](https://github.com/Thundernerd/Unity3D-SerializableInterface/compare/v1.9.0...v1.10.0) (2022-07-25) + + +### Features + +* added methods for getting and setting values with serialized properties ([aba0c30](https://github.com/Thundernerd/Unity3D-SerializableInterface/commit/aba0c305b87ab843a3842d584a38d58487e61a89)) +* added passing serialized property to CustomObjectDrawer and Dropdown ([5913ab7](https://github.com/Thundernerd/Unity3D-SerializableInterface/commit/5913ab76e7759e2264a2979081972468dcae2f40)) +* added serialized property extensions for convenience ([547c892](https://github.com/Thundernerd/Unity3D-SerializableInterface/commit/547c89271c892ca1bfa14e30958437c379dc9853)) + +### [1.9.0](https://github.com/Thundernerd/Unity3D-SerializableInterface/compare/v1.8.0...v1.9.0) (2202-07-23) + + +### What's Changed +* Added RawReferenceDrawer.Styles.cs + DrawLine - #41 by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/42 +* ReferenceMode + AvoidDuplicateReferencesInArray by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/43 + +### [1.8.0](https://github.com/Thundernerd/Unity3D-SerializableInterface/compare/v1.7.3...v1.8.0) (2022-07-22) + +### What's Changed +* fix: added null check to prevent null reference exception when clicking properties by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/23 +* #24 add none option custom drawers by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/26 +* Fixed Drag and Drop behaviour by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/28 +* Fixes #25 SerializableInterface maintains instances when set by Inspector by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/27 +* #34 add prefabs assets item builder by @marc-antoine-girard in https://github.com/Thundernerd/Unity3D-SerializableInterface/pull/35 + ### [1.7.3](https://github.com/Thundernerd/Unity3D-SerializableInterface/compare/v1.7.2...v1.7.3) (2022-07-22) diff --git a/Editor/Drawers/CustomObjectDrawer.cs b/Editor/Drawers/CustomObjectDrawer.cs index 5b6b27e..09697bb 100644 --- a/Editor/Drawers/CustomObjectDrawer.cs +++ b/Editor/Drawers/CustomObjectDrawer.cs @@ -5,13 +5,13 @@ namespace TNRD.Drawers { public partial class CustomObjectDrawer { - public delegate void ButtonClickedDelegate(Rect position); + public delegate void ButtonClickedDelegate(Rect position, SerializedProperty property); - public delegate void ClickedDelegate(); + public delegate void ClickedDelegate(SerializedProperty property); - public delegate void DeletePressedDelegate(); + public delegate void DeletePressedDelegate(SerializedProperty property); - public delegate void PropertiesClickedDelegate(); + public delegate void PropertiesClickedDelegate(SerializedProperty property); private bool isSelected; @@ -21,18 +21,18 @@ public partial class CustomObjectDrawer public event ClickedDelegate Clicked; public event DeletePressedDelegate DeletePressed; public event PropertiesClickedDelegate PropertiesClicked; - - public void OnGUI(Rect position, GUIContent label, GUIContent content) + + public void OnGUI(Rect position, GUIContent label, GUIContent content, SerializedProperty property) { Rect positionWithoutThumb = new Rect(position); positionWithoutThumb.xMax -= 20; position = DrawPrefixLabel(position, label); DrawObjectField(position, content); - DrawButton(position); + DrawButton(position, property); - HandleMouseDown(position, positionWithoutThumb); - HandleKeyDown(); + HandleMouseDown(position, positionWithoutThumb, property); + HandleKeyDown(property); } private Rect DrawPrefixLabel(Rect position, GUIContent label) @@ -66,7 +66,7 @@ private void ForceRepaintEditors() } } - private void DrawButton(Rect position) + private void DrawButton(Rect position, SerializedProperty property) { Rect buttonRect = new Rect(position); buttonRect.yMin += 1; @@ -76,11 +76,11 @@ private void DrawButton(Rect position) if (GUI.Button(buttonRect, string.Empty, "objectFieldButton")) { - ButtonClicked?.Invoke(position); + ButtonClicked?.Invoke(position, property); } } - private void HandleMouseDown(Rect position, Rect positionWithoutThumb) + private void HandleMouseDown(Rect position, Rect positionWithoutThumb, SerializedProperty property) { if (Event.type != EventType.MouseDown) return; @@ -89,26 +89,26 @@ private void HandleMouseDown(Rect position, Rect positionWithoutThumb) { isSelected = positionWithoutThumb.Contains(Event.mousePosition); ForceRepaintEditors(); - Clicked?.Invoke(); + Clicked?.Invoke(property); } else if (Event.button == 1 && positionWithoutThumb.Contains(Event.mousePosition)) { GenericMenu menu = new GenericMenu(); - menu.AddItem(new GUIContent("Clear"), false, () => { DeletePressed?.Invoke(); }); - menu.AddItem(new GUIContent("Properties..."), false, () => { PropertiesClicked?.Invoke(); }); + menu.AddItem(new GUIContent("Clear"), false, () => { DeletePressed?.Invoke(property); }); + menu.AddItem(new GUIContent("Properties..."), false, () => { PropertiesClicked?.Invoke(property); }); menu.DropDown(position); Event.Use(); } } - private void HandleKeyDown() + private void HandleKeyDown(SerializedProperty property) { if (!isSelected) return; if (Event.type == EventType.KeyDown && Event.keyCode == KeyCode.Delete) { - DeletePressed?.Invoke(); + DeletePressed?.Invoke(property); } } } diff --git a/Editor/Drawers/RawReferenceDrawer.cs b/Editor/Drawers/RawReferenceDrawer.cs index 23b9348..6ff5eaf 100644 --- a/Editor/Drawers/RawReferenceDrawer.cs +++ b/Editor/Drawers/RawReferenceDrawer.cs @@ -45,7 +45,7 @@ public void OnGUI(Rect position) ? EditorGUIUtility.ObjectContent((MonoScript)null, typeof(MonoScript)) : new GUIContent(rawReferenceValue.GetType().Name, IconUtility.ScriptIcon); - CustomObjectDrawer.OnGUI(objectFieldRect, label, content); + CustomObjectDrawer.OnGUI(objectFieldRect, label, content, Property); HandleDragAndDrop(objectFieldRect); @@ -79,13 +79,13 @@ private void DrawLine(Rect position) EditorGUI.DrawRect(line, Styles.LineColor); } - protected override void PingObject() + protected override void PingObject(SerializedProperty property) { // No support for pinging raw objects for now (I guess this would ping the MonoScript?) } /// - protected override void OnPropertiesClicked() + protected override void OnPropertiesClicked(SerializedProperty property) { if (RawReferenceValue == null) return; diff --git a/Editor/Drawers/ReferenceDrawer.cs b/Editor/Drawers/ReferenceDrawer.cs index 56456fd..85e4010 100644 --- a/Editor/Drawers/ReferenceDrawer.cs +++ b/Editor/Drawers/ReferenceDrawer.cs @@ -27,69 +27,28 @@ private enum DragAndDropMode protected SerializedProperty Property { get; private set; } protected Type GenericType { get; private set; } - protected SerializedProperty ReferenceModeProperty => Property.FindPropertyRelative("mode"); - protected SerializedProperty RawReferenceProperty => Property.FindPropertyRelative("rawReference"); - protected SerializedProperty UnityReferenceProperty => Property.FindPropertyRelative("unityReference"); + protected SerializedProperty ReferenceModeProperty => Property.ReferenceModeProperty(); + protected SerializedProperty RawReferenceProperty => Property.RawReferenceProperty(); + protected SerializedProperty UnityReferenceProperty => Property.UnityReferenceProperty(); protected FieldInfo FieldInfo { get; private set; } protected ReferenceMode ModeValue { - get => (ReferenceMode)ReferenceModeProperty.enumValueIndex; - set => ReferenceModeProperty.enumValueIndex = (int)value; + get => GetModeValue(Property); + set => SetModeValue(Property, value); } protected object RawReferenceValue { - get - { -#if UNITY_2021_1_OR_NEWER - return RawReferenceProperty.managedReferenceValue; -#else - ISerializableInterface instance = - (ISerializableInterface)FieldInfo.GetValue(Property.serializedObject.targetObject); - return instance.GetRawReference(); -#endif - } - set - { -#if UNITY_2021_1_OR_NEWER - RawReferenceProperty.managedReferenceValue = value; -#else - FieldInfo.SetValue(Property.serializedObject.targetObject, value); -#endif - } + get => GetRawReferenceValue(Property); + set => SetRawReferenceValue(Property, value); } protected object PropertyValue { - get - { - return ModeValue switch - { - ReferenceMode.Raw => RawReferenceValue, - ReferenceMode.Unity => UnityReferenceProperty.objectReferenceValue, - _ => throw new ArgumentOutOfRangeException() - }; - } - set - { - switch (ModeValue) - { - case ReferenceMode.Raw: - RawReferenceValue = value; - UnityReferenceProperty.objectReferenceValue = null; - break; - case ReferenceMode.Unity: - UnityReferenceProperty.objectReferenceValue = GetUnityObject((Object)value); - RawReferenceValue = null; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - Property.serializedObject.ApplyModifiedProperties(); - } + get => GetPropertyValue(Property); + set => SetPropertyValue(Property, value); } protected ReferenceDrawer() @@ -108,18 +67,18 @@ protected void Initialize(SerializedProperty property, Type genericType, FieldIn FieldInfo = fieldInfo; } - private void OnButtonClicked(Rect position) + private void OnButtonClicked(Rect position, SerializedProperty property) { AdvancedDropdownState state = new AdvancedDropdownState(); SerializableInterfaceAdvancedDropdown dropdown = - new SerializableInterfaceAdvancedDropdown(state, GenericType, GetRelevantScene()); + new SerializableInterfaceAdvancedDropdown(state, GenericType, GetRelevantScene(property), property); dropdown.ItemSelectedEvent += OnItemSelected; dropdown.Show(position); } - private Scene? GetRelevantScene() + private static Scene? GetRelevantScene(SerializedProperty property) { - Object target = Property.serializedObject.targetObject; + Object target = property.serializedObject.targetObject; if (target is ScriptableObject) return null; @@ -131,30 +90,30 @@ private void OnButtonClicked(Rect position) return null; } - private void OnClicked() + private void OnClicked(SerializedProperty property) { - PingObject(); + PingObject(property); } - private void OnDeletePressed() + private void OnDeletePressed(SerializedProperty property) { - ModeValue = default; - PropertyValue = null; + SetModeValue(property, default); + SetPropertyValue(property, null); } - private void OnItemSelected(ReferenceMode mode, object reference) + private void OnItemSelected(SerializedProperty property, ReferenceMode mode, object reference) { - ModeValue = mode; - PropertyValue = reference; + SetModeValue(property, mode); + SetPropertyValue(property, reference); } - protected abstract void OnPropertiesClicked(); + protected abstract void OnPropertiesClicked(SerializedProperty property); protected void HandleDragAndDrop(Rect position) { if (!position.Contains(Event.current.mousePosition)) return; - + if (Event.current.type == EventType.DragPerform) { HandleDragUpdated(); @@ -241,11 +200,80 @@ private void HandleDragPerform() private Object GetUnityObject(Object objectReference) { - if(objectReference is GameObject gameObject) + if (objectReference is GameObject gameObject) return gameObject.GetComponent(GenericType); return objectReference; } - protected abstract void PingObject(); + protected abstract void PingObject(SerializedProperty property); + + protected ReferenceMode GetModeValue(SerializedProperty property) + { + return (ReferenceMode)property.ReferenceModeProperty().enumValueIndex; + } + + protected void SetModeValue(SerializedProperty property, ReferenceMode mode) + { + property.ReferenceModeProperty().enumValueIndex = (int)mode; + } + + protected object GetRawReferenceValue(SerializedProperty property) + { +#if UNITY_2021_1_OR_NEWER + return property.RawReferenceProperty().managedReferenceValue; +#else + ISerializableInterface instance = + (ISerializableInterface)FieldInfo.GetValue(property.serializedObject.targetObject); + return instance.GetRawReference(); +#endif + } + + protected void SetRawReferenceValue(SerializedProperty property, object value) + { +#if UNITY_2021_1_OR_NEWER + property.RawReferenceProperty().managedReferenceValue = value; +#else + FieldInfo.SetValue(property.serializedObject.targetObject, value); +#endif + } + + protected Object GetUnityReferenceValue(SerializedProperty property) + { + return property.UnityReferenceProperty().objectReferenceValue; + } + + protected void SetUnityReferenceValue(SerializedProperty property, object value) + { + property.UnityReferenceProperty().objectReferenceValue = GetUnityObject((Object)value); + } + + protected object GetPropertyValue(SerializedProperty property) + { + return GetModeValue(property) switch + { + ReferenceMode.Raw => GetRawReferenceValue(property), + ReferenceMode.Unity => GetUnityReferenceValue(property), + _ => throw new ArgumentOutOfRangeException() + }; + } + + protected void SetPropertyValue(SerializedProperty property, object value) + { + switch (GetModeValue(property)) + { + case ReferenceMode.Unity: + SetUnityReferenceValue(property, value); + SetRawReferenceValue(property, null); + break; + case ReferenceMode.Raw: + SetRawReferenceValue(property, value); + SetUnityReferenceValue(property, null); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + property.serializedObject.ApplyModifiedProperties(); + } } } diff --git a/Editor/Drawers/UnityReferenceDrawer.cs b/Editor/Drawers/UnityReferenceDrawer.cs index 45a8893..3886f27 100644 --- a/Editor/Drawers/UnityReferenceDrawer.cs +++ b/Editor/Drawers/UnityReferenceDrawer.cs @@ -27,18 +27,18 @@ public void OnGUI(Rect position) Object unityReference = UnityReferenceProperty.objectReferenceValue; Type referenceType = unityReference == null ? typeof(Object) : unityReference.GetType(); GUIContent objectContent = EditorGUIUtility.ObjectContent(unityReference, referenceType); - CustomObjectDrawer.OnGUI(position, label, objectContent); + CustomObjectDrawer.OnGUI(position, label, objectContent, Property); HandleDragAndDrop(position); } - protected override void PingObject() + protected override void PingObject(SerializedProperty property) { - EditorGUIUtility.PingObject((Object)PropertyValue); + EditorGUIUtility.PingObject((Object)GetPropertyValue(property)); } - protected override void OnPropertiesClicked() + protected override void OnPropertiesClicked(SerializedProperty property) { - PropertyEditorUtility.Show(UnityReferenceProperty.objectReferenceValue); + PropertyEditorUtility.Show(property.UnityReferenceProperty().objectReferenceValue); } } } diff --git a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs index 923d03a..bae1c81 100644 --- a/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs +++ b/Editor/Utilities/SerializableInterfaceAdvancedDropdown.cs @@ -3,6 +3,7 @@ using System.Reflection; using TNRD.Builders; using TNRD.Items; +using UnityEditor; using UnityEditor.IMGUI.Controls; using UnityEngine; using UnityEngine.Assertions; @@ -16,8 +17,9 @@ internal sealed class SerializableInterfaceAdvancedDropdown : AdvancedDropdown private readonly MethodInfo sortChildrenMethod; private readonly bool canSort; private readonly Scene? relevantScene; + private readonly SerializedProperty property; - public delegate void ItemSelectedDelegate(ReferenceMode mode, object reference); + public delegate void ItemSelectedDelegate(SerializedProperty property, ReferenceMode mode, object reference); public event ItemSelectedDelegate ItemSelectedEvent; // Suffixed with Event because of the override @@ -25,7 +27,8 @@ internal sealed class SerializableInterfaceAdvancedDropdown : AdvancedDropdown public SerializableInterfaceAdvancedDropdown( AdvancedDropdownState state, Type interfaceType, - Scene? relevantScene + Scene? relevantScene, + SerializedProperty property ) : base(state) { @@ -38,6 +41,7 @@ public SerializableInterfaceAdvancedDropdown( minimumSize = new Vector2(0, 300); this.interfaceType = interfaceType; this.relevantScene = relevantScene; + this.property = property; } /// @@ -52,7 +56,7 @@ protected override AdvancedDropdownItem BuildRoot() { dropdownItem.AddChild(new NoneDropdownItem()); } - + if (canSort) { sortChildrenMethod.Invoke(item, @@ -72,7 +76,7 @@ private int Sort(AdvancedDropdownItem a, AdvancedDropdownItem b) return -1; if (b is NoneDropdownItem) return 1; - + int childrenA = a.children.Count(); int childrenB = b.children.Count(); @@ -90,7 +94,7 @@ protected override void ItemSelected(AdvancedDropdownItem item) { if (item is IDropdownItem dropdownItem) { - ItemSelectedEvent?.Invoke(dropdownItem.Mode, dropdownItem.GetValue()); + ItemSelectedEvent?.Invoke(property, dropdownItem.Mode, dropdownItem.GetValue()); } } } diff --git a/Editor/Utilities/SerializedPropertyExtensions.cs b/Editor/Utilities/SerializedPropertyExtensions.cs new file mode 100644 index 0000000..7043e2e --- /dev/null +++ b/Editor/Utilities/SerializedPropertyExtensions.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +namespace TNRD.Utilities +{ + internal static class SerializedPropertyExtensions + { + public static SerializedProperty ReferenceModeProperty(this SerializedProperty property) + { + return property.FindPropertyRelative("mode"); + } + + public static SerializedProperty RawReferenceProperty(this SerializedProperty property) + { + return property.FindPropertyRelative("rawReference"); + } + + public static SerializedProperty UnityReferenceProperty(this SerializedProperty property) + { + return property.FindPropertyRelative("unityReference"); + } + } +} diff --git a/Editor/Utilities/SerializedPropertyExtensions.cs.meta b/Editor/Utilities/SerializedPropertyExtensions.cs.meta new file mode 100644 index 0000000..f9fcc92 --- /dev/null +++ b/Editor/Utilities/SerializedPropertyExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8bfd876a31f9470b802c64d4f1a8dd37 +timeCreated: 1658567318 \ No newline at end of file diff --git a/package.json b/package.json index c6c90e6..2f8703a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "net.tnrd.serializableinterface", - "version": "1.9.0", + "version": "1.10.0", "displayName": "Serializable Interface", "unity": "2020.1", "description": "A wrapper that allows serialization of interfaces that supports both UnityEngine.Object and regular object types",