TeamSirenix / odin-serializer

Fast, robust, powerful and extendible .NET serializer built for Unity
http://www.odininspector.com
Apache License 2.0
1.69k stars 193 forks source link

Abstract classes not serialized correctly on AOT Build #45

Open FelipeQuevici opened 3 years ago

FelipeQuevici commented 3 years ago

Unity version: 2020.1.7f1

Odin: 3.0.1.0

Windows 10.

I’m using SerializationUtility.SerializeValue to save the state of an object so I can retrieve it later, it does work fine in editor but does not work in IL2CPP builds.

Relevant bits of code:

SerializableEntity.cs

public class SerializableEntity : MonoBehaviour
{
        Dictionary<string, EntityParameter> _parametersDict = new Dictionary<string, EntityParameter>();

        public virtual byte[] SerializeParameters()
        {
            Assert.IsNotNull(_parametersDict);

            var paremters = _parametersDict.Values.ToArray();
            var serialized = SerializationUtility.SerializeValue<EntityParameter[]>(paremters, DataFormat.JSON);

            Debug.Log("Serialize " + name + " " + paremters.Length);
            foreach (var item in paremters)
            {
                Debug.Log(item.Name);
            }
            Debug.Log(System.Text.Encoding.UTF8.GetString(serialized));

            return serialized;
        }
    }

EntityParemeter.cs

[Serializable]
  public abstract class EntityParameter
  {
    public event Action OnChanged;

    public EntityParameter()
    {

    }

    protected void FireOnChanged()
    {
      OnChanged?.Invoke();
    }

    [SerializeField]
    private string _name;

    public string Name
    {
      get => _name;
    }

    [SerializeField]
    private string _label = string.Empty;

    public string Label
    {
      get => _label != string.Empty ? _label : _name;
    }

    public abstract object Value
    {
      get; set;
    }

    public EntityParameter(string name, string label = null)
    {
      _name = name;
      _label = label ?? string.Empty;
    }
  }

BoolParameter.cs

  [Serializable]
  public class BoolParameter : EntityParameter
  {
    [SerializeField]
    private bool _value;

    public override object Value
    {
      get => _value;
      set
      {
        if (value.GetType() != typeof(bool)) return;
        if (value.Equals(_value)) return;
        _value = (bool)value;
        FireOnChanged();
      }
    }

    public BoolParameter(string name, bool value, string label = null) : base(name, label)
    {
      _value = value;
    }
  }

AOTPreprocessor.cs

public class AOTPreprocessor  : IPreprocessBuildWithReport
{
    public int callbackOrder => 0;

    public void OnPreprocessBuild(BuildReport report)
    {
        List<System.Type> supportedTypes;
        if (AOTSupportUtilities.ScanProjectForSerializedTypes(out supportedTypes))
        {
            supportedTypes.Add(typeof(EntityParameter));
            supportedTypes.Add(typeof(BoolParameter));
            supportedTypes.Add(typeof(EntityParameter[]));
            supportedTypes.Add(typeof(int));
            supportedTypes.Add(typeof(float));
            supportedTypes.Add(typeof(string));
            supportedTypes.Add(typeof(bool));
            supportedTypes.Add(typeof(Vector2));
            supportedTypes.Add(typeof(Vector3));
            AOTSupportUtilities.GenerateDLL(Application.dataPath + "/Plugins/", "GeneratedAOT", supportedTypes);
            Debug.Log("generate AOT");
            Debug.Log(Application.dataPath + "/Plugins/");
        }
    }

I serialized it to JSON so I can see what is happening and in the editor, the log is this:

Serialize TerroristEditor(Clone) 1

_isFacingRight

{
"$id": 0,
"$type": "0|MRChip.LevelManager.EntityParameter[], Plugins",
"$rlength": 1,
"$rcontent": [{"$id": 1,"$type": "1|MRChip.LevelManager.BoolParameter, Plugins","_name": "_isFacingRight","_label": "Is Facing Right","_value": true}]
}

The exact same scene, with the exact same object in the IL2CPP build, results is this:

Serialize TerroristEditor(Clone) 1

_isFacingRight
{
    "$id": 0,
    "$type": "0|MRChip.LevelManager.EntityParameter[], Plugins"
}

The parameter ( “_isFacingRight”) is in the object, but it is not present on the serialization.