Hello, guys, my problem is that I have a enemies database using a scriptable object. The database is a dictionary and since unity does not serialize dictionaries, then I’m implementing ISerializationCallbackReceiver to serialize the dictionary, very simple using the exact same method the documentation about this interface tells you and it works…until I close the editor, look:
This is after changing the dictionary values which are split between 2 normal lists to use for serialization.
![alt text][1]
Here you can see that List<string> ED_Keys and List<EnemyType> ED_Valuesare being populated correctly with the dictionary contents when OnBeforeSerialize() is called. and yes they are set to [SerializeField] so they should be serialized so whenOnAfterDeserialize() is called the dictionary will be populated with its values again.
But once I come back, then List<string> ED_Keys and List<EnemyType> ED_Values comeback to their former state and dont serialized.
Any help, please?
Source Code:
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine.Serialization;
using UnityEngine;
using System.Linq;
public class EnemiesDataBase : ScriptableObject, ISerializationCallbackReceiver
{
[SerializeField]
public List<string> ED_Keys = new List<string>();
[SerializeField]
public List<EnemyType> ED_Values = new List<EnemyType>();
private Dictionary<string, EnemyType> enemies = new Dictionary<string, EnemyType>();
/// <summary>
///
/// </summary>
public Dictionary<string, EnemyType> Enemies
{
get { return enemies; }
}
public GameObject RetrieveEnemyReference(string enemyName, int level)
{
var enemy = new EnemyType();
if(enemies.TryGetValue(enemyName, out enemy))
{
for (int i = 0; i < enemy.Levels.Count; i++)
{
if(i == level)
{
return enemy.Levels*.gameObject;*
}
}
}
else
{
return null;
}
return null;
}
public void AddEnemyType(string enemyName)
{
enemies.Add(enemyName, new EnemyType());
}
public void RemoveEnemyType(string name)
{
enemies.Remove(name);
}
public void AddEnemyReference(string name)
{
enemies[name].Levels.Add(null);
}
public void AddEnemyReference(string name, GameObject enemy)
{
enemies[name].Levels.Add(enemy);
}
public void RemoveEnemyReference(string name, int level)
{
enemies[name].Levels.RemoveAt(level);
}
public void OnBeforeSerialize()
{
ED_Keys.Clear();
ED_Values.Clear();
foreach (var item in enemies)
{
ED_Keys.Add(item.Key);
ED_Values.Add(item.Value);
}
}
public void OnAfterDeserialize()
{
enemies.Clear();
for (int i = 0; i < ED_Keys.Count; i++)
{
enemies.Add(ED_Keys, ED_Values*);
_}
}
}*_
[System.Serializable]
public class EnemyType
{
[SerializeField]
private List levels = new List();
public List Levels
{
get { return levels; }
}
}
Source code for the custom inspector used to add and remove enemies to the dictionary of enemies:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;
[CustomEditor(typeof(EnemiesDataBase))]
public class Inspector_EnemiesDataBase : Editor
{
EnemiesDataBase dataBaseScript;
int enemiesCount;
Vector2 scrollPos = new Vector2();
List foldOuts = new List();
string inputName;
private void OnEnable()
{
dataBaseScript = (EnemiesDataBase)target;
enemiesCount = dataBaseScript.Enemies.Count;
foldOuts = new List();
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal();
inputName = EditorGUILayout.TextField(“New Type Name”, inputName);
if (GUILayout.Button(“Add”, GUILayout.Width(50)))
{
if (dataBaseScript.Enemies.ContainsKey(inputName))
{
if (EditorUtility.DisplayDialog(“Duplicate”, “An enemy type with the name " + inputName + " already exist.”, “Ok”))
{
}
}
else
{
dataBaseScript.AddEnemyType(inputName);
enemiesCount++;
foldOuts.Add(true);
if (dataBaseScript.Enemies[inputName].Levels.Count <= 0)
{
dataBaseScript.AddEnemyReference(inputName);
}
}
}
EditorGUILayout.EndHorizontal();
while (foldOuts.Count < enemiesCount)
{
foldOuts.Add(false);
}
EditorGUILayout.BeginHorizontal();
//Code kept for example on how to get a gui element to the right.
//GUILayout.Space(EditorGUIUtility.currentViewWidth - 40);
if (GUILayout.Button(“
”, GUILayout.Width(20)))
{
for (int i = 0; i < foldOuts.Count; i++)
{
foldOuts = false;
}
}
if (GUILayout.Button(“
”, GUILayout.Width(20)))
{
for (int i = 0; i < foldOuts.Count; i++)
{
foldOuts = true;
}
}
EditorGUILayout.EndHorizontal();
scrollPos = EditorGUILayout.BeginScrollView(scrollPos, “box”/, GUILayout.Height(200)/);
if (enemiesCount > 0)
{
int i = 0;
foreach (var key in dataBaseScript.Enemies.Keys.ToList())
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button(“”, “OL Minus”, GUILayout.Width(20)))
{
if (EditorUtility.DisplayDialog(“Delete Enemy Type”, “Are you sure you want to delete this enemy type?”, “Delete”, “Cancel”))
{
dataBaseScript.RemoveEnemyType(key);
enemiesCount–;
foldOuts.RemoveAt(i);
continue;
}
}
if (dataBaseScript.Enemies.Count > 0)
{
if (dataBaseScript.Enemies[key] != null)
{
GUILayout.Space(10);
foldOuts = EditorGUILayout.Foldout(foldOuts*, key, true);*
if (GUILayout.Button(“Add Level”, GUILayout.Width(75)))
{
dataBaseScript.AddEnemyReference(key, null);
}
}
}
EditorGUILayout.EndHorizontal();
if (dataBaseScript.Enemies.Count > 0)
{
if (foldOuts && dataBaseScript.Enemies[key] != null)
{
EditorGUILayout.BeginHorizontal();
GUILayout.Space(20);
EditorGUILayout.BeginVertical(“box”);
if (dataBaseScript.Enemies[key].Levels.Count < 2)
{
EditorGUI.BeginDisabledGroup(true);
GUILayout.Button(“”, “OL Minus”, GUILayout.Width(20));
EditorGUI.EndDisabledGroup();
}
else
{
if (GUILayout.Button(“”, “OL Minus”, GUILayout.Width(20)))
{
dataBaseScript.RemoveEnemyReference(key, dataBaseScript.Enemies[key].Levels.Count - 1);
}
}
for (int a = 0; a < dataBaseScript.Enemies[key].Levels.Count; a++)
{
if (dataBaseScript.Enemies.Count > 0)
{
dataBaseScript.Enemies[key].Levels[a] = (GameObject)EditorGUILayout.ObjectField("Lvl " + (a + 1).ToString(), dataBaseScript.Enemies[key].Levels[a], typeof(GameObject), false);
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndHorizontal();
}
}
i++;
}
}
else
{
EditorGUILayout.HelpBox(“No enemy types have been added.”, MessageType.Warning);
}
EditorGUILayout.EndScrollView();
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
[MenuItem(“Tools/Enemies DataBase”)]
public static void Init()
{
string[] lookFor = new string[] { “Assets/DataBase/Enemies” };
string[] result = AssetDatabase.FindAssets(“EnemiesDataBase”, lookFor);
if (result == null || result.Length <= 0)
{
ScriptableObjectUtility.CreateAsset(“Assets/DataBase/Enemies”);
}
else
{
Selection.activeObject = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(result[0]));
}
}
}
_*[1]: https://i.imgur.com/KytH5r9.jpg*_