Hello everybody.
I have a MonoBehavior implementing ISerializationCallbackReceiver.
It contains a couple of things Unity can serialise and some Unity cannot, by default, serialise.
The problem real quick:
- Saving the scene (via Ctrl+S) will not persist a byte array changed via custom inspector / Editor windows.
- Force-Saving scene via
EditorApplication.SaveScene()
works - Changing something else on the same GameObject will also force Unity into persisting the byte array.
Assuming:
- Unity has trouble recognising a changed by array?
- I’m missing something important?
The problem in detail:
Here’s a version of that class stripped down for brevity:
public class SequenceExecutor : MonoBehaviour, ISerializationCallbackReceiver {
[SerializeField]
private List<ValueField> globalDataContext;
[SerializeField][HideInInspector]
private byte[] serializedModelTree;
private UnityBtModel rootModel; // This is not serializable by unity as it contains deep tree structures further than 7 steps
[SerializeField]
private ExecutionType executionType;
public void OnAfterDeserialize() {
using (var ms = new MemoryStream(serializedModelTree)) {
ms.Position = 0;
this.rootModel = DataSerializer.DeserializeProtoObject<UnityBtModel>(ms.ToArray());
}
}
public void OnBeforeSerialize() {
this.serializedModelTree = DataSerializer.SerializeProtoObject(this.rootModel);
}
}
The important bit here is the byte array that is handled in the serializer callbacks.
I’m editing this class via an EditorWindow that I open through a button added via custom inspector.
Everytime OnInspectorGUI is called I set the instance of the class in the inspector dirty via EditorUtilities.SetDirty()
.
So all prerequisites for that byte array getting written to disk are there, to my understanding.
Here’s what is happening though:
I’m changing the data in rootModel (add some children, change data inside the children) via the editor.
Now I’m saving the scene (because that MonoBehavior is scene data).
I have some Debug output that indicates I’m serializing (via the serialisation callbacks) the correct data and set it to the variable serializedObjectTree
, which is a serializable byte array.
Now closing the project.
When loading the project again, the changes did not persist.
However.
When doing the same thing but also changing something Unity can serialize “natively” - like the executionType
enum, then all changes, including the ones that go into the byte array, are persisted properly. In fact, it will already do to disable and enable the component in the inspector.
I wonder, what am I not getting here?
Should I handle that byte array differently?
EDIT:
I also tried in OnInspectorGUI to force a new byte array down Unitys serializer like this:
var prop = serializedObject.FindProperty("serializedModelTree");
prop.ClearArray();
sequencer.OnBeforeSerialize();
for (int i = 0; i < sequencer.SerializedModelTree.Length; ++i) {
prop.InsertArrayElementAtIndex(i);
var element = prop.GetArrayElementAtIndex(i);
element.intValue = sequencer.SerializedModelTree*;*
}
EditorUtility.SetDirty(sequencer);
To no avail. It’s still only writing the data (including the changed byte array) to disk only when I change something “natively” serializable.
For reference, here’S the inspector code. It’s using the target object and passes it on to an editor window, where it gets edited.
Edited changes are seen in the inspector.
[CustomEditor(typeof(SequenceExecutor))]
public class SequencerInspector : UnityEditor.Editor {
public override void OnInspectorGUI() {
if (target == null) {
return;
}
base.OnInspectorGUI();
SequenceExecutor sequencer = target as SequenceExecutor;
if (GUILayout.Button(“Open Sequencer Settings”)) {
var window = GenericPopupWindow.Popup();
window.SetData(sequencer);
}
var prop = serializedObject.FindProperty(“serializedModelTree”);
prop.ClearArray();
sequencer.OnBeforeSerialize(); // make real the byte array is up to date
for (int i = 0; i < sequencer.SerializedModelTree.Length; ++i) {
prop.InsertArrayElementAtIndex(i);
var element = prop.GetArrayElementAtIndex(i);
element.intValue = sequencer.SerializedModelTree*;*
}
EditorUtility.SetDirty(sequencer);
}
}
I’ll see what else I can do in the meantime.