Search Issue Tracker

Fixed in 2018.4

Votes

27

Found in

2018.1.4f1

Issue ID

1050941

Regression

No

ScriptableObject references become temporarily null in Editor when they are modified outside of Unity and then reloaded

Scripting

-

When a .asset file containing a ScriptableObject is modified on disk, Unity destroys the existing ScriptableObject C# instance, then creates a new one and loads the modified file into it. However, for a while at least, any other objects (Like MonoBehaviours in the scene) that have a direct reference to the ScriptableObject will still be pointing to the destroyed instance.

To reproduce:

1. Download attached project "ScriptableObjectReloadTest.zip" and open in Unity
2. Open "SampleScene" scene
3. Select the ScriptableObjectReloadTest > Probe Container menu item
4. Observe the following output in the Unity Console:

"Everything fine! (name="FooConfig" instanceID=2390 data="Foo7", ID=1) m_Config
Everything fine! (name="FooConfig" instanceID=2390 data="Foo7", ID=1) config at index 0 of m_Configs
Everything fine! (name="FooConfig" instanceID=2390 data="Foo7", ID=1) config at index 0(FooWrapper) of m_ConfigWrappers
Probed, 0 errors found"

5. From Assets folder open the FooConfig.asset file in an external text editor
6. Modify the last line to change the m_Data property of the asset
7. Save the .asset file from the text editor
Note: This simulates an external operation like a sync or reverts in source control that modifies the .asset file
8. Switch back to Unity
Note: At this point, Unity will notice the file has been changed and silently reloads it
9. Select the ScriptableObjectReloadTest > Probe Container menu item
10. Observe the following output in the Unity Console:

"Unity null (instanceID=2390 data="Foo7" ID=1) m_Config
Unity null (instanceID=2390 data="Foo7" ID=1) config at index 0 of m_Configs
Unity null (instanceID=2390 data="Foo7" ID=1) config at index 0(FooWrapper) of m_ConfigWrappers
Probed, 3 errors found"

11. Observe as well that the "Data" value reported in the console is the old value from before we changed it outside Unity

To Resolve:

1. Select the ScriptableObjectReloadTest > Probe Container using SerializedObject menu item
Note: This uses a different API to get the m_Config value, simulating what the Unity inspector is doing
2. Observe the following output in the Unity Console:

"Everything fine! (name="FooConfig" instanceID=2390 data="Foo8", ID=2) m_Config (via SerializedProperty)
Probed SerializedObject, 0 errors found"

3. Observe that when accessed this way the reference is valid and the "Data" value is correct
4. Select the ScriptableObjectReloadTest > Probe Container menu item
5. Observe that the references still look broken
6. Select "Container" gameObject and in the Inspector modify the "Unrelated Data" field of the Scene Container script
7. Select the ScriptableObjectReloadTest > Probe Container menu item
8. Observe that everything is back to normal and shows correct references

Notes:
- This issue appears both on Windows and OSX
- Other instances where this can occur:
1. A user is about to edit an asset, but it isn't at the head revision, because someone else has recently checked in a change to the same file, the user right clicks the asset in Unity and select "Version Control/ Get Latest"
2. A user has been working on an asset (and saved it) but now wants to throw away their changes, so they right-click the asset in Unity and select "Version Control/Revert..."

Reproduced on Unity 2017.1.4p2, 2017.2.3p1, 2017.3.2f1, 2017.4.6f1, 2018.1.6f1, 2018.2.0b10 and 2018.3.0a3

  1. Response avatar

    Resolution Note (fix version 2018.4):

    Currently in Unity Editor when an asset is loaded, Unity creates a representation of the asset in the managed side of the engine an another representation on the native side of the engine.
    In general the internal data of the asset is stored in the native object, so when the user queries the data of the asset from the managed side, internally the data is retrieved from the native object. For this reason it is safe to have several objects in the manage side representing the same asset, since all of them will be linked within a single native object.

    ScriptableObject asset is an exception to the default asset loading behavior because for this type of asset, the asset data is actually in the managed object itself. For this reason it is not safe to have several objects in the manage side representing the same ScriptableObject asset. Since data is stored on the managed side, having multiple managed object representing the same object could end up of having data out of sync.

    At the moment there is no plan to support proper HotReload on ScriptableObjects, so for now, if an ScriptableObject is unloaded it will have to be reloaded manually again and any previous reference to that ScriptableObject won't be valid.

