- Home /
Objects created in editor tool, fields reset on play and unable to serialize.
Hello peopleses!
Sorry for the long read. I do have a question, but if this is better suited for a Forum discussion, I apologize.
I'm using an editor tool of mine to create objects (through code) in the editor before the game start, and it seems to work just fine at first. But as soon as I press play I get all these NullReferenceExceptions. It seems that some fields, and all my non-public fields, are being reset upon pressing play.
After some confusion and searching for this problem this my understanding of the case: objects are serialized and recreated on start. As a result, if something is not serializable it is given a default value (null or zero, etc). So it seems what I need to do is serialize all (non-public) fields so that Unity can create them again on play.
But... You don't seem to be able to serialize everything. For example, I'm using LinkedList, and while I can serialize the field holding an object, that object's LinkedList fields are set to null. This is for a big project, big classes, lots of code - changing the classes being used is not an option.
So my question: Is there an easy workaround to this problem? Is there another way to get your objects from the editor to the game without having all fields, fields of the fields' objects (and so on) serializable? Since some of my objects unfortunately are not fully serializable it seems.
I can think of one workaround: I could make new representations of all the data currently used to create the objects in the editor, and have these representations be serializable. And instead of creating the objects directly in the editor I create objects for holding the serializable versions of the data. Then on Start() I create the actual objects using this data. (A matter of convering the data from one format to the other and then back.)
But maybe I'm missing something. Any suggestions, guidance or corrections to this problem is greatly appreciated!
Cheers. :)
EDIT: On second thought, LinkedList< T > does have the Serializable attribute... And still it is being reset! Why is this? :O
Answer by TowerOfBricks · Aug 14, 2011 at 07:47 PM
As you have guessed, Unity cannot serialize everything, it can serialize classes with the Serializable attribute and (according to the docs, but it seems to work fine without) inheriting from UnityEngine.Object. Unity must however be able to serialize the members of the class, which could be ints,floats,strings,booleans, other similar simple types or built-in arrays of those (e.g float[]).
If Unity should be able to serialize your data, you must expose them to a public variable in a ScriptableObject or to a MonoBehaviour. Unity should be able to serialize a linked list of simple classes like this:
public TestClass linkedListStart = new TestClass ();
[System.SerializableAttribute]
public class TestClass {
public float someData = 42;
//Note, if this was set to = new TestClass (), it would get stuck in an infinite loop and crash Unity
public TestClass next = null;
}
Try to organize your data to something Unity can serialize, that is the easiest approach. And don't forget to mark your object with EditorUtility.SetDirty (...);
Otherwise you can use a custom serializer to serialize your data. Take a look here: http://msdn.microsoft.com/en-us/library/ms973893.aspx
Answer by roburky · Aug 14, 2011 at 07:50 PM
LinkedList should be serializable, as long as it is storing a serializable type. Are there any other types you are depending on that are truly not serializable? Check the documentation page for [SerializeField].
Try setting [System.Serializable] on the objects you are creating from the editor.
[System.Serializable]
public class MyClass
{
[SerializeField]
private LinkedList<int> linkedList;
}
[1]: http://unity3d.com/support/documentation/ScriptReference/SerializeField.html
Thanks for the answers. You would think that would work... But I created a serializable test class, with public fields (public fields being Serializable by default in a Serializable class). I had it contain one LinkedList< int > (just like in your example) and one int. When I ran the game the int was not reset, it had its value remain. But still the linked list was reset to null, despite containing ints.
$$anonymous$$y current solution is having an intermediary serializable class, and using arrays ins$$anonymous$$d of linked lists. I then convert it to the proper classes and create the game objects when the game starts ins$$anonymous$$d. It works but its a bit ugly.
Could you post the whole code of your test class?
I use LinkedList all the time, and I would find it very frustrating if I couldn't serialize it.
Alright, so I made this new test class. I added SerializeField to it even though its public, just in case.
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
[Serializable]
public class Test : $$anonymous$$onoBehaviour
{
[SerializeField]
public LinkedList< int > LinkedListTest;
public void Start ()
{
if (LinkedListTest == null)
Debug.Log("The linked list is null!");
else
{
String str = "The linked list contains the following items: ";
for (LinkedListNode
n = LinkedListTest.First; n != null; n = n.Next)
str += (n.Next == null ? n.Value.ToString() : n.Value.ToString() + ", ");
Debug.Log(str);
}
}
}
After I've created the test class in the editor and created a new linked list with the elements 0, 1 and 2 I call its Start() method myself and I get the expected debug log: "The linked list contains the following items: 0, 1, 2".
However when I start the game and the test class' Start() is invoked I get the debug log "The linked list is null!".
I then tried EditorUtility.SetDirty() as suggested by The Stone (this method is new to me), when I've created and added the Test component to a GameObject I used SetDirty() on the Test object. Anyway, the result is the same. The linked list is reset to null.
Hmm.
All I can think of at the moment is that it's something to do with your custom editor scripting.
Does a public LinkedList on a simple $$anonymous$$onoBehaviour script with a default Inspector and no other special editor stuff going on work ok? Do the values in your LinkedList get saved if you deselect the GameObject and reselect it, without running the game?
Your answer
Follow this Question
Related Questions
Prevent Reset() from clearing out serialized fields 2 Answers
Character motor script resets when I play 1 Answer
How do I expose class properties (not fields) in C#? 7 Answers
Variables in editor script reset when playing 1 Answer
field become null after object as instantiated using EditorGUILayout.ObjectField 1 Answer