Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Trying to have game settings saved into a file, keeps getting serialization errors

Discussion in 'Editor & General Support' started by UNTL1, May 18, 2020.

  1. UNTL1

    UNTL1

    Joined:
    Mar 30, 2020
    Posts:
    71
    Hello. I'm building an Android game and the Options menu provides 3 different settings: background music volume, sound effects volume, and screen side placement of the shooting button. There is also the high score which should be saved.

    I tried creating a script building on an answer someone provided, but when I test it with the music volume slider it keeps returning errors about things not being serializable. At first it said "SerializationException: Type 'GameData' in Assembly 'Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable", so I tried adding "[System.Serializable]" above the class code as suggested somewhere, but now instead it returns the error "SerializationException: Type 'UnityEngine.MonoBehaviour' in Assembly 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable".

    Also, after the serialization error it also writes the error "IOException: Sharing violation on path C:\Users\UserName\AppData\LocalLow\CompanyName\AppName\save.dat".

    Here's the code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.Security.Cryptography;
    7.  
    8. [System.Serializable]
    9. public class GameData : MonoBehaviour
    10. {
    11.     public int highScore = 0;
    12.     public float musicVol = 1;
    13.     public float sfxVol = 1;
    14.     public int shootSide = 1;
    15.     // Start is called before the first frame update
    16.     private void Start()
    17.     {
    18.         LoadFile();
    19.     }
    20.     public void HighScoreValue(int highS)
    21.     {
    22.         highScore = highS;
    23.         SaveData();
    24.     }
    25.     public void MusicValue(float musicV)
    26.     {
    27.         musicVol = musicV;
    28.         SaveData();
    29.     }
    30.     public void SfxValue(float sfxV)
    31.     {
    32.         sfxVol = sfxV;
    33.         SaveData();
    34.     }
    35.     public void ShootSideValue(int shootS)
    36.     {
    37.         shootSide = shootS;
    38.         SaveData();
    39.     }
    40.     private void SaveData()
    41.     {
    42.         string destination = Application.persistentDataPath + "/save.dat";
    43.         FileStream file;
    44.  
    45.         if (File.Exists(destination))
    46.         {
    47.             file = File.OpenWrite(destination);
    48.         }
    49.         else
    50.         {
    51.             file = File.Create(destination);
    52.         }
    53.         GameData data = gameObject.AddComponent<GameData>();
    54.         BinaryFormatter formatter = new BinaryFormatter();
    55.         formatter.Serialize(file, data);
    56.         file.Close();
    57.     }
    58.     private void LoadFile()
    59.     {
    60.         string destination = Application.persistentDataPath + "/save.dat";
    61.         FileStream file;
    62.  
    63.         if (File.Exists(destination))
    64.         {
    65.             file = File.OpenRead(destination);
    66.         }
    67.         else
    68.         {
    69.             Debug.Log("File not found");
    70.             return;
    71.         }
    72.         BinaryFormatter formatter = new BinaryFormatter();
    73.         GameData data = (GameData)formatter.Deserialize(file);
    74.         file.Close();
    75.         highScore = data.highScore;
    76.         musicVol = data.musicVol;
    77.         sfxVol = data.sfxVol;
    78.         shootSide = data.shootSide;
    79.     }
    80. }
    Where is the issue? Thanks in advance.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,735
    MonoBehavior contains a bunch of other fields besides your custom data that you don't want to serialize. It's better to just create a small data class that you fully control:

    Code (CSharp):
    1. [Serializable]
    2. public class MyData {
    3.   public int highScore = 0;
    4.   public float musicVol = 1;
    5.   public float sfxVol = 1;
    6.   public int shootSide = 1;
    7. }
    Then just give your MonoBehaviour one of these as a field:
    Code (CSharp):
    1. public class GameData : MonoBehaviour
    2. {
    3.   public MyData data;
    4. ...
    and serialize/deserialize only that object.
     
  3. UNTL1

    UNTL1

    Joined:
    Mar 30, 2020
    Posts:
    71
    Thanks for replying. I tried dividing the code into two classes like this:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using System.Security.Cryptography;
    7.  
    8. public class GameData : MonoBehaviour
    9. {
    10.     public DataHandler data;
    11.     public int highScore;
    12.     public float musicVol;
    13.     public float sfxVol;
    14.     public int shootSide;
    15.     // Start is called before the first frame update
    16.     private void Start()
    17.     {
    18.         LoadFile();
    19.     }
    20.     public void HighScoreValue(int highS)
    21.     {
    22.         data.highScore = highS;
    23.         SaveData();
    24.     }
    25.     public void MusicValue(float musicV)
    26.     {
    27.         data.musicVol = musicV;
    28.         SaveData();
    29.     }
    30.     public void SfxValue(float sfxV)
    31.     {
    32.         data.sfxVol = sfxV;
    33.         SaveData();
    34.     }
    35.     public void ShootSideValue(int shootS)
    36.     {
    37.         data.shootSide = shootS;
    38.         SaveData();
    39.     }
    40.     private void SaveData()
    41.     {
    42.         string destination = Application.persistentDataPath + "/save.dat";
    43.         FileStream file;
    44.  
    45.         if (File.Exists(destination))
    46.         {
    47.             file = File.OpenWrite(destination);
    48.         }
    49.         else
    50.         {
    51.             file = File.Create(destination);
    52.         }
    53.         BinaryFormatter formatter = new BinaryFormatter();
    54.         formatter.Serialize(file, data);
    55.         file.Close();
    56.     }
    57.     private void LoadFile()
    58.     {
    59.         string destination = Application.persistentDataPath + "/save.dat";
    60.         FileStream file;
    61.  
    62.         if (File.Exists(destination))
    63.         {
    64.             file = File.OpenRead(destination);
    65.         }
    66.         else
    67.         {
    68.             Debug.Log("File not found");
    69.             return;
    70.         }
    71.         BinaryFormatter formatter = new BinaryFormatter();
    72.         DataHandler data = (DataHandler)formatter.Deserialize(file);
    73.         file.Close();
    74.         highScore = data.highScore;
    75.         musicVol = data.musicVol;
    76.         sfxVol = data.sfxVol;
    77.         shootSide = data.shootSide;
    78.     }
    79. }
    And:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [System.Serializable]
    6. public class DataHandler
    7. {
    8.     public int highScore = 0;
    9.     public float musicVol = 1;
    10.     public float sfxVol = 1;
    11.     public int shootSide = 1;
    12. }
    But I currently get the error as soon as the Editor player is started:
    "SerializationException: End of Stream encountered before parsing was completed".
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,735
    Well yeah you probably have an existing save file left over that doesn't match the new data type that it tried to load.
     
  5. UNTL1

    UNTL1

    Joined:
    Mar 30, 2020
    Posts:
    71
    I deleted the file, made a couple of other changes suggested elsewhere, and I thought it was working but actually it still wasn't accessing the file's data as the file.Close(); line was written in LoadFile() before the information requests. Now I moved that as I saw the data my sliders receive is zero when it shouldn't be, but then it again started writing the IOException error.

    What's causing this error?

    EDIT: Ok, I find the issue. First, it seems I did need to write file.Close(); right after copying its values to a new construct. Second, the data was held at the construct so the file wasn't need at the moment anymore anyway. And the issue was simply that I needed to use "Dynamic Float" in the slider inspector, as otherwise it just sent a predefined data which was 0.
     
    Last edited: May 18, 2020