Search Unity

Question Save system doesn't work in IL2CPP build but works in Mono Build

Discussion in 'Scripting' started by sowatnow, Sep 22, 2020.

  1. sowatnow

    sowatnow

    Joined:
    Jun 12, 2014
    Posts:
    309
    Hi guys,

    I came across this problem, where save system works in Scripting Backened Mono mode, but it doesn't work when i select IL2CPP mode.

    I tried to debug and found 2 errors in IL2CPP build when trying to save. I get this error when i try to do Manual Save.

    ERROR 1:
    ProtoException: No wire-value is mapped to the enum Nanawatai.Saving.SaveGameType.ManualSave at position 1

    ProtoBuf.ProtoWriter.ThrowEnumException (ProtoBuf.ProtoWriter writer, System.Object enumValue)
    ProtoBuf.Serializers.TypeSerializer.Write (System.Object value, ProtoBuf.ProtoWriter dest)
    ProtoBuf.Meta.RuntimeTypeModel.Serialize (Int32 key, System.Object value, ProtoBuf.ProtoWriter dest)
    ProtoBuf.Meta.TypeModel.SerializeCore (ProtoBuf.ProtoWriter writer, System.Object value)
    ProtoBuf.Meta.TypeModel.Serialize (System.IO.Stream dest, System.Object value, ProtoBuf.SerializationContext context)
    Nanawatai.Saving.ProtobufDataSerializer.WriteSaveGameHeader (System.IO.BinaryWriter writer, Nanawatai.Saving.SaveGame saveGame)
    Nanawatai.Saving.DataSerializer.Save (Nanawatai.Saving.SaveGame saveGame, Nanawatai.Saving.SaveState saveState)
    Nanawatai.Saving.SaveGameManager.SaveGame (Nanawatai.Saving.SaveGame saveGame, Nanawatai.Saving.SaveState saveState, UnityEngine.Texture2D screenshot)
    Nanawatai.Saving.SaveSystem.OnSaveGame (Nanawatai.Saving.SaveGame saveGame, System.String overrideTitle)
    Nanawatai.UI.UISaveGameMenu+<CreateNewSaveFile>c__Iterator0.MoveNext ()
    UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress)
    Nanawatai.Saving.DataSerializer:Save(SaveGame, SaveState)
    Nanawatai.Saving.SaveGameManager:SaveGame(SaveGame, SaveState, Texture2D)
    Nanawatai.Saving.SaveSystem:OnSaveGame(SaveGame, String)
    Nanawatai.UI.<CreateNewSaveFile>c__Iterator0:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)



    ERROR 2:
    Could not serialize SaveState at path: /storage/emulated/0/Android/data/co.codeasylum.CodeAsylumdc/files/Saves/1b3772025c9f4f78aa6ce247aaca4ba8/ManualSave_b0cb26279328445188f0274a7fdf0f06.sav

    Nanawatai.Saving.DataSerializer:Save(SaveGame, SaveState)
    Nanawatai.Saving.SaveGameManager:SaveGame(SaveGame, SaveState, Texture2D)
    Nanawatai.Saving.SaveSystem:OnSaveGame(SaveGame, String)
    Nanawatai.UI.<CreateNewSaveFile>c__Iterator0:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)


    I believe it has something to do with this code. I don't know what to change, because I dont' want to break the save system which works in Mono build.

    Code is here:

    Code (CSharp):
    1. using System;
    2. using ProtoBuf;
    3.  
    4. namespace Nanawatai.Saving
    5. {
    6.     [ProtoContract]
    7.     public enum SaveGameType
    8.     {
    9.         [ProtoEnum(Name = "ManualSave", Value = 0)]
    10.         ManualSave,
    11.         [ProtoEnum(Name = "AutoSave", Value = 1)]
    12.         AutoSave,
    13.         [ProtoEnum(Name = "QuickSave", Value = 2)]
    14.         QuickSave,
    15.         [ProtoEnum(Name = "Checkpoint", Value = 3)]
    16.         Checkpoint
    17.     }
    18.  
    19.     [Serializable]
    20.     [ProtoContract]
    21.     public class SaveGame : IComparable, ISaveGame
    22.     {
    23.         public const int VERSION = 1;
    24.  
    25.         [ProtoMember(1, IsRequired = true)]
    26.         private SaveGameType m_type;
    27.         [ProtoMember(2)]
    28.         private string m_sceneName;
    29.         [ProtoMember(3)]
    30.         private string m_title;
    31.         [ProtoMember(4)]
    32.         private bool m_streamingScene;
    33.         [ProtoMember(5)]
    34.         private DateTime m_timestamp;
    35.         [ProtoMember(6)]
    36.         public float m_timePlayed;
    37.         [ProtoMember(7)]
    38.         private string m_uniqueID;
    39.         [ProtoMember(8)]
    40.         private int m_version;
    41.  
    42.         [NonSerialized]
    43.         private string m_savePath;
    44.         [NonSerialized]
    45.         private string m_screenshotPath;
    46.  
    47.         public SaveGameType Type
    48.         {
    49.             get { return m_type; }
    50.             set { m_type = value; }
    51.         }
    52.  
    53.         public string SceneName
    54.         {
    55.             get { return m_sceneName; }
    56.             set { m_sceneName = value; }
    57.         }
    58.  
    59.         public string Title
    60.         {
    61.             get { return m_title; }
    62.             set { m_title = value; }
    63.         }
    64.  
    65.         public string UniqueID
    66.         {
    67.             get { return m_uniqueID; }
    68.             set { m_uniqueID = value; }
    69.         }
    70.  
    71.         public string SavePath
    72.         {
    73.             get { return m_savePath; }
    74.             set { m_savePath = value; }
    75.         }
    76.  
    77.         public string ScreenshotPath
    78.         {
    79.             get { return m_screenshotPath; }
    80.             set { m_screenshotPath = value; }
    81.         }
    82.  
    83.         public bool StreamingScene
    84.         {
    85.             get { return m_streamingScene; }
    86.             set { m_streamingScene = value; }
    87.         }
    88.  
    89.         public DateTime Timestamp
    90.         {
    91.             get { return m_timestamp; }
    92.             set { m_timestamp = value; }
    93.         }
    94.  
    95.         public float TimePlayed
    96.         {
    97.             get { return m_timePlayed; }
    98.             set { m_timePlayed = value; }
    99.         }
    100.  
    101.         public int Version
    102.         {
    103.             get { return m_version; }
    104.             set { m_version = value; }
    105.         }
    106.  
    107.         public SaveGame()
    108.         {
    109.             m_type = SaveGameType.ManualSave;
    110.             m_sceneName = null;
    111.             m_title = null;
    112.             m_savePath = null;
    113.             m_screenshotPath = null;
    114.             m_streamingScene = false;
    115.             m_timestamp = DateTime.Now;
    116.             m_timePlayed = 0.0f;
    117.             m_uniqueID = null;
    118.             m_version = VERSION;
    119.         }
    120.  
    121.         public int CompareTo(object obj)
    122.         {
    123.             if(obj is SaveGame)
    124.             {
    125.                 return m_timestamp.CompareTo(((SaveGame)obj).m_timestamp);
    126.             }
    127.          
    128.             return 0;
    129.         }
    130.  
    131.         public static SaveGame Create(CharacterProfile profile, SaveGameType saveGameType = SaveGameType.ManualSave)
    132.         {
    133.             return Create(profile, saveGameType.ToString(), saveGameType);
    134.         }
    135.  
    136.         public static SaveGame Create(CharacterProfile profile, string title, SaveGameType saveGameType = SaveGameType.ManualSave)
    137.         {
    138.             if(profile != null)
    139.             {
    140.                 SaveGame saveGame = new SaveGame();
    141.                 saveGame.Title = title;
    142.                 saveGame.Type = saveGameType;
    143.                 saveGame.UniqueID = SaveSystemUtils.GetUniqueID();
    144.                 saveGame.SavePath = SaveSystemUtils.GetSavePath(profile, saveGame.Type, saveGame.UniqueID);
    145.                 saveGame.ScreenshotPath = SaveSystemUtils.ChangeExtension(saveGame.SavePath, "png");
    146.                 return saveGame;
    147.             }
    148.  
    149.             return null;
    150.         }
    151.     }
    152. }
    Any help would be appreciated.

    Kind regards
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    One candidate to look at would be code stripping. The rules for code stripping in IL2CPP are quite different than Mono, and if functions are getting stripped, then things might not be serializable.

    Another place to check is more with protobuf itself, since that is not a Unity thing. Maybe check if there are limitations and/or expectations that this library has, such as it might not be IL2CPP compatible in the first place.

    In any case, plain old JSON save/load should work just fine, and for that I recommend the JSON .NET package from the Unity asset store.
     
  3. sowatnow

    sowatnow

    Joined:
    Jun 12, 2014
    Posts:
    309

    Thanks for your reply.

    I did try to disable code stripping in IL2CPP, however it did not fix the problem.

    I will try to find someone who can help me with this.
     
  4. Tech-Unity3d

    Tech-Unity3d

    Joined:
    Apr 25, 2016
    Posts:
    11
    As per your ProtoException, ProtobufDataSerializer received some exception, you have to check ProtobufDataSerializer .method.
     
  5. R1PFake

    R1PFake

    Joined:
    Aug 7, 2015
    Posts:
    542
    Try to remove the ProtoEnum attributes (they are optional) and see if you still get the same error.
     
  6. sowatnow

    sowatnow

    Joined:
    Jun 12, 2014
    Posts:
    309
    I tried the above changes, but didn't work. Maybe i didn't do it correctly. I
    Thanks
     
    Last edited: Sep 29, 2020