Hello,
I’ve run into a bit of a wall with my current project. I’m storing stuff in a Vector2,Node Dictionary, wherein both Vector2 and Node are custom classes. I’ve read a lot of stuff about this in the past month. Solutions other people say work should be :
- Make Dictionary non generic by inheritance.
- Write a “Custom Dictionary” class
- Write the dictionary keys and values to arrays just before serialization starts and reload them right after.
- Override Serialization function in Type?
- Implement a custom serializer
If possible I would like to see if we can’t get them all to work. If you have any solution to this it would be awesome if you could post it.
I know I’m not the only one having these problems and it might be useful to collect working solutions here.
#Solution 1 does not work. Being generic is not the problem here, being unsorted and non-indexed is.
#Solution 2 is noticeably slower than the original, but if you’re not into micro-optimisation yet or if you just want it for a POC, here is the solution LightStriker kindly posted :
#Solution 3, Which atm for my Layer class looks like this :
private bool first = true;
public Layer()// base constructor
{
EditorApplication.playmodeStateChanged += Serialize;
}
public void OnEnable()
{
OnO();
}
public void Serialize()
{
if (EditorApplication.isPlayingOrWillChangePlaymode !EditorApplication.isPlaying)
{
CertainSerialize();
}
}
public void CertainSerialize()
{
Debug.Log("Saving this many nodes : " + nodes.Keys.Count);
if (nodes.Count == 0)
return;
SerializedNodeKeys = nodes.Keys.ToArray();
SerializedNodeValues = nodes.Values.ToArray();
}
public void OnO()
{
if (SerializedNodeKeys == null || SerializedNodeValues == null)
return;
Debug.Log("Loading this many nodes : " + SerializedNodeValues.Length);
nodes = new Dictionary<Vector2, Node>();
for (var i = 0; i < SerializedNodeValues.Length; i++)
{
nodes.Add(SerializedNodeKeys[i],SerializedNodeValues[i]);
}
}
Now so far it saves when the user presses the Start button in the editor and it loads the dictionary again both after the game starts and when the game stops. This way no data is lost and changes in play mode are being reverted. Now all we’re missing is a way to serialize the dictionaries just before the compiler wipes them after each compilation. This is a bit more tricky. The only working way I found is to add an editor script which atm needs handle each class that contains a dictionary individually. However, I can imagine this also working in a more generic manner, I just haven’t figured out how to get all instances of the dictionary yet. One could modify the dictionary to add itself to a static list on construction, but I haven’t tried this. Anyways, the working bit of code that detects that the compilation just started is this:
class MyAllPostprocessor : AssetPostprocessor
{
static void OnPostprocessAllAssets(
string[] importedAssets,
string[] deletedAssets,
string[] movedAssets,
string[] movedFromAssetPaths)
{
var coms = UnityEngine.Object.FindObjectsOfType<Layer>();
foreach (Layer com in coms)
{
Debug.Log("Compiler starts");
com.CertainSerialize(); //
}
}
}
It needs to be in the editor forlder. Once the compiler finishes. All your scripts that run in edit mode will OnEnable(); in which case you need to load your dics again.
As for
#Solution 4
http://w3mentor.com/learn/asp-dot-net-c-sharp/c-streams/example-of-onserializing-and-ondeserialized/
This means one can use [OnSerializing] and [OnDeserializing] on any function and use a StreamingContext parameter in that function to save and load stuff. However, they do not seem to work in mono 2.3 , at least not from MonoBehaviours or other UnityObjects (come to think of it , I haven’t tried it on normal ones yet).
#Solution 5
I’ve spent at least a week dabbling with custom serializers. And in the end I gained nothing. I started with the popular open source json serializer from whydoidoit.com , but while it is super easy to set up, it is far too heavy on the performance if you have lots of circular references like I do. Then I went on and tried to implement other serializers. The main problem here is that my plugin uses references to unityEngine.GameObject s and to other internal classes which one cannot edit. So all those excellent serializers like protobuff cannot be implemented. Others loose references to said types and then again others are simply far to slow.
So I’ll admit that I won’t try this again. It is probably possible to implement new serializers, but it’s far too big a project to start it just for some dictionaries.
So yeah, that’s my little journey through the exiting world of serialization in Unity. Any help would be appreciated ![]()