Search code examples
c#unity-game-engine

Modify ScriptableObject through editor script


I have TranslationData : ScriptableObject that stores all translations and custom inspector view for TranslatableText

enter image description here

There from this custom inspector view i should modify linked TranslationData, but i can't resave this asset.

I try this (look like a bad practice):

EditorUtility.SetDirty(translationData);
// Modifying value of ScriptableObject asset
translationData.data[textField.value] = new TranslationData.Node();
// Saving (i think)
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

And this works for recompiles, but not for restarting unity or building app

Is there any way to update SerializedProperty.objectReferenceValue and save it?


Solution

  • The problem was using Dictionary, unity didn't serialize field with that type.

    EDIT:

    So unity can't serialize Dictionary (like almost any generic non-primitive types).

    There 2 tricks to make Dictionary serializable:

    1. Copy all keys and values into custom List<TKey> keys and List<TValue> values before serialization with ISerializationCallbackReceiver
    public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
    {
        [SerializeField]
        public List<TKey> keys = new();
        [SerializeField]
        public List<TValue> values = new();
        public void OnBeforeSerialize()
        {
            keys = Keys.ToList();
            values = Values.ToList();
        }
        public void OnAfterDeserialize()
        {
            Clear();
            for (var i = 0; i < keys.Count; i++)
                Add(keys[i], values[i]);
        }
    }
    
    1. Create a non-generic type, because Unity serializer can't handle generics for some reason:
    // Node type also Serializable
    [Serializable]
    public class SDictionaryOfStringAndNode : SerializableDictionary<string, Node> { };
    [SerializeField]
    public SDictionaryOfStringAndNode data = new();
    

    Be cereful with recursive serialization! max recursion depth that unity can handle is 10, so any tree-structures better to serialize without any recursion (by creating {path: object, ..} dict inside OnBeforeSerialize for example)