- Home /
Serialization depth limit 7 exceeded
To later simplify some things for my current project I am first creating a custom EditorWindow tool. Since I want to be able to save its current state (to make it survive entering/leaving play-mode or restarting Unity without always resetting) I have created a settings-object that gets saved and is supposed to hold all the data.
However, it seems that my current implementation results in the warning "Serialization depth limit 7 exceeded". The data structure looks like this: (Hierarchy on the left for inheritance, arrows for references to instances of a type)
Basically when opening the TilesetEditor it loads the TilesetEditorSettings object. In there is a list of 1-n TilesetEditorPanels which each have their own few references to some PanelElements (e.g. Grid, Texture, Zoom). Since some PanelEements need to access data from other elements (e.g. Texture needs to be scaled according to Zoom) they have a reference to their containing Panel (lower upward-travelling arrow). Also it will later be necessary to acess other Panels (e.g. to check if a drag started in a different Panel than the one it ended in) which is why there is a referene to the TilesetEditor in order to get to the Settings (upper upward-travelling arrow).
From my understanding of the serializaton manual page those upward-travelling references are the problem, since they lead to endless loops when deserializing (which then get interrupted by the warning).
The question is how to best resolve this.
I suppose one way would be to derive my TilesetEditorElement class from ScriptableObject as well, since apparently references to those types can be resolved properly. The downsize though would be that apart from the Settings object I'd also need to save all objects which then derive from TilesetEditorElement into an Assets folder, which could get a bit messy. Also it means that I couldnt use a normal constructor with parameters anymore so I'd need to use the ScriptableObject.Instantiate method and a custom Init method to set up the parameters.
Or is there maybe a better approach?
Answer by Bunny83 · Feb 03, 2018 at 10:59 PM
Well, the solution is to flatten the hierarchy of your TilesetEditorElements. That means yout TilesetEditorSettings class would simple store a linear list of TilesetEditorElements which will include all elements in a linear list. You can still use your current setup, just make sure all those references are not serialized. Instead your classes can implement the "ISerializationCallbackReceiver" interface which allows you to pre / post process your class instance when serialized / deserialized. So you can still handle your objects in a hierarchical structure at "runtime" which is not serialized. Inside "OnBeforeSerialize" you will actually iterate your whole tree structure and place each TilesetEditorElement in a linear List which will be serialized. Of course you also need to add a way to restore the parent element for each item. For this you can use a simple integer variable which stores the index into your linear list.
In "OnAfterDeserialize" you just have to reverse the process. Iterate through the list and restore the actual references between the classes.
The back reference to the editor shouldn't be serialized at all. As i have understood your setup the TilesetEditorSettings class is meant to be stored as asset. However an editorwindow shouldn't be stored in an asset and therefore can't be referenced from your TilesetEditorSettings asset. Since you usually only have one TilesetEditor window open you may use a static singleton reference for the editor window reference if you need it.
ps: If you think implementing the ISerializationCallbackReceiver is too complicated you can also make your TilesetEditorElement a ScriptableObject as well. Of course that would mean you have to save those manually into an asset file. $$anonymous$$eep in $$anonymous$$d that you can save multiple objects / assets into the same asset file by using AddObjectToAsset.
I can't really go more into details here as it highly depends on the actual usecase, what data those classes will hold and how many cross-referencing variables you might have.
would a list of type TilesetEditorElement actually work? in the manual I linked above it says "No support for polymorphism"...
I had the same thought about the back reference to the editor. When I made it [NonSerialized] for a test before, Unity only complained about the second back reference so I think it should work.
in case I'd use ScriptableObjects, can objects added to assets via AddObjectToAsset still be deleted normally? since the number of Panels should be able to be changed I'd add/delete Assets for them accordingly.
Yes, you are right, inheritance doesn't work for custom serializable classes. So you would need either seperate lists for each type or use ScriptableObjects.
Yes, you should be able to delete single instances. However note that Unity's asset format doesn't have any hierarchy within the file. In the inspector one asset will represent the main asset and the others will show up as child assets. Currently there's no way to control which asses is used as main asset. However if you set the hideFlags of the child assets so the are not visible and only one asset in the file is actually visible, Unity should show that asset when selecting the file.
Your answer
Follow this Question
Related Questions
Organizing Recursive EditorGUI elements 1 Answer
Save ScriptableObject On Unity Application Quit? 1 Answer
OnSerialize event 2 Answers
Referencing / linking a .asset / .prefab file in another .asset / .prefab file programmatically. 2 Answers
Why doesn't my ScriptableObject save using a custom EditorWindow? 3 Answers