Comments (5)

  1. C51f843c7a7d04f32651cb97725902e8?d=mm

    Lune

    Aug 18, 2019 04:54

    I have found a ridiculous way to fix this.

    if you hit play, you should be able to see the data contained in the scriptable object files.

    while playing, right click on the files in the projects tab, hit reimport (yes.. while playing), if the data is not corrupted, you should have recovered the data from your missing scriptable object.

  2. E8868d71e514ddfbe59a9f2724196306?d=mm

    kahyong_unity

    Jul 29, 2019 03:39

    I have verified that there is a fix that landed on 2019.1 and it was back-ported back to 2018.4 and 2018.3 as well.

  3. E8868d71e514ddfbe59a9f2724196306?d=mm

    kahyong_unity

    Jul 29, 2019 03:37

    It appears that this SO behavior is no longer reproducible on 2018.3.14f1, 2018.4.5f1 and 2019.1.12f1.

  4. Ef5507abd3854f6ff77906202360c80e?d=mm

    roboryantron

    Jul 18, 2019 03:17

    Coming across this bug report has cleared up so much ambiguity with asset database bugs my team has run into. It has gotten to the point where people close the editor before syncing on source control.

    This is a huge frustration on a daily basis and leaves people just angry at the editor. Please consider reprioritizing this as it should be expected that developers pull in changes from source control regularly. The fix note seems to imply that using source control when the editor is not open is not supported. This is not a limitation that should be expected in modern software development.

  5. 0c6c1a2c7a70204589b2a61afdf0dd0d?d=mm

    DCardillo

    Apr 23, 2019 15:20

    For anyone stumbling upon this issue, I may have found a workaround. The references I had to a ScriptableObject would be equal to Unity's "null", but they wouldn't have a name and I couldn't get the GUID from them (which would be required to load the asset again). However, calling GetInstanceID() returned a valid instance ID. Curiously enough, this is the same instance ID as the real ScriptableObject my reference is failing to find. Calling "EditorUtility.InstanceIDToObject(id) as ScriptableObjectType" would return the reference I needed after getting the ID from the "null" reference.

    I was forced to do it this way since none of the standard functions for refreshing or dirtying assets seemed to fix the null references. SerializedObject.Update(), SerializedObject.ApplyModifiedProperties(), Undo.RecordObject(), EditorUtility.SetDirty(), AssetDatabase.ImportAsset(), AssetDatabase.Refresh() and AssetDatabase.SaveAssets() do NOTHING to fix the references.

    I wish Unity specified in their resolution note what they meant by "reloaded again manually" as it would be impossible to reload a null reference without getting it's path or GUID (which is impossible to get from the null reference AFAIK). You could serialize an additional GUID string for any ScriptableObject reference, but this seems like a waste when the GUID is already serialized to store the reference in the first place.

    Unity will automatically fix this "null" reference issue during a recompile or when you quit the application and open it again. What is frustrating is that Unity must have some internal method for updating ScriptableObject references, but it is not made public to developers. This issue wouldn't be so bad if we could simply force Objects to update their ScriptableObject references by calling AssetDatabase.UpdateAsset() or something.

    It is unfortunate that Unity has no current plans to address this, but at least a workaround exists for now. Hopefully the new "Addressable Asset System" resolves this when it releases. I would also strongly encourage Unity to put this information in their documentation, as I spent hours trying to figure out why none of the functions I mentioned were fixing the issue.

Add comment

Log in to post comment

All about bugs

View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.