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

ScriptableObjects are not updating when changed on the filesystem via git

Discussion in 'Scripting' started by MattRix, Feb 23, 2020.

  1. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    When I update my Unity git repository with another user's changes, everything updates fine except for ScriptableObjects, despite them changing on disk. I can check the .asset file and see all the correct values in the YAML. No matter what I do in Unity, whether Refresh or Reimport, or even specifically calling ImportAsset with ForceUpdate, they are still incorrect in Unity itself. The only way to get them to update is to close Unity and reopen it.
     
    ManuelKers and Xarbrough like this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    Unity is an AWESOME game engine, but for nearly a decade they have been INFURIATINGLY bad about calling
    fflush()
    to write changed asset data to disk. This maddeningly sophmoric programming problem persists today, even with the latest and greatest version of Unity. It baffles me why they haven't simply addressed it and forced assets to commit to disk whenever they are changed. It's not like that would even take a measureable amount of editor CPU time to do on a modern system!

    For us chickens trying to live with it, and I encounter this problem EVERY SINGLE DAY, the solution is fortunately even easier than closing and starting Unity: just do a File -> Save Project. That will commit all files to disk, and when git changes stuff, it will get updated, at least once you deselect and reselect the object in question and give the editor inspector window a chance to update.

    Also, props for using git because everybody should be using source control all the time.
     
    Propagant, Docboy, Zyblade and 10 others like this.
  3. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    Ah, that's a similar but unrelated problem. We're missing changes on assets that have not been modified/edited in the local Unity Editor instance at all. Doing Save Project doesn't help us in this case. The assets have changed on the filesystem (due to git), yet the changes still aren't showing up in the editor no matter what we do (even though the .asset's YAML data is correct).
     
  4. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    After more investigation, I figured out the exact cause of this issue: if you add a new field to a ScriptableObject's .cs file (ex. public int someVar = 25) and on the same git commit, also change the value of that property in the inspector (ex. setting someVar to 99), and then commit that... it breaks when another user loads that change.

    So in this specific example, the default value of 25 clobbers the value of 99 that you set in the inspector. In the .asset file on disk, the YAML has someVar: 99, but in Unity itself, you will see 25 instead.

    This is a huge problem, because now if the user in Unity goes and changes someOtherVar in the ScriptableObject, the 99 value on disk will now get clobbered with the value of 25 as well.


    This is not actually a problem unique to git, the same thing will happen if you copy in both a .cs and .asset file on the file system before switching focus back to Unity. In other words, any time a new property is added at the same time as changing that property in Unity, the change from Unity will not register.

    I don't know if this is specific to my current version of Unity (2019.1.14f1), but it's a very bad bug, because it leads to all kinds of data being overwritten/lost by accident.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    You should endeavor to stay away from this construct in Unity because it leads to misunderstandings, both to you and other team members.

    Instead, you should just declare the variable blank:

    Code (csharp):
    1. public int someVar;
    and then provide a Reset() function:

    Code (csharp):
    1. void Reset()
    2. {
    3.   someVar = 25;
    4. }
    I know it doesn't catch all cases, and for later-added fields it requires you to actively hit the Reset menu option in the Monobehavior inspector, but the advantage is that it does not mis-communicate what initialization might happen.

    Additionally, you can supply default fields if you select the script in the inspector (not an instance of the script, the actual .cs file!), and look in the inspector. This will let you prepopulate with default values whenever one of these come into being. Those values are stored in the .meta file.

    And everything I noted about fflush() above is still valid, so you still gotta save-project before committing.
     
  6. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    Ok a bunch of things to say here: first, manually specified default values have nothing to do with this issue! Even if you don't specify a default value, the default for that type (ex. zero for ints) will still clobber the value anyway.

    Secondly, I strongly disagree with the idea that default values are bad. They are there for a reason, to provide sensible defaults. For MANY objects in my projects, the defaults are never modified. If I have a value where it must be modified, that is the only time I may leave it blank. But even when you leave it blank, that is not actually "no value", it is still zero.

    Thirdly, Reset is not a solution for this whatsoever. The moment you add more fields to a class, using Reset no longer makes sense, because you are going to clobber the user's values they've already specified.

    And also, Reset is an even worse solution for ScriptableObjects because *it doesn't work properly on them*. Specifically, Reset wipes out the .name property of the ScriptableObject to a blank string! If you don't believe me, try it out yourself. This bug has been in Unity since the dawn of ScriptableObjects. The only way to get the name back is to rename the file, it's really silly.

    Specifying default values in the script itself is a decent solution, but seems largely unnecessary. To be honest I've never had issues with default field values causing confusion.
     
  7. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    I just made a GitHub project demonstrating this bug, if anyone else wants to try it out and see if it happens in their version of Unity as well: https://github.com/MattRix/SOFail
     
  8. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    Not an issue I've ever run into, and we use a lot of SO's, and merge them several times of day.

    What OS and Unity version are you on?
     
  9. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    2019.1.14f1 in Windows - try my demo project in that git link and see if it fails for you
     
  10. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    Just tested this in a couple more Unity versions: the bug does NOT happen in 2019.2.21f1 or in 2019.3.3f1 - so at least it looks like it was fixed at some point, probably 2019.2?
     
  11. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    Doesn't happen in 2018.4 either, so it seems like they introduced and then fixed a bug.

    So, time to upgrade, I guess?
     
  12. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    OP, looking at the release notes for 2019.2.0 (the very next available after 2019.1.14) I saw this note:

    "Scripting: Fixed an issue where constructors were called twice on ScriptableObjects with custom attributes when referencing the ScriptableObject instance. (1113071)"

    I could imagine how that could manifest itself in weird behavior along the lines of what you experienced. Do you have custom attributes? I don't know if a CreateAssetMenuAttribute is considered a custom attribute.
     
  13. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    926
    There were other similar inconsistencies that i've experienced so i made it a habit to close unity before doing anything git related and that works well for me.
     
    Bunny83 and Kurt-Dekker like this.
  14. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    Since posting about this, people on Twitter have told me that they've also experienced this bug (or one quite similar to it) in 2019.3 - I can't seem to recreate it there myself, but if it wasn't fixed intentionally, I wouldn't be surprised to see it return. The 113071 issue sounds like it might be related, but it's hard to tell for sure.

    Perhaps the most interesting thing is how I've had almost polar opposite responses, many people saying "ScriptableObjects are fine for us and we've used them for years with zero problems" and then many others saying "of course ScriptableObjects have problems, we've been dealing with issues like this for years". I'm inclined to think both groups are telling the truth, which means there must be some variability in what causes this.
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    One of the big disconnects with ScriptableObjects has to do with their lifecycle.

    Monobehaviors have a very clear lifecycle, and only exist on GameObjects.

    ScriptableObjects are a lot more fuzzy: they don't exist until referenced somehow, there is only one instance associated with a disk asset (unless you instantiate a copy of course), and once in existence, they don't go away until destruction or the app closes. This means in the editor even private fields are preserved from compile to compile, unless you mark them as NonSerializable. Just the mere saving of a private field is counter to all other Unity usages, let alone saving it when it's not even in the scene from run to run.

    Compounding this is that SOs receive OnEnable() and OnDisable() calls, but really only incidentally: you'll get an OnEnable() when they first get spun up, then no more Ena/Dis calls until the app exits, and this detail could have profound implications if you're assuming they are more like MBs.
     
    eses likes this.
  16. MattRix

    MattRix

    Joined:
    Aug 23, 2011
    Posts:
    121
    Found this other thread that seems to be talking about the same (or similar issue), says it is fixed in 2020.1 because of Asset Pipeline V2: https://forum.unity.com/threads/solved-issue-with-asset-files-updating-through-collab.457722/

    FWIW, the very specific issue I described in this thread only happens in 2019.1, not 2019.2 or 2019.3, but it sure sounds like there is a very similar issue still occuring in those versions (though I haven't experienced it yet personally).
     
  17. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    OnEnable/OnDIsable call conditions are pretty straight-forward. OnEnable is called the moment the asset is loaded into memory. OnDisable is called when its unloaded (either manually or automatically). Typically it'll unload when its no longer referenced and you manually call Resources.UnloadUnusedAssets, when a scene unloads, or when unity decides it needs to clear up memory. They can also be called editor-time too when you compile, switch scenes, or change playmode, but this tends to only happen when they are serialized to a field in the scene. You can log your OnEnable/OnDisable calls and find out if your Sos are hanging around in memory too long, or not long enough.
     
  18. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    1,268
    I have a project with thousands of so's and use git a lot, and haven't seemed to run into this issue yet. I remember an issue like this a while ago, but I think it was fixed in 2018.3, so I think it's a different issue. Are you using any serialization add-ons, like Odin Serializer?
     
  19. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    855
    I have the problem as well.
    I have many sos and decided to change a field default value from 0.5 to 0.75. Instead of doing it for every so, I changed my variable name and with new default value 0.75.
    It is OK and all of them have default value 0.75 in the inspector but when I check so file, I see 0.5 with old field name and can not send changes through git to another one.
    upload_2020-4-23_5-5-48.png

    upload_2020-4-23_5-6-24.png
     
  20. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    That's a different issue. The so hasn't been reserialized. If you change any single property on that so, you'll see the values change.

    If you want to do it in bulk, there's the AssetDatabase.ForceReserializeAssets API to do that.
     
    mahdiii likes this.
  21. mahdiii

    mahdiii

    Joined:
    Oct 30, 2014
    Posts:
    855
    Thanks and you mean it is normal and it is not a problem?
    Do you know why sos are not reserialized while they have changed in the inspector?
    I think it is more convenient to change values in the inspector instead of using
    AssetDatabase.ForceReserializeAssets
    Because I have to pass different paths to it.
     
    Last edited: Apr 23, 2020
  22. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,194
    It's not a problem - the values you're seeing are the ones that will be used. Unity just doesn't write anything to file unless you make an active change, probably to reduce the amount of version control spam.
     
    Bunny83 likes this.
  23. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    752
    I'm running into the same issue where ScriptableObjects don't always update when changes happen on the file system outside of Unity. I'm on 2019.4.15f1
     
    Xarbrough and AnkamaUnity22 like this.
  24. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    We're coincidentally on this same version and have a lot of SOs, and use source control in a team context. It certainly SEEMS to update every time... that said though, the best way to use Unity and source control is still to close Unity before committing or pulling or doing anything to your working files.
     
    Joe-Censored likes this.
  25. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    I have the same issue as OP in Unity 2020.2. Some ScriptableObject assets in the projects have a checkbox enabled and a string "hey". The data is shown in the inspector and is also serialized to the YAML file. I then update via PlasticSCM or simply revert a file in version control. This changes the YAML file on disk. I can see in a text editor, that the bool is now false and the string is "bla". In Unity, the inspector still shows enabled and "hey". I then refresh, reimport, enter play mode etc, and nothing will force the inspector to update unless I restart Unity. It seems Unity has an in-memory cache of the ScriptableObject and doesn't reload from disk until restarted.

    Same thing happens with Materials, btw. I also found that I can "force fix" the issue by disabling "Directory Monitoring" in the Preferences and then reimporting the asset.
     
    Last edited: Feb 8, 2021
    Clay_More and ManuelKers like this.
  26. ManuelKers

    ManuelKers

    Joined:
    Jan 24, 2015
    Posts:
    3
    I'm experiencing the same issue as originally posted in Unity 2020.2.4. It definitely was in 2020.2.3 as well. This issue seemed to pop up after updating from 2020.1.3 to 2020.2.3.

    I've put together a minimal reproduction case in the attached project. It only presents the issue seemingly arbitrarily about 7 out of 10 times, and only when the file-edited object is selected in the inspector, but still it is easily reproducible on my Windows 10 machine. In our actual project the issue arises 100% of the time. i.e. after syncing a team member's changes (git pull) we cannot get the correct state in the scriptable object inspector without restarting unity.

    I feel the issue is related to the Asset Importer missing out on file changes, depending on the complexity of the project.

    Attaching the entire bug report below. Will update when we get any answers from Unity.

    @ryanc-unity Pinging you since you originally helped people in seemingly the same issue in thread https://forum.unity.com/threads/solved-issue-with-asset-files-updating-through-collab.457722/ Perhaps you can put this issue on the radar of the right people? Thanks in advance.

     

    Attached Files:

    Clay_More, Xarbrough and AbbeyAdriaan like this.
  27. ManuelKers

    ManuelKers

    Joined:
    Jan 24, 2015
    Posts:
    3
    Also just noticed that there's an Asset Importer log. This reflects that the change is actually always noticed by the importer, just not always by th inspector.

    These are the two subsequent outputs of the importer log when changing the file and checking back in Unity (using the provided test project). The former resulted in no inspector-state update, the latter in a correct update. However both imports seem successful and the output doesn't differ as far as I can see.
     
    AbbeyAdriaan likes this.
  28. Clay_More

    Clay_More

    Joined:
    Dec 17, 2015
    Posts:
    11
    This problem is also present on 2020.1.15f1.
    I would expect that all scriptable objects would be reloaded from disc after scripts reload. It is very counter intuitive that you can have some cached version of the asset which differs with version from disc even after domain reload..
     
    joshcamas likes this.
  29. ManuelKers

    ManuelKers

    Joined:
    Jan 24, 2015
    Posts:
    3
    Sad to hear you're experiencing it too, Clay_More. How do you or your team deal with it?

    I just got a response to my bug report:

    I'm not sure why this issue isn't tracked publicly, but I went through the patch notes of 2021.1.0a9 and I think they are referring to the following, which indeed lacks an issue link, but does have an ID.
    I've asked about some more info on the backport fix, because we probably won't be upgrading to 2021 for this project, let alone an alpha version.

    Update: More info from customer support:
     
    Last edited: Feb 23, 2021
  30. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    752
    Wow, if its not backported to 2019.4, that's pretty horrible. They can't expect us to upgrade to an alpha version from a LTS
     
  31. mariozhou

    mariozhou

    Joined:
    Oct 18, 2019
    Posts:
    23
    Reproduces with 2020.3.5f1
     
  32. rise9912

    rise9912

    Joined:
    Feb 19, 2018
    Posts:
    10
    Same problem in 2019 LTS version. Very annoying. Our team have to reopen unity every time if there was a change in SO
     
  33. Arkitas

    Arkitas

    Joined:
    Oct 29, 2019
    Posts:
    4
    For anyone like @Kurt-Dekker and myself where editor changes are not writing to disk (typically needed for git/VCS management). If you are using Custom Scriptable Object Inspectors you need to mark the target inspector as "Dirty" for the EditorUtility. That will force it to write values to disk as soon whenever you next save.

    Solution was found here:
    https://forum.unity.com/threads/custom-editor-not-saving-changes.424675/
     
    Kurt-Dekker likes this.
  34. esteban16108

    esteban16108

    Joined:
    Jan 23, 2014
    Posts:
    158
    it just happened to me and I searched on google and found this...

    Unity v202.3.27 and Windows 11

    I was going crazy, happened to me with animationControllers and animations and they didn't appear dirty until I closed Unity
     
  35. Midiphony-panda

    Midiphony-panda

    Joined:
    Feb 10, 2020
    Posts:
    234
    Issue here with Unity 2021.2.5f1.
    Will check in the next weeks with Unity 2021 LTS
     
  36. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    752
    I'm still having this issue, I'm now on 2020.3.32f1. Does anyone have any news on this?
     
  37. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    Since it has been like this for several decades, and since people have filed countless bug reports, and those bug reports are either marked will not fix or whatever, I seriously urge you to stop wasting time reporting the same findings. It has become just white noise.

    Instead, use the common workaround we all use every day: Save the Project before doing source control, or even exit Unity if you're unsure.

    Don't let it hold you back. Don't let it make you bitter. Think of it as like that irritating static electricity shock you get anywhere in Arizona when you touch a doorknob. Anticipate it and get on with your life. Focus on the real problems.
     
    chriseborn and tinoow like this.
  38. guneyozsan

    guneyozsan

    Joined:
    Feb 1, 2012
    Posts:
    99
    I do `File/Save` (not `Ctrl+S`, it does not work) when I modify a scriptable object, so that it is serialized and git grabs the changes. Interestingly enough, although it says `Ctrl+S` as the keyboard shortcut near the `File/Save` menu item, they definitely do not do the same thing.
     
  39. unity_64C4953874932131A25C

    unity_64C4953874932131A25C

    Joined:
    Aug 25, 2022
    Posts:
    1
    call EditorUtility.SetDirty(your_so); and then click File > Save Project works for me
     
    pjhk5797 likes this.
  40. cihadturhan_unity

    cihadturhan_unity

    Joined:
    Apr 19, 2021
    Posts:
    51
    Thanks! `SetDirty` worked
     
  41. pjhk5797

    pjhk5797

    Joined:
    Mar 11, 2021
    Posts:
    2
    This worked mine too! Thanks!
     
  42. dhanrajsinh24

    dhanrajsinh24

    Joined:
    May 8, 2014
    Posts:
    59
    You don't need to do File->Save Project or Save, just include this line after SetDirty:
    AssetDatabase.SaveAssets();

    we use AssetDatabase.SaveAssets() to save those changes to disk. This should ensure that the changes are detected. You must explicitly tell Unity to serialize and save the changes when they occur programmatically.

    So,

    // Mark it as dirty and save to disk
    EditorUtility.SetDirty(mySO);
    AssetDatabase.SaveAssets();
     
    pjhk5797 likes this.
  43. pjhk5797

    pjhk5797

    Joined:
    Mar 11, 2021
    Posts:
    2
    yep, you are right. plus, you can simply use AssetDatabase.SaveAssetIfDirty(Object or GUID); instead. To prevent the saving of other assets at the same time.
     
    dhanrajsinh24 likes this.