Hello,
I am looking for an answer to changing or generating data in the editor when optimizing objects. Before I get into details or my own research results, I would like to give a quick example that hopefully explains my issue.
Example: I have a MonoBehavior component that looks like this:
public class MyComponent : MonoBehavior {
[SerializeField]
private List<MyScriptableObject> data;
}
This component has a list of data objects (ScriptableObjects), which contain configurations. My designer can now easily choose which objects to add to this list and everything works fine. However, inside my code where I use the configurated data, I need to have a different collection, in this particular case a Dictionary.
How do I display the list in the inspector, but transform it into a different object for runtime purposes, but in the editor, explicitely not transforming it at runtime?
Research: Having made my own research, I found two solutions, being ISerializationCallbackReceiver and OnValidate. I am not going too much into detail what these things do and more into the problems that I have with them.
Let’s start with the easier one, OnValidate. This is a method that is being called every time that something in the inspector is being changed. Sounds perfect, since I want to do something when my designer alters data in the inspector of a component.
public class MyComponent : MonoBehavior {
[SerializeField]
private List<MyScriptableObject> data;
private Dictionary<MyKeyType, MyScriptableObject> organizedData;
public void OnValidate(){
organizedData.Clear();
foreach(var item in data){
// fill organizedData based on data.
}
}
}
The problem that I have here is that I don’t know if this works with serialization and if the data generated for organizedData will persist through sessions and at runtime. ISerializationCallbackReceiver does exactly that, it seems:
public class MyComponent : MonoBehavior, ISerializationCallbackReceiver {
[SerializeField]
private List<MyScriptableObject> data;
private Dictionary<MyKeyType, MyScriptableObject> organizedData;
public void OnBeforeSerialize(){}
public void OnAfterDeserialize()
{
organizedData = new Dictionary<MyKeyType, MyScriptableObject>();
for (int i = 0; i != data.Count; i++){
// fill dictionary
}
}
}
}
However, I do not understand why I have to write code into both directions. I only want to fill the dictionary, why do I have to implement OnBeforeSerialize(), too? It is a one-way transformation, isn’t it, so why would I want to transform the dictionary back into the list?
Additionally, in both solutions, I end up with more member per class that I need. At runtime, there should be no list with the data, only the dictionary. Is there any way around this, having only the members at runtime that one actually needs? I thought about using #UNITY_EDITOR for members that are only relevant in the editor, but I don’t know if at runtime, OnAfterDeserialize() is being called or something like that.
Are there better ways to transform members into different members in the editor, so that one ends up with optimized objects and not more members than necessary in the object?