Destroying ScriptableObjects in scene

So I have a scene object which references some ScriptableObjects, these ScriptableObjects cannot be saved assets, they need to reference other scene objects. And they need to be ScriptableObjects so I can use PropertyField GUI’s

Deleting the scene object will cause nested ScriptableObjects to leak. This can be solved by creating a custom editor for your scene object and listening to the OnDestroy method, going over fields using Reflection and Destroying the nested ScriptableObjects. This works ok, but Undoing this delete ooperation does not restore the ScriptableObjects that were destroyed through Reflection, sigh.

Is there anyway to Record a delete on a ScriptableObject and upon undoing this, restore its reference in the scene object?

I’ve literally changed my entire object handling code at least 15 times in the last 2 weeks because of this ScriptableObject nonsense, getting pretty tired of it.

ok, found this: Undo.DestroyObjectImmediate

but, when redoing, unity crashes :frowning:

ok, so the crash was related to OnDestroy being called when calling a redo! doesn’t make any sense to me, but whatever.

solution is to listen to UndoRedo and either enable/disable using Undo.DestroyObjectImmediate:

public class MyEditor : UnityEditor.Editor {
   
    private bool canDestroy;

    void OnEnable() {

        canDestroy = true;

        Undo.undoRedoPerformed -= OnUndoRedoPerformed;
        Undo.undoRedoPerformed += OnUndoRedoPerformed;
    }

    private void OnUndoRedoPerformed() {

        canDestroy = false;
    }

    void OnDestroy() {
   
        Undo.undoRedoPerformed -= OnUndoRedoPerformed;           

        if (Application.isEditor && target == null) {       

            //destroy

            if (canDestroy) {

                //perform nested destroy code here using Undo.DestroyObjectImmediate()
                canDestroy = false;
            }
        }
    }
}

why must ScriptableObjects be so difficult to work with? Can’t we have a different type, like a ScriptableObjectInstance?

When you destroy the game object, you could try something similar to this:

// Register an undo operation on the game object that contains the scriptable object
Undo.RecordObjects( holder, "Removed");

// Register undo actions on each scriptable object and remove them one at a time
while(target.ScriptableObjects.Count > 0)
{
    // Register undo
    var scriptableObject = target.ScriptableObjects[0];
    Undo.RecordObjects( scriptableObject, "Removed");
  
    // Remove from game object
    holder.ScriptableObjects.Remove(itemToRemove);
  
    // Destroy but register undo
    Undo.DestroyObjectImmediate(itemToRemove);
}

// Collapse all undo actions
Undo.RecordObjects( holder, "Removed");
Undo.CollapseUndoOperations(Undo.GetCurrentGroup());