diff --git a/Assets/Editor Toolbox/CHANGELOG.md b/Assets/Editor Toolbox/CHANGELOG.md index 4acd11f0..3c3a118d 100644 --- a/Assets/Editor Toolbox/CHANGELOG.md +++ b/Assets/Editor Toolbox/CHANGELOG.md @@ -1,3 +1,11 @@ +## 0.11.4 [17.07.2022] + +### Added: +- ToolboxWizard, additional Toolbox-based equivalent for the ScriptableWizard class + +### Changed: +- Fix caching FieldInfo for [SerializeReference] properties + ## 0.11.3 [05.06.2022] ### Added: diff --git a/Assets/Editor Toolbox/Editor/AssemblyInfo.cs b/Assets/Editor Toolbox/Editor/AssemblyInfo.cs new file mode 100644 index 00000000..56531bf7 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Toolbox.Editor.Tests")] \ No newline at end of file diff --git a/Assets/Editor Toolbox/Editor/AssemblyInfo.cs.meta b/Assets/Editor Toolbox/Editor/AssemblyInfo.cs.meta new file mode 100644 index 00000000..21d8e90f --- /dev/null +++ b/Assets/Editor Toolbox/Editor/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9902dbb509706e44eada79a468fcaf93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Editor/ToolboxDrawerModule.cs b/Assets/Editor Toolbox/Editor/ToolboxDrawerModule.cs index 0004e68b..e705573a 100644 --- a/Assets/Editor Toolbox/Editor/ToolboxDrawerModule.cs +++ b/Assets/Editor Toolbox/Editor/ToolboxDrawerModule.cs @@ -19,20 +19,20 @@ internal static void InitializeModule() } - private readonly static Type decoratorDrawerBase = typeof(ToolboxDecoratorDrawer<>); - private readonly static Type conditionDrawerBase = typeof(ToolboxConditionDrawer<>); - private readonly static Type selfPropertyDrawerBase = typeof(ToolboxSelfPropertyDrawer<>); - private readonly static Type listPropertyDrawerBase = typeof(ToolboxListPropertyDrawer<>); + private static readonly Type decoratorDrawerBase = typeof(ToolboxDecoratorDrawer<>); + private static readonly Type conditionDrawerBase = typeof(ToolboxConditionDrawer<>); + private static readonly Type selfPropertyDrawerBase = typeof(ToolboxSelfPropertyDrawer<>); + private static readonly Type listPropertyDrawerBase = typeof(ToolboxListPropertyDrawer<>); - private readonly static Dictionary decoratorDrawers = new Dictionary(); - private readonly static Dictionary conditionDrawers = new Dictionary(); - private readonly static Dictionary selfPropertyDrawers = new Dictionary(); - private readonly static Dictionary listPropertyDrawers = new Dictionary(); + private static readonly Dictionary decoratorDrawers = new Dictionary(); + private static readonly Dictionary conditionDrawers = new Dictionary(); + private static readonly Dictionary selfPropertyDrawers = new Dictionary(); + private static readonly Dictionary listPropertyDrawers = new Dictionary(); /// /// Collection of specific drawers mapped to selected (picked) object types. /// - private readonly static Dictionary targetTypeDrawers = new Dictionary(); + private static readonly Dictionary targetTypeDrawers = new Dictionary(); /// /// Collection of currently cached handlers mapped to a unique property key. diff --git a/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs b/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs index e97b3f5c..1990c527 100644 --- a/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs +++ b/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs @@ -7,8 +7,6 @@ using UnityEditor; using Object = UnityEngine.Object; -[assembly: InternalsVisibleTo("Toolbox.Editor.Tests")] - namespace Toolbox.Editor { public static partial class PropertyUtility @@ -27,7 +25,9 @@ internal static bool HasModifedProperties(this SerializedProperty property) internal static string GetPropertyHashKey(this SerializedProperty property) { var hash = property.serializedObject.GetHashCode(); - return string.Format("{0}.{1}", hash, property.propertyPath); + return property.propertyType != SerializedPropertyType.ManagedReference + ? $"{hash}.{property.propertyPath}" + : $"{hash}.{property.propertyPath}.{property.managedReferenceFieldTypename}"; } /// @@ -36,7 +36,9 @@ internal static string GetPropertyHashKey(this SerializedProperty property) internal static string GetPropertyTypeKey(this SerializedProperty property) { var type = property.serializedObject.targetObject.GetType(); - return string.Format("{0}.{1}", type, property.propertyPath); + return property.propertyType != SerializedPropertyType.ManagedReference + ? $"{type}.{property.propertyPath}" + : $"{type}.{property.propertyPath}.{property.managedReferenceFieldTypename}"; } /// @@ -253,7 +255,7 @@ internal static FieldInfo GetFieldInfo(this SerializedProperty property, out Typ internal static FieldInfo GetFieldInfo(this SerializedProperty property, out Type propertyType, Object target) { - return GetFieldInfoFromProperty(target.GetType(), property.propertyPath, out propertyType); + return GetFieldInfoFromProperty(property, out propertyType, target.GetType()); } public static FieldInfo GetFieldInfoFromProperty(SerializedProperty property, out Type type) @@ -265,14 +267,15 @@ public static FieldInfo GetFieldInfoFromProperty(SerializedProperty property, ou return null; } - return GetFieldInfoFromProperty(classType, property.propertyPath, out type); + return GetFieldInfoFromProperty(property, out type, classType); } - public static FieldInfo GetFieldInfoFromProperty(Type host, string fieldPath, out Type type) + public static FieldInfo GetFieldInfoFromProperty(SerializedProperty property, out Type type, Type host) { FieldInfo field = null; type = host; + var fieldPath = property.propertyPath; var members = GetPropertyFieldTree(fieldPath, false); for (var i = 0; i < members.Length; i++) { @@ -287,10 +290,21 @@ public static FieldInfo GetFieldInfoFromProperty(Type host, string fieldPath, ou continue; } + const BindingFlags fieldFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo foundField = null; for (var currentType = type; foundField == null && currentType != null; currentType = currentType.BaseType) { - foundField = currentType.GetField(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foundField = currentType.GetField(member, fieldFlags); + //NOTE: [SerializeReference] detected? If so we need to check dynamically cached type + if (foundField == null) + { + var parent = property.GetParent(); + if (parent != null && parent.propertyType == SerializedPropertyType.ManagedReference) + { + TypeUtilities.TryGetTypeFromManagedReferenceFullTypeName(parent.managedReferenceFullTypename, out var parentType); + foundField = parentType.GetField(member, fieldFlags); + } + } } if (foundField == null) diff --git a/Assets/Editor Toolbox/Editor/Windows.meta b/Assets/Editor Toolbox/Editor/Windows.meta new file mode 100644 index 00000000..7f5c68f1 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/Windows.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 33420690c5af85841905024abd93f883 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs b/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs new file mode 100644 index 00000000..919f26f2 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs @@ -0,0 +1,93 @@ +using UnityEditor; +using UnityEngine; + +namespace Toolbox.Editor.Wizards +{ + using Editor = UnityEditor.Editor; + + public class ToolboxWizard : EditorWindow + { + private Editor targetEditor; + + private Vector2 scrollPosition; + + private void OnDestroy() + { + DestroyImmediate(targetEditor); + } + + private void OnGUI() + { + using (var scrollView = new EditorGUILayout.ScrollViewScope(scrollPosition)) + { + scrollPosition = scrollView.scrollPosition; + EditorGUI.BeginChangeCheck(); + OnWizardGui(); + if (EditorGUI.EndChangeCheck()) + { + OnWizardUpdate(); + } + } + + using (new EditorGUILayout.VerticalScope()) + { + GUILayout.FlexibleSpace(); + using (new EditorGUILayout.HorizontalScope()) + { + GUILayout.FlexibleSpace(); + HandleOtherButtons(); + GUI.enabled = IsValid; + if (HandleCreateButton()) + { + OnWizardCreate(); + Close(); + GUIUtility.ExitGUI(); + } + + GUI.enabled = true; + } + + GUILayout.Space(5); + } + } + + private void PrepareEditor() + { + if (targetEditor != null) + { + return; + } + + targetEditor = Editor.CreateEditor(this); + targetEditor.hideFlags = HideFlags.HideAndDontSave; + OnWizardUpdate(); + } + + protected virtual void OnWizardCreate() + { } + + protected virtual void OnWizardUpdate() + { } + + protected virtual void OnWizardGui() + { + PrepareEditor(); + targetEditor.OnInspectorGUI(); + } + + protected virtual bool HandleCreateButton() + { + return GUILayout.Button("Create", GUILayout.MinWidth(100)); + } + + protected virtual void HandleOtherButtons() + { } + + public static T DisplayWizard(string title) where T : ToolboxWizard + { + return GetWindow(true, title); + } + + protected bool IsValid { get; set; } = true; + } +} \ No newline at end of file diff --git a/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs.meta b/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs.meta new file mode 100644 index 00000000..adc6ff1c --- /dev/null +++ b/Assets/Editor Toolbox/Editor/Windows/ToolboxWizard.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa851672284a43845b3540068666d072 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/package.json b/Assets/Editor Toolbox/package.json index 88785180..b12d1941 100644 --- a/Assets/Editor Toolbox/package.json +++ b/Assets/Editor Toolbox/package.json @@ -1,7 +1,7 @@ { "name": "com.arimger.editor-toolbox", "displayName": "Editor Toolbox", - "version": "0.11.3", + "version": "0.11.4", "unity": "2018.1", "description": "Tools, custom attributes, drawers, hierarchy overlay, and other extensions for the Unity Editor.", "keywords": [ diff --git a/Assets/Examples/Editor/SampleWizard.cs b/Assets/Examples/Editor/SampleWizard.cs new file mode 100644 index 00000000..68833a0b --- /dev/null +++ b/Assets/Examples/Editor/SampleWizard.cs @@ -0,0 +1,55 @@ +using Toolbox.Editor.Wizards; + +using UnityEditor; +using UnityEngine; + +public class SampleWizard : ToolboxWizard +{ + [SerializeField, InLineEditor] + private GameObject prefab; + [SerializeField] + private string targetName; + + private bool hasInvalidName; + + [MenuItem("GameObject/Sample Wizard")] + public static void CreateWizard() + { + DisplayWizard("Create GameObject"); + } + + protected override void OnWizardCreate() + { + GameObject go; + if (prefab != null) + { + go = Instantiate(prefab); + go.name = targetName; + } + else + { + go = new GameObject(targetName); + } + + Selection.activeObject = go; + } + + protected override void OnWizardUpdate() + { + hasInvalidName = string.IsNullOrEmpty(targetName); + } + + protected override void OnWizardGui() + { + base.OnWizardGui(); + if (hasInvalidName) + { + EditorGUILayout.HelpBox("Name is invalid", MessageType.Error, true); + } + } + + protected override void HandleOtherButtons() + { + //you can draw more buttons here + } +} \ No newline at end of file diff --git a/Assets/Examples/Editor/SampleWizard.cs.meta b/Assets/Examples/Editor/SampleWizard.cs.meta new file mode 100644 index 00000000..a0467c2d --- /dev/null +++ b/Assets/Examples/Editor/SampleWizard.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1bb32b688a40424bb4818611e483779 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Examples/Scenes/SampleScene.unity b/Assets/Examples/Scenes/SampleScene.unity index 590d0085..e500f594 100644 --- a/Assets/Examples/Scenes/SampleScene.unity +++ b/Assets/Examples/Scenes/SampleScene.unity @@ -584,14 +584,21 @@ MonoBehaviour: references: version: 1 00000000: - type: {class: SampleBehaviour6/Struct, ns: , asm: Assembly-CSharp} + type: {class: SampleBehaviour6/ClassWithInterface1, ns: , asm: Assembly-CSharp} data: - var1: 1 - var2: 1 + go: {fileID: 977748987} + var1: + id: 2 00000001: type: {class: SampleBehaviour6/ClassWithInterface2, ns: , asm: Assembly-CSharp} data: var1: 0 + mat: {fileID: 2100000, guid: 7404c70251f9d0045a4aabaa49d83963, type: 2} + 00000002: + type: {class: SampleBehaviour6/Struct, ns: , asm: Assembly-CSharp} + data: + var1: 1 + var2: 0 --- !u!4 &752799893 Transform: m_ObjectHideFlags: 2 diff --git a/Assets/Examples/Scripts/SampleBehaviour6.cs b/Assets/Examples/Scripts/SampleBehaviour6.cs index 5b8ac3bf..e829e1dc 100644 --- a/Assets/Examples/Scripts/SampleBehaviour6.cs +++ b/Assets/Examples/Scripts/SampleBehaviour6.cs @@ -27,7 +27,10 @@ public abstract class ClassWithInterfaceBase : Interface1 { } [Serializable] public class ClassWithInterface1 : ClassWithInterfaceBase { + [InLineEditor] public GameObject go; + [SerializeReference, ReferencePicker] + public Interface1 var1; } [Serializable] @@ -35,6 +38,8 @@ public class ClassWithInterface2 : ClassWithInterfaceBase { [LeftToggle] public bool var1; + [InLineEditor] + public Material mat; } [Serializable]