Kefik
Kefik

Reputation: 101

Serialization misbehave when closing Unity

I'm using ISerializationCallbackReceiver to serialize my custom interrelated data following tutorial http://blogs.unity3d.com/2014/06/24/serialization-in-unity/ regarding serialization of graph nodes adjusting it to my needs.

My serialization is working fine when I'm hot swapping the code when I'm developing scripts. But once I save the scene, close Unity and reload the project again, my data is deserializing from some bogus.

[01] [17:23:43] Quest[The Sculpture and The Box|SLEEP]: Serializing QuestStepData[fqcn=experiment.questsjg.steps.GoToLocation|name=Sculpture|description=F|closedByIndex=-1|go1Present=True|go1=sculptures_01_02 (UnityEngine.GameObject)|go2Present=True|go2=[1] Go To Location Point (Sculpture) (UnityEngine.GameObject)|f1=8]
[02] [17:23:43] Quest[The Sculpture and The Box|SLEEP]: Serializing QuestStepData[fqcn=experiment.questsjg.steps.GoToLocation|name=box|description=S|closedByIndex=-1|go1Present=True|go1=box1 (UnityEngine.GameObject)|go2Present=True|go2=[2] Go To Location Point (box) (UnityEngine.GameObject)|f1=4]

[03] [17:24:09] Quest[The Sculpture and The Box|SLEEP]: Deserializing QuestStepData[fqcn=experiment.questsjg.steps.GoToLocation|name=Sculpture|description=|closedByIndex=-1|go1Present=True|go1= (UnityEngine.GameObject)|go2Present=True|go2= (UnityEngine.GameObject)|f1=8]
[04] [17:24:09] Quest[The Sculpture and The Box|SLEEP]: Deserializing QuestStepData[fqcn=experiment.questsjg.steps.GoToLocation|name=|description=|closedByIndex=-1|go1Present=False|go2Present=False|f1=10]

Here is a log of what I'm de/serializing. Unity got restarted between 17:23:45-17:24:00 and as you can see it did not deserialize (Rows 03 and 04) from the same data I serialized (Rows 01 and 02).

When I save the scene, I typically get Rows 01 and 02 logged.

But when these "rows" gets deserialized when I open Unity, I get Rows 03 and 04 and as you can see Row 03 "description" differs from Row 01 and Row 04 is missing everything except 'fqcn' field when compared with Row 02.

Logs are as precise as they can get (I'm writing them to the file), so these serialization lines 01 and 02 should be the last thing Unity is doing with my data when closing...

Now I'm buffled...

  1. Serialization is working flawlessly when hot swapping the code
  2. Not working when restarting Unity ... (the worst thing is that it "drops" only some infos)

Any hints what I might be doing wrong?

(The same happens for 3+ items... only 1st item is somehow correct)

P.S.: It does not matter whether you have Asset serialization set to "Mixed" or "Force Text".

If I have "MIXED" then data within the scene file looks like this:

The Sculpture and The Box               !   NyŻ        
stepsData.Array.data[0].fqcn&   
experiment.questsjg.steps.GoToLocation              !   NyŻ     %   
stepsData.Array.data[0].closedByIndex      -1              !  NyŻ    
stepsData.Array.data[0].f1     8               !   NyŻ        
stepsData.Array.data[0].name       Sculpture               !   NyŻ        
stepsData.Array.data[0].go1         ^    !   NyŻ     "   
stepsData.Array.data[0].go1Present     1               !   NyŻ        
stepsData.Array.data[0].go2         *¨    !   NyŻ     "   
stepsData.Array.data[0].go2Present     1               !   NyŻ        
stepsData.Array.data[1].fqcn&   
experiment.questsjg.steps.GoToLocation              !   NyŻ     %   
stepsData.Array.data[1].closedByIndex      -1              !   NyŻ        
stepsData.Array.data[1].f1     10              !   NyŻ        

As you can see, serialized data are not there, just compare stepsData.Array.data[0] and stepsData.Array.data[1]

If I have "Force Text" then data within the scene file looks like this (it's actually even worse):

- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[0].fqcn
  value: quests.steps.GoToLocation
  objectReference: {fileID: 0}
- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[0].closedByIndex
  value: -1
  objectReference: {fileID: 0}
- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[0].f1
  value: 10
  objectReference: {fileID: 0}
- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[1].fqcn
  value: quests.steps.GoToLocation
  objectReference: {fileID: 0}
- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[1].closedByIndex
  value: -1
  objectReference: {fileID: 0}
- target: {fileID: 11499854, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: stepsData.Array.data[1].f1
  value: 10
  objectReference: {fileID: 0}
- target: {fileID: 107138, guid: bd017908bdedeb24d9559a160e99a0c1, type: 2}
  propertyPath: m_Name
  value: First Quest
  objectReference: {fileID: 0}

Hmmmm, what's happening in there?

Upvotes: 1

Views: 339

Answers (1)

Kefik
Kefik

Reputation: 101

Aaaa!

The trick is to call EditorUtility.SetDirty(gameObject) EVERY TIME ANYTHING CHANGES as this page states: http://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html

Unity internally uses the dirty flag to find out when assets have changed and need to be saved to disk.

E.g. if you modify a prefab's MonoBehaviour or ScriptableObject variables, you must tell Unity that the value has changed. Unity builtin components internally call SetDirty whenever a property changes. MonoBehaviour or ScriptableObject DON'T DO this AUTOMATICALLY so if you want your value to be saved you need to call SetDirty.

Therefore, whenever you're creating your CustomEditor following http://docs.unity3d.com/Manual/editor-CustomEditors.html make sure to use the trick:

GUI.changed = false;

// do you're edit code here

if (GUI.changed) SetDirty(yourGameObjectThatHasJustChanged);

Hope this saves someone's time :-)

Cheers!

Upvotes: 0

Related Questions