Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Feature Request ScriptableObject Manipulations should also be published via ObjectChangeEvents

Discussion in 'Scripting' started by Nefahl, Apr 13, 2022.

  1. Nefahl

    Nefahl

    Joined:
    Feb 20, 2017
    Posts:
    71
    Hello, I was recently very confused about the missing Notifications on ScriptableObject derived Object Asset creation (and I assume also delete etc.) via the Callback:
    Code (CSharp):
    1. ObjectChangeEvents.changesPublished
    This seems to only work for GameObjects/Prefabs and all assets but ScriptableObjects, whereas the docs state that it should work on all types of assets:

    "Any undoable change to any object loaded in the editor (both GameObject and assets such as Material object) are recorded and exposed as a stream of events. See ObjectChangeKind for more information as to which types of changes are recorded."
    Excluding files that end on .asset from "assets such as [...]" is pretty counterintuitive, also this seems to be the only way to properly react to a UnityObject being duplicated, both via Ctrl+D and the Context-Menu (also copy/pasted). If you want to have some unique value on the object, or need to do some other work on duplicates to set them up properly (e.g. nested ScriptableObjects just broke on duplicate, at least last time I used them after seeing a unite-talk promoting this)

    Registering the following Method to the callback will print nothing when creating SO's

    Code (CSharp):
    1. private static void OnChangesPublished(ref ObjectChangeEventStream stream)
    2. {
    3.     for (int i = 0; i < stream.length; i++)
    4.     {
    5.         Debug.Log(stream.GetEventType(i));
    6.      }
    7. }
    ScriptableObjects should at least fire CreateAssetObject and DestroyAssetObject like Prefabs / GameObjects do (they also fire Create when being duplicated)

    Also I want to suggest to re-think the whole shortcut and context menu stuff. It would help immensly if you could react to modification events like duplicate / copy/paste somehow, either via such a generic event-stream like above, but maybe also in custom-inspectors, why not provide a Message / virtual Function for custom-editors where you could react to duplicate / [copy]'paste, and in case you have some field with unique identifier assign a new unique value there on the duplicated/pasted instance? The Forums / Answers-Section are full of people looking for such a feature, with tons of half-working workarounds, like checking
    Event.current.commandName == 'Duplicate'
    in OnValidate, which is potentially dangerous since you think it works (it does with Ctrl+D), but then you use the rightclick-context menu duplicate function and create duplicated "unique" values without the event being triggered.

    Tl;DR;
    - Please provide Events in the ObjectChangeStream for ScriptableObjects aswell.
    - Please consider implementing a solid editor event/notification system where editors (inspectorWindows, editorWindows via messages/virtual functions and customClasses registerd to callbacks) can react to modifications done via kind of generic editor functions like copy/paste, duplicate which you can't even disable for some custom types to prevent asset-corruption by using the "wrong" duplicate technique.
     
    Last edited: Apr 13, 2022
    bloodthirst69 likes this.
  2. bloodthirst69

    bloodthirst69

    Joined:
    Oct 1, 2017
    Posts:
    28
    i would like to add to this request that it would be much more helpful to add more infos in the EventArgs , like for example i was trying to track when components are added/removed to hook in some extra logic , well for the adding event there's already this
    Code (CSharp):
    1. ObjectFactory.componentWasAdded
    editor event that works well , but for removing component there no equivalent event , so ill have to go through the event
    Code (CSharp):
    1. ObjectChangeEvents.changesPublished
    The problem in my case is that the EventArgs don't give enough info for me , it doesn't say which component was deleted , so i can't really reason about how to deal with the event , sure it does give the instanceID that i can use to get the GameObject but after that i can't figure out what event happend to it.
     
  3. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    According to the C# Reference in Github, Unity has an attribute that can be added to ScriptableObject classes to prevent them from being copied/duplicated, but it's internal :(. Here's a quick dirty trick I use to prevent duplication of ScriptableObject subassets: Add a slash somewhere in their name. Unity can't handle naming assets with a "/" so, when duplicating, it will print an error and do nothing. It's ugly but also fast and simple.

    I'm not sure I understand what you want to detect for scriptable objects, so I'm not sure if I could help. Here are some other hooks I've used to detect changes related to ScriptableObjects, in case they help:
    - OnPostProcessAllAssets can be used to detect when assets are deleted, moved, renamed, created, or their changes have been saved.
    - AssetModificationProcessor can be used to stop an asset from being created, destroyed, their changes saved or moved. Supposedly, you shouldn't use the AssetDatabase API in those callbacks; I've used it to get info about the type of objects passed to the callback and it's been fine. You're still somewhat limited in what you can do there, though.
    - Undo.postProcessModifications is called when object properties are changed directly by the user. It tells you which properties changed, their previous value, their new value, and the object they belong to.
    - Undo.undoRedoPerformed is called on Undo and Redo. It doesn't tell you anything about what happened, but sometimes is the only hook available to detect those kinds of changes.
     
  4. iendsl

    iendsl

    Joined:
    Oct 17, 2013
    Posts:
    2
    I'm here to second the ScriptableObjects firing CreateAssetObject and DestroyAssetObject or at least add a note to the API that they won't