Search Unity

Question Discard unsaved changes done to ScriptableObject (in Editor)

Discussion in 'Editor & General Support' started by OndrejP, Aug 29, 2021.

  1. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    It happens that I need sometimes to discard changes done to certain scriptable objects, prefabs and possibly other assets in editor. There are couple ways, but optimal way is not available.

    Option 1: Just use Instantiate
    Not possible when scriptable object is being referenced by other prefabs or scriptable objects.

    Option 2: Resources.UnloadAsset
    Kinda works, but causes missing managed references. When object is references by other prefabs or scriptable objects, calling UnloadAsset causes these references to be null.
    There's workaround for that, but it costs a lot, about 10s for my project.
    It's EditorUtility.RequestScriptReload, this fixes the references.

    Option 3: Changing and reimporting the asset
    Calling AssetDatabase.ImportAsset(ForceUpdate) does not help, what's necessary is to actually change asset.
    E.g. adding empty space at the end of text '.asset' file works, but it's inconvenient and I'm not sure what to do for binary assets. (changing last write time does not help). This is faster than option 2, but way more dangerous and inconvenient.

    Optimal solution: AssetDatabase.ReloadAsset(Object) or EditorUtility.DiscardChanges(Object)
    Unity, please add one of the following methods ^^
    It would be a great help. I know the functionality is here, just hidden in unmanaged code.
    Option 3 does exactly what's needed, now I'd like to actually do it without modifying the asset.

    Am I missing something? Is there some hidden way to achieve this?
     
    Last edited: Aug 29, 2021
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    Optimal way is ALWAYS available when you use source control.

    Please consider using proper industrial-grade source control in order to guard and protect your hard-earned work.

    Personally I use git (completely outside of Unity) because it is free and there are tons of tutorials out there to help you set it up as well as free places to host your repo (BitBucket, Github, Gitlab, etc.).

    As far as configuring Unity to play nice with git, keep this in mind:

    https://forum.unity.com/threads/prefab-links-keep-getting-dumped-on-git-pull.646600/#post-7142306

    Here's how I use git in one of my games, Jetpack Kurt:

    https://forum.unity.com/threads/2-steps-backwards.965048/#post-6282497

    Using fine-grained source control as you work to refine your engineering:

    https://forum.unity.com/threads/whe...grammer-example-in-text.1048739/#post-6783740

    Share/Sharing source code between projects:

    https://forum.unity.com/threads/your-techniques-to-share-code-between-projects.575959/#post-3835837

    Setting up an appropriate .gitignore file for Unity3D:

    https://forum.unity.com/threads/removing-il2cpp_cache-from-project.1084607/#post-6997067

    Generally setting Unity up (includes above .gitignore concepts):

    https://thoughtbot.com/blog/how-to-git-with-unity

    It is only simple economics that you must expend as much effort into backing it up as you feel the work is worth in the first place.

    "Use source control or you will be really sad sooner or later." - StarManta on the Unity3D forum boards
     
    OZAV likes this.
  3. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    We use Git with LFS hosted on Bitbucket.

    But VCS won't be very useful here. I'd have to manually (or by script) discard file changes every time I'd like to discard modified unsaved asset. I'd also have to save the modified asset first to be able to discard the changes.
    What if I already have some saved changes to that asset I'd like to keep? That would force me to commit or at least stage the changes first.

    When the asset is saved, it's too late for me.

    I appreciate the help, but this seems more complicated than other options. It's the VCS that tells me in the first place that there's some modified asset, which shouldn't be modified. I understand it's best practice NOT to modify ScriptableObject during PlayMode, but unfortunately that's not the world I live in. I'm able to prevent that on projects I own, but on other project I can't control that.

    The proposed solution would allow me to automatically discard unsaved changes on ScriptableObjects when Exiting from play mode...
     
  4. koirat

    koirat

    Joined:
    Jul 7, 2012
    Posts:
    2,073
    @OndrejP I know that this is not built in solution as you would expect but you may try this:
    Duplicate your scriptable object, and make the duplicate a template.

    Create editor for scriptable object and add button "reset" and a field for template SO.
    When "reset" is pressed perform memberwise copy from template to current, you can do it manually or using the reflection.
     
    uurha, OndrejP and Kurt-Dekker like this.
  5. Grhyll

    Grhyll

    Joined:
    Oct 15, 2012
    Posts:
    119
    Just for future people stumbling on this post while looking for something similar, I've had success with:

    List<string> path = new List<string>();
    path.Add(AssetDatabase.GetAssetPath(myAsset));
    AssetDatabase.ForceReserializeAssets(path);
    AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(myAsset), ImportAssetOptions.ForceUpdate);
    AssetDatabase.Refresh();

    (Not sure everything is needed there.)
     
    HIMMELMAX, uurha and OndrejP like this.
  6. uurha

    uurha

    Joined:
    Nov 15, 2020
    Posts:
    21

    Next time read the question, and do not suggest useless information. Your posts are misleading and just spam.
     
    HIMMELMAX likes this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    You may wish to reconsider publicly posting about things you apparently know nothing about.

    OP posted this:

    The one and the only way that every person at my company ever "discards changes done to certain scriptable objects, prefabs and possibly other assets" is using source control and selecting revert.

    But hey, if you find a better way, we are all still waiting for you to post about it.

    First hit in Google:

    Screen Shot 2023-02-13 at 2.34.06 PM.png
     
  8. Grhyll

    Grhyll

    Joined:
    Oct 15, 2012
    Posts:
    119
    The title of the thread isn't clear, but your answer doesn't address the real problem raised here (although it does solve the most direct interpretation of the thread's title).
    The goal here is to revert unsaved changes made to an asset, so when the asset is dirty (instantiated asset is different from on-disk serialized asset). Version control can only access to on-disk serialized asset. Additionally, the solution should be able to revert to last saved asset, and not last committed asset. So if you have asset version A on your source control, change it in Unity, save it to version B, then change it again, you want to be able to revert it to version B (discard non-saved changes), and source control can't do that because it doesn't even know you're not in version B anymore (unless you save this version C, but then source control doesn't have any record of version B, only current version C and last committed version A).
     
    uurha likes this.
  9. OndrejP

    OndrejP

    Joined:
    Jul 19, 2017
    Posts:
    304
    Title updated :)
     
    Grhyll and uurha like this.
  10. uurha

    uurha

    Joined:
    Nov 15, 2020
    Posts:
    21
    You totally misunderstanding question. The question not about source control at all. Do you genuinely believe that all programs uses git or other source control to store temporary data before user stores data to disk?

    Stop "tag searching" and replying with first answer in google (even if your google search request not fits the question description).

    So If you were read the question you should think about such "a better way"s:
    1. Instead writing data directly into SO, you can create class with needed data and user decides to "Save" changes set new class reference into the file.
    2. Use undo/redo Editor functions (kinda weird way, but still better than manipulate with local repo from Editor scripts)
    3. Create temporary "memory-stored" SO instance and write changes into this instance rather then writing them into SO stored in project.

    @OndrejP above some other possible ways fulfill your question (except p.3)

    Yes, sure just right after you will apply this to you, and next time read everything except post title before start searching for "obvious solution", thanks.
     
    Last edited: Feb 15, 2023
    OndrejP likes this.
  11. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,924
    I feel like this situation is a good use case for EditorJsonUtility: https://docs.unity3d.com/ScriptReference/EditorJsonUtility.html

    Get the serialised copy of the object, store it however you want, and write it back over the scriptable object when you're done.

    Just note this only works with values that Unity can serialise.
     
    OndrejP and uurha like this.
  12. OneManEscapePlan

    OneManEscapePlan

    Joined:
    Oct 14, 2015
    Posts:
    222
    Maybe you've misunderstood the use case here.

    Let's say that you've made some changes to a ScriptableObject asset in the Editor, and want to discard them. With Git, you have to do this:

    1. In Unity, File > Save Project to write the changes that you don't even want to disk
    2. Switch to Git client/command line
    3. Find the file that you want to revert and discard changes to it
    4. Switch back to Unity

    Sure, it works, but it's a bit of extra hassle.

    Many applications let you revert the changes to a document, or simply close the document without saving. The Unity Editor even lets us to this with scenes. However, there's no built-in UI or API to do the same with ScriptableObjects.

    It would be nice if there were an Editor API function that simply reloads a dirty asset from the disk, discarding any changes we've made in the Editor since the asset was last saved. This would make it more practical to add a "Revert" button to our ScriptableObject editors without having to resort to hacks like adding a space to the end of the asset file to get the Editor to reload it from disk.
     
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,735
    No, not quite. I wanted to have the use case you mention: a handy revert button.

    My goodness, wouldn't that be an awesome feature? We sorta have it with prefabs... sorta.

    However after 12 years using Unity that feature has not arrived.

    Therefore about 11.9 years ago I decided to address the issue using source control.

    Your move.
     
  14. OneManEscapePlan

    OneManEscapePlan

    Joined:
    Oct 14, 2015
    Posts:
    222
    I'm not even sure what point you're trying to make any more. Are you saying that you agree with the OP that Unity should add an API for discarding unsaved changes to an asset? Or are you saying that Unity should not add such a feature because the only acceptable way to revert changes is with source control?