Search Unity

Loss of serialized data when pulling new scripts and prefabs from a repo

Discussion in 'Editor & General Support' started by AndrewCzarnietzki, Apr 19, 2017.

  1. AndrewCzarnietzki

    AndrewCzarnietzki

    Joined:
    Jul 23, 2013
    Posts:
    189
    Hey,

    We're running into a weird serialization related issue. The sequence of events:

    a) Programmer adds a [SerializedField] / public variable.
    b) Programmer gives this variable some data on a prefab / in a scene.
    c) Programmer submits script and prefab together to Perforce (submitting just the script would have a temporarily broken state - and the work makes sense to package together). Note we've also reproduced the issue with Programmer submits script. Programmer submits prefab.
    d) Person X checks out the latest version from the repo.
    e) Person X opens Unity. Unity appears to import the prefabs and THEN compile the code. The new serialized values are lost (as the fields didn't exist when it was loaded), the freshly compiled code makes the values appear as fields, but as there was no data loaded the fields have the default / null values. If Person X were to save this data they would undo all of the Programmer's field data, which can include fairly sensitive tuning.

    The workaround, which is absolutely brutal, is to open Unity, allow the code to compile, then close Unity without saving, then open Unity again.

    On our last project (which involved large vehicle prefabs brimming with scripts), and even with this workflow, this error was responsible for about 20% of our bugs.

    It appears that the data is still present in the library prefab asset, but the freshly compiled fields only have data once the code is compiled and then either the meta is changed or we reload Unity completely.

    While we see this issue with Perforce, we can reproduce this with just notepad - changing a prefab and script file on disc (as if it came from source control).

    We can't be the only ones to encounter this rather frustrating issue. Is there some way to automatically force a reload or otherwise keep this data in sync? Does anyone have a suggested workaround?

    Thanks!

    A
     
    Mulegames likes this.
  2. Mulegames

    Mulegames

    Joined:
    Sep 27, 2016
    Posts:
    10
    We've been running into something similar with ScriptableObjects and SerializedFields. Trick we use is check out asset, CTRL-D to duplicate, then delete the duplicate and check in. Almost as if Unity is keeping the data in memory instead of committing it to the file.

    This occurs even when there is no change to the code for the ScriptableObject, either. If Person A makes changes to ScriptableObject Asset then checks it in, Person B still gets an old version of the file when they pull. Likewise, if Person A made changes to Asset, then Unity crashes for whatever reason, all the changes will be lost for Person A when they reopen Unity.

    Quite annoying, as we rely heavily on ScriptableObjects in our game.
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    So you're saying that if you have a script like this:

    Code (csharp):
    1. public class Data : MonoBehaviour {
    2.  
    3.     public int i;
    4.     public string s;
    5.     public bool b;
    6. }
    And a prefab with the data set like this:
    Code (csharp):
    1.  
    2.   i: 3
    3.   s: asdf
    4.   b: 0
    And then you push a change that adds a field:

    Code (csharp):
    1. public class Data : MonoBehaviour {
    2.  
    3.     public int i;
    4.     public string s;
    5.     public int i2;
    6.     public bool b;
    7. }
    ... and sets that new field on the prefab:

    Code (csharp):
    1.   i: 3
    2.   s: asdf
    3.   i2: 15
    4.   b: 0
    The i2 on the bottom there will be turned into 0 when you open the project?

    I did both edits with notepad, with the project closed, and when I opened the project again everything worked as expected. i2 was not reverted to 0, as you seem to be experiencing.

    I've also never experienced this (working on a project that started in late Unity 3, finished in 5.5, using git for source control), so I'm guessing it's got something to do with your setup that triggers the bug. What's your Asset Serialization and Version Control modes?
     
  4. AndrewCzarnietzki

    AndrewCzarnietzki

    Joined:
    Jul 23, 2013
    Posts:
    189
    Thank you for the reply and sorry about the delayed response!

    The code above does illustrate the anomaly. We are using perforce for version control, but as I said we are able to replicate this in notepad. Forced text serialization with visible meta files.

    So we add a new variable, lets call it [SerializeField] int foo = 0; (our code standards define defaults for everything, and no public variables - I'm actually now wondering if this is related looking at your example...)

    We then submit the C# containing this (defaulting foo=0), and a prefab where foo = 15. The client machine syncs, receiving both the C3 file and prefab file.

    When we open Unity (or if we updated while Unity was running), foo doesn't exist in the prefab. The code compiles. Then foo is set to 0. The library instance of the prefab data does show foo = 15. The .prefab file still shows foo = 15, but the instance inside Unity has foo = 0. If we save prefabs, the .prefab will then contain foo = 0. If we change the meta file for the prefab, or close Unity and re-open it, then foo will be loaded as 15.

    The workaround is to let Unity compile, then to close Unity, then re-open. This is a very ugly issue. We have seen this through all of Unity 5x (hard to say when it started as we noticed what we thought was user error first), up to and including 5.6.

    Thanks!
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    It might be the defaults. I never use defaults for Unit-serialized data. Honestly, I still don't quite understand how Unity handles it.

    Are you using some kind of perforce integration? I've seen Perforce as a possible choice in a drop-down somewhere. It could be that the integration and default variables don't mix very well.

    Try sending some prefabs without defaults, and see what happens.