- Home /
Serialization of List
Hi there Uniteers. I am currently developing a hierarchy creation system in an editor window, and I have trouble serializing my newly created data, as it simple gets destroyed upon play/exit in the editor.
What the tool can do is create a hiearchy tree of custom classes:
Quest Manager
Quest
SubQuest
ObjectiveInSubQuest
Each of these classes inherit from a class called "HiearchyEntry", in which is a List that contains all the objects of the "sub" class. So basically, QuestManager have a list of Quest. Each Quest have a list of SubQuests etc... The HiearchyEntry contains information about the quantity of sub-types and index values while the child class have some custom logic for game purposes.
The scripts I use are:
Base class: - Contains List<object>
where Object
is the sub element in the hiearchy
[System.Serializable]
public class HiearchyEntry : ScriptableObject
{
[SerializeField]
List<Object> listOfEntries = new List<Object>();
}
Child class: - Inherits from HiearchyEntry
, and contain custom code for game logic
[System.Serializable]
public class QManager : HiearchyEntry
{
public void GetAllActiveQuests()
{
// Insert game logic
}
}
Editor script: - Get the reference of QManager
from Manager
and feed the information to the editor window
[CustomEditor(typeof(Manager))]
public class QManagerEditor : Editor
{
public override void OnInspectorGUI()
{
if (GUILayout.Button("Open Quest Manager"))
{
Manager ManagerMonobehaviour = (Manager)target;
if (ManagerMonobehaviour.qmanager == null) // Creates a new instance of QManager if it doesn't exist
ManagerMonobehaviour.qmanager = (QManager)ScriptableObject.CreateInstance(typeof(QManager));
QManagerWindow newlyCreatedWindow = (QManagerWindow)EditorWindow.GetWindow(typeof(QManagerWindow)); // Opens the editor window
newlyCreatedWindow.InitializeWindow(ManagerMonobehaviour.qmanager); // Initiliaze the new window with the QManager.
}
}
}
The creation of the hiearchy is functioning as intended, but whenever I enter/exit playmode, all my hiearchy data is lost and you will have to create the hiearchy from scratch.
I have looked through various posts and blogs about serialization etc, but nothing have worked out, I am not even sure what I am trying to do is possible.
I have alot of code, and so I have tried to minimize it to, what I believe, is the error. Pleas ask for more information if you think I have left something out.
By "Object" you mean UnityEngine.Object ? Is there a reason why you use a list of Objects? Wouldn't "HiearchyEntry" make a lot more sense?
Answer by Bunny83 · Nov 17, 2013 at 05:54 PM
Unity's serialization system doesn't support inheritance for custom classes. We had that kind of questions quite a few times.
If you need inheritance you have those options:
Use MonoBehaviour as base class. That means all your instances are components and have to be created with AddComponent and therefore are attached to some GameObject / prefab.
Use ScriptableObject as base class. Those don't need to be attached to GameObjects, but need to be created with ScriptableObject.CreateInstance() and they have to be serialized on their own. So you need to use the AssetDatabase to either create seperate asset files or add the asset to an existing asset. That of course only works in the editor, like the whole serialization system.
Use your own classes but don't use Unity's serialization system. So you have to serialize / deserialize your stuff on your own (JSON / XML / binary / ...)
ps: All ScriptableObjects have the same requirement as MonoBehaviour classes, they need to be placed in a seperate file, named like the class.
How would I go around using the AssetDatabase? Would I have to apply my entire hiearchy into a prefab of some sort (That requires the base-class to inherit from $$anonymous$$onoBehaviour), or what would my approach be?
Everything that is saved has to be in some kind of asset within your project. $$anonymous$$onoBehaviours can be saved in prefabs or scene files. Scenes only contain GameObjects and all of their components. Everything else are usually seperate assets. Textures, meshes, animations, materials, GUISkins (which is a ScriptableObject btw) are saved as seperate assets.
Unity's asset format is actually quite veratile. Unity allows to store several assets within the same assetfile. See AssetDatabase.AddObjectToAsset. In the example they add an AnimationClip to a material asset (that doesn't make much sense but it's possible). When you import a FBX file, The importer creates sub-assets on the actual FBX file which for example contains the mesh data as $$anonymous$$esh.
You can use AssetDatabase.CreateAsset to create a seperate asset out of any serializable object (custom classes that inherit from System.Object don't work).
ps: If you have Unity pro, it's worth to enforce text-serialization. That way you can view all assets as Yaml text. It really helps to understand what and how Unity serializes stuff.
pps: So called "custom serializable classes", that are normal classes derived from System.Object but with System.Serializable attribute, can't be serialized on their own. They are actually serialized along with the referencing object which has to be a $$anonymous$$onoBehaviour or ScriptableObject. Unity serializes those classes per referencing variable and use the type of the variable. That's why custom classes are always serialized as the type of the referencing variable. So a subclass would become an instance of the base class if that's the type of the variable.
Also no "cross references". Unity treats those classes like structs, If two $$anonymous$$onoBehaviours reference the same custom class, each $$anonymous$$B will serialize it's own version. Since ScriptableObjects are real assets they have an instanceID so they are referenced correctly, but as said, they have to be stored as assets somewhere.
It's usually easier to simply use $$anonymous$$onoBehaviours which you attach to a single GameObject, but i've seen a lot people using ScriptableObjects. As far as i remember NGUI uses ScriptableObjects for most "assets". The actual GUI is created with prefabs, therefore $$anonymous$$onoBehaviours.
Thank you very much for your long and detailed answer, guess I learned something new today. I'll try the AssetDataBase approach, but if it deems too compliated or problematic I'll surely tend towards the $$anonymous$$onobehaviour approach. I'll report back when I have advanced.
Okay, this was wierd. After working around with my scripts, I actually managed to get the serilization working with my own approach. I didn't change the code structure or anything, but what I did is I changed out all my System.Object
with UnityEngine.Object
which apparently did the trick. Is my approach working because of this?
In the link you provided it also stated "Unity fully supports only types derived from UnityEngine.Object. A "normal" class (derived from System.Object) is not really serialized. Unity just stores the serializeable fields it can find within the class that is actually serialized (for example a $$anonymous$$onoBehaviour that holds the reference to an instance)."
Answer by gamesappstudio · Jul 12, 2017 at 03:43 PM
You can find plugin here (easy to implement ) assetstore.unity3d.com/en/#!/content/94493
Answers like these are unfortunate if the link dies, as I do not even know what plugin was being referenced to try and find an up to date link.