- Home /
Dictionaries don't serialize within scriptable objects
Hello. I've been working on the problem of dictionaries within scriptable objects. The most common solution of making a non-generic dictionary that implements ISerializationCallbackReceiver
doesn't actually seem to work for me. When I use the Asset menu to create a new ItemTemplate
(which is scriptableobject) and then start/close the Game view, because the deserializer sees nothing within the Lists within the SerializeableDictionary it wipes everything.
Here's the relevant code:
This is the ScriptableObject:
public class ItemTemplate : ScriptableObject
{
public SDict_StrStr tags_string;
public Dictionary_StrInt tags_int;
public int test;
public string nametest;
public ItemTemplate()
{
tags_string = new Dictionary_StrStr();
tags_int = new Dictionary_StrInt();
}
public void setTestTags()
{
tags_string.Add("name", "base herb");
tags_string.Add("description", "It's a base herb.");
tags_int.Add("basecost", 100);
tags_float.Add("volume", 5);
tags_float.Add("trait:base", 1);
tags_bool.Add("isPlant", true);
test = 8;
nametest = "base herb";
}
}
This is the SerializableDictionary:
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
// adapted from http://answers.unity3d.com/questions/460727/how-to-serialize-dictionary-with-unity-serializati.html
[Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField] public List<TKey> keys = new List<TKey>();
[SerializeField] public List<TValue> vals = new List<TValue>();
public SerializableDictionary() {
}
public void OnAfterDeserialize()
{
if (keys.Count != vals.Count)
{
throw new ArgumentException(string.Format("{0} things in keys and {1} things in vals. Mismatch."
, keys.Count, vals.Count));
}
for(int i = 0; i < keys.Count; i++)
{
Add(keys[i], vals[i]);
}
}
public void OnBeforeSerialize()
{
keys.Clear();
vals.Clear();
foreach (var kp in this)
{
keys.Add(kp.Key);
vals.Add(kp.Value);
}
}
}
[Serializable]
public class Dictionary_StrStr: SerializableDictionary<string, string>, ISerializationCallbackReceiver
{
}
[Serializable]
public class Dictionary_StrInt : SerializableDictionary<string, int>
{
}
The serializer does serialize primitive fields like int/str within ItemTemplate, so it's being serialized. Just not completely. How can I make the dictionaries within ItemTemplate be serialized?
Also, could the fact that I'm using a MenuItem to create ItemTemplates be the problem? The code is like such:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class MakeItemTemplate {
[MenuItem("Assets/Create/Item Template")]
public static ItemTemplate Create() {
string path = EditorUtility.SaveFilePanelInProject("Create new ItemTemplate",
"NewItemTemplate.asset",
"asset",
"Please select file name to save ItemTemplate as:");
ItemTemplate asset = ScriptableObject.CreateInstance<ItemTemplate>();
if (!string.IsNullOrEmpty(path))
{
asset.setTestTags();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
return asset;
}
return asset;
}
}