diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc5f783..c90300f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,11 @@ All package updates & migration steps will be listed in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [4.2.1] - 2024-11-19
+### Fixed
+- Issue where nested structs in scriptable object drawers have glitching UI.
+- Disable autosaving toggle wasn't fully disabling.
+
## [4.2.0] - 2024-10-31
### Added
- Additional checks during parameter generation to ensure the generated code matches.
diff --git a/Editor/Editor/InspectorAutoSave.cs b/Editor/Editor/InspectorAutoSave.cs
index 26f3820..495f13f 100644
--- a/Editor/Editor/InspectorAutoSave.cs
+++ b/Editor/Editor/InspectorAutoSave.cs
@@ -66,10 +66,10 @@ private static void Update()
if (s_target != null)
{
- if (s_dirtyStopWatch.IsRunning && s_dirtyStopWatch.ElapsedMilliseconds < SaveDelayMillis)
- return;
-
- SaveAsset();
+ if (s_dirtyStopWatch.IsRunning && s_dirtyStopWatch.ElapsedMilliseconds >= SaveDelayMillis)
+ {
+ SaveAsset();
+ }
}
}
diff --git a/Editor/Editor/ParamProperty.cs b/Editor/Editor/ParamProperty.cs
index 6885963..823cd9d 100644
--- a/Editor/Editor/ParamProperty.cs
+++ b/Editor/Editor/ParamProperty.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
@@ -48,6 +49,8 @@ public ScriptableObject ScriptableObject
}
}
+ public SerializedObject SerializedScriptableObject => _serializedScriptableObject;
+
///
/// Current position if the property is part of a list or array. Null otherwise.
///
@@ -60,6 +63,20 @@ public ScriptableObject ScriptableObject
private readonly SerializedProperty _guidProperty;
+ /*
+ * Unity recommended we cache our SerializedObject to avoid GUI glitches.
+ *
+ * Unity's response:
+ * Regarding the issue of Serializable fields becoming unselectable originates from your custom
+ * property drawer. Our investigation revealed that parts of IMGUI, including the ReorderableList,
+ * are stateful. This means they retain data about the SerializedObject and SerializedProperties.
+ * In your property drawer, you are generating a new SerializedObject each time and disposing of it
+ * immediately. This process invalidates the state, causing multiple drawings of the list and
+ * disrupting input states.
+ */
+ private readonly SerializedObject _serializedScriptableObject;
+ private static Dictionary s_serializedScriptableObjectByGuid = new ();
+
public ParamProperty(FieldInfo fieldInfo, SerializedProperty property)
{
Property = property;
@@ -86,14 +103,29 @@ public ParamProperty(FieldInfo fieldInfo, SerializedProperty property)
if (!string.IsNullOrWhiteSpace(GUID))
{
- if (ScriptableObject == null)
+ var scriptableObject = ScriptableObject;
+ if (scriptableObject == null)
{
Error = $"Missing asset {GUID}";
}
- else if (!InterfaceType.IsInstanceOfType(ScriptableObject))
+ else if (!InterfaceType.IsInstanceOfType(scriptableObject))
{
Error = $"Asset no longer matches generic type {InterfaceType}";
}
+ else
+ {
+ if (!s_serializedScriptableObjectByGuid.TryGetValue(GUID, out var serializedScriptableObject))
+ {
+ serializedScriptableObject = new SerializedObject(scriptableObject);
+ s_serializedScriptableObjectByGuid[GUID] = serializedScriptableObject;
+ }
+ else
+ {
+ // call to ensure the values are up to date with the target in case it was modified in another inspector/drawer
+ serializedScriptableObject.Update();
+ }
+ _serializedScriptableObject = serializedScriptableObject;
+ }
}
}
}
diff --git a/Editor/Editor/ParameterReferenceDrawer.cs b/Editor/Editor/ParameterReferenceDrawer.cs
index a9c7d39..37255c9 100644
--- a/Editor/Editor/ParameterReferenceDrawer.cs
+++ b/Editor/Editor/ParameterReferenceDrawer.cs
@@ -146,7 +146,7 @@ private float InnerInspectorHeight(ParamProperty paramProperty, SerializedProper
return 0;
float height = 0;
- var serializedObject = new SerializedObject(paramProperty.ScriptableObject);
+ var serializedObject = paramProperty.SerializedScriptableObject;
var prop = serializedObject.GetIterator();
bool children = true;
while (prop.NextVisible(children))
@@ -160,7 +160,6 @@ private float InnerInspectorHeight(ParamProperty paramProperty, SerializedProper
height += EditorGUI.GetPropertyHeight(prop, new GUIContent(prop.displayName), true);
height += EditorGUIUtility.standardVerticalSpacing;
}
- serializedObject.Dispose();
return height;
}
@@ -206,7 +205,6 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
objectFieldPosition.y, newButtonWidth, objectFieldPosition.height);
objectFieldPosition.width -= newButtonWidth;
EditorGUI.BeginChangeCheck();
- bool objectChanged = false;
newObject = null;
// object field
var scriptableObject = paramProperty.ScriptableObject;
@@ -214,10 +212,11 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
if (EditorGUI.EndChangeCheck())
{
// this means the user interacted and set the value on the field
- // this helps determine if the user deliberately an object or nulled the field.
- objectChanged = true;
+ // this helps determine if the user deliberately set an object or nulled the field.
newObject = fieldObject as ParameterScriptableObject;
- scriptableObject = newObject;
+
+ // return early so that the ParamProperty can be updated with the correct scriptable object
+ return true;
}
if (GUI.Button(buttonRect, "New"))
@@ -250,9 +249,10 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
{
var createdObject = ScriptableObject.CreateInstance(parameterInterface.ScriptableObjectType());
AssetDatabase.CreateAsset(createdObject, savePath);
- objectChanged = true;
- scriptableObject = createdObject;
newObject = createdObject as ParameterScriptableObject;
+
+ // return early so that the ParamProperty can be updated with the correct scriptable object
+ return true;
}
}
@@ -281,8 +281,7 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
}
else if (canExpandDrawer && property.isExpanded)
{
- var serializedObject = new SerializedObject(scriptableObject);
- var prop = serializedObject.GetIterator();
+ var prop = paramProperty.SerializedScriptableObject.GetIterator();
EditorGUI.indentLevel++;
bool children = true;
while (prop.NextVisible(children))
@@ -307,7 +306,7 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
{
height = EditorGUI.GetPropertyHeight(prop, propLabel, true);
position.height = height;
- DrawExpandedField(serializedObject, position, prop, propLabel);
+ DrawExpandedField(paramProperty.SerializedScriptableObject, position, prop, propLabel);
}
position.y += height + EditorGUIUtility.standardVerticalSpacing;
}
@@ -322,10 +321,9 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
*/
if (GUI.changed)
{
- serializedObject.ApplyModifiedProperties();
+ paramProperty.SerializedScriptableObject.ApplyModifiedProperties();
InspectorAutoSave.DispatchDelayedSave();
}
- serializedObject.Dispose();
}
if (paramProperty.ElementPosition.HasValue)
@@ -336,7 +334,7 @@ private bool DrawGUI(Rect position, SerializedProperty property, ParamProperty p
s_firstTargetObject = null;
}
- return objectChanged;
+ return false;
}
///
diff --git a/Editor/Editor/ParameterScriptableObjectInspector.cs b/Editor/Editor/ParameterScriptableObjectInspector.cs
index 0832243..f6182e6 100644
--- a/Editor/Editor/ParameterScriptableObjectInspector.cs
+++ b/Editor/Editor/ParameterScriptableObjectInspector.cs
@@ -148,7 +148,9 @@ public override void OnInspectorGUI()
}
// collect properties & errors
- List<(SerializedProperty, string)> properties = new List<(SerializedProperty, string)>();
+ List<(SerializedProperty, string)> properties = new();
+ // call to ensure the values are up to date with the target in case it was modified in another inspector/drawer
+ serializedObject.Update();
var serializedProp = serializedObject.GetIterator();
bool children = true;
while (serializedProp.NextVisible(children))
diff --git a/package.json b/package.json
index c631b60..26c3ca8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "com.pocketgems.scriptableobject.flatbuffer",
- "version": "4.2.0",
+ "version": "4.2.1",
"displayName": "Scriptable Object - FlatBuffer",
"description": "Seamless syncing between Scriptable Objects and CSVs. Scriptable Object data built to Google FlatBuffers for optimal runtime loading & access.",
"unity": "2021.3",