in a custom inspector I’m adding new items to an array when a button is pressed:
if (GUILayout.Button("Add"))
{
// T derives from ScriptableObject
var newItem = CreateInstance<T>();
newItem.hideFlags = HideFlags.HideInHierarchy;
AssetDatabase.AddObjectToAsset(newItem, target);
AssetDatabase.SaveAssets();
// itemsProperty is of type T[] (an array of T)
++itemsProperty.arraySize;
itemsProperty.GetArrayElementAtIndex(itemsProperty.arraySize - 1).objectReferenceValue = newItem;
}
It works fine but I can’t get the undo system to function properly. I tried various solutions involving the Undo class but I had no luck so far.
Any help is much appreciated.
Thank you very much.
Edit:
To make it clear, I’d like to have a single undo operation to:
1 - Revert add object to asset
2 - Revert array size increment
Edit 2:
To be even more clear, the problem is that the array size change is undone but the child asset remains (as far as I can tell…)
You can do this by using a combination of SerializedObject/Property (which you’re already using I think) along with the [Undo.RegisterCreatedObjectUndo](https://docs.unity3d.com/ScriptReference/Undo.RegisterCreatedObjectUndo.html) method.
// T derives from ScriptableObject
var newItem = CreateInstance<T>();
//newItem.hideFlags = HideFlags.HideInHierarchy;
newItem.hideFlags = HideFlags.None; // Using None so we can see the object being removed on Undo. Use HideInHierarchy when you're done testing.
// Register the created object with the undo system.
Undo.RegisterCreatedObjectUndo(newItem, "<Your Undo text here>")
AssetDatabase.AddObjectToAsset(newItem, target);
// Update the serialized property array.
serializedProperty.arraySize = serializedProperty.arraySize + 1;
var arrayElement = serializedProperty.GetArrayElementAtIndex(serializedProperty.arraySize - 1);
nodeArrayElement.objectReferenceValue = newItem;
// Apply the changes. Automatically adds to the current undo group, causing the array change to be grouped with the object creation change.
serializedObject.ApplyModifiedProperties();
Don’t forget, you’ll need to save the project to see the Scriptable Object update in the project window. Alternatively, you can call AssetDatabase.SaveAssets() from your script if you want to force a save.
@Pelican_7 Thanks! This approach works for me, but there is some weirdness going on with the project window during undo/redo. I have a Graph ScriptableObject that has a list of Nodes. When I add a Node to the graph, the Graph is properly updated as well as the project view.
However, if I undo or redo a change, the project view doesn’t update until I save the whole project. (Though it seems that the Graph is properly updated). I’m not exactly sure why this is happening:
[CreateAssetMenu(menuName = "SO/Overworld/Graph")]
public class OverworldGraph : ScriptableObject
{
[SerializeField]
private List<OverworldNode> overworldNodes;
#if UNITY_EDITOR
public void AddNode()
{
Undo.RecordObject(this, "added node to graph");
var node = CreateInstance<OverworldNode>();
node.hideFlags = HideFlags.None;
AssetDatabase.AddObjectToAsset(node, this);
overworldNodes.Add(node);
Undo.RegisterCreatedObjectUndo(node, "Node added");
AssetDatabase.SaveAssets();
}
#endif
}