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. Dismiss Notice

Question Binaryformatter isn't working for save/load function

Discussion in 'Scripting' started by mehmeh111, Mar 1, 2021.

  1. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    I'm new to using unity and I've been trying to learn to use binaryformatter to save and load stats, but even though it says the save and load worked, the stats don't go to how they were supposed to be like
    Here's the code

    public class Save: MonoBehaviour
    {
    // Start is called before the first frame update
    private Player _player;
    private PlayerD dat;
    public void Awake()
    {
    _player = GameObject.FindObjectOfType<Player>();
    }
    public void Saving()
    {
    string path = Application.persistentDataPath + "/save.game";
    FileStream stream = new FileStream(path, FileMode.OpenOrCreate);
    try
    {
    BinaryFormatter bf = new BinaryFormatter();
    bf.Serialize(stream, _player.a);
    }
    catch (SerializationException)
    {
    Debug.Log("Save Error");
    }
    finally
    {
    Debug.Log("Reading");

    stream.Close();
    }
    }
    public void Load()
    {string path = Application.persistentDataPath + "/save.game";
    FileStream stream = new FileStream(path, FileMode.Open);
    try
    {
    BinaryFormatter bf = new BinaryFormatter();
    PlayerD data = bf.Deserialize(stream) as PlayerD;
    }
    catch (SerializationException)
    {
    Debug.LogError("Load error");
    }
    finally
    {
    Debug.Log("loading");
    stream.Close();
    }
    }
    }
     
  2. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    Code (CSharp):
    1. public class Save: MonoBehaviour
    2. {
    3. // Start is called before the first frame update
    4. private Player _player;
    5. private PlayerD dat;
    6. public void Awake()
    7. {
    8. _player = GameObject.FindObjectOfType<Player>();
    9. }
    10. public void Saving()
    11. {
    12. string path = Application.persistentDataPath + "/save.game";
    13. FileStream stream = new FileStream(path, FileMode.OpenOrCreate);
    14. try
    15. {
    16. BinaryFormatter bf = new BinaryFormatter();
    17. bf.Serialize(stream, _player.a);
    18. }
    19. catch (SerializationException)
    20. {
    21. Debug.Log("Save Error");
    22. }
    23. finally
    24. {
    25. Debug.Log("Reading");
    26.  
    27. stream.Close();
    28. }
    29. }
    30. public void Load()
    31. {string path = Application.persistentDataPath + "/save.game";
    32. FileStream stream = new FileStream(path, FileMode.Open);
    33. try
    34. {
    35. BinaryFormatter bf = new BinaryFormatter();
    36. PlayerD data = bf.Deserialize(stream) as PlayerD;
    37. }
    38. catch (SerializationException)
    39. {
    40. Debug.LogError("Load error");
    41. }
    42. finally
    43. {
    44. Debug.Log("loading");
    45. stream.Close();
    46. }
    47. }
    48. }
     
  3. Cyber-Dog

    Cyber-Dog

    Joined:
    Sep 12, 2018
    Posts:
    352
    You are serializing _player.a
    Is the field/property a type of PlayerD?
     
  4. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    yes, _player.a is a type of PlayerD (and PlayerD is serializable)
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
  6. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Good points from @Kurt-Dekker, whenever I save stuff like player data (health, lives, money, etc) I take extra steps to make it easily editable in JSON.

    On my current project I use binary to reduce the save size, it won't help secure your save(it will make it harder to modify to your liking though), but it has other benefits.

    edit: one good example for JSON is a config file, video setting and such.
     
    Last edited: Mar 2, 2021
    Joe-Censored likes this.
  7. Elango

    Elango

    Joined:
    Jan 27, 2016
    Posts:
    107
    Aside from the obvious advice about JSON instead of BinaryFormatter, the problem with the code is that you never load data back into "_player.a", instead you load it into a local variable that dies within the scope of the Load method. Also, use cast instead of "as". With "as" you will not be able to catch an error with invalid data.
    Code (CSharp):
    1. _player.a = (PlayerD)bf.Deserialize(stream);
     
    Bunny83 and SparrowGS like this.
  8. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    ok, so to sum it all up, I should try to use JSON for more secure and flexible save files instead of BF and my old code wasn't actually loading the file back into the game.
     
  9. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    I just made the jump from BinarySerializer to Newtonsoft JSON and I'm really glad I finally listened to @Kurt-Dekker 's advice.

    It was not a whole lot of work for me since the only change was the actual serialization process, my data transfer objects remain the same and Newtonsoft's JSON implementation will honor the ISerializable interface which is what I use mostly.

    I'm not a fan of the inflated file size increase but it makes debugging a thousand times easier and allowed me to quickly notice where I was serializing data wrong.

    Honestly switch to JSON it's super worth it!
     
    Kurt-Dekker likes this.
  10. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    ok so I tried switching to JSon but it now seems like the values aren't being actually saved?
    (not trying to save position currently, since that seems like an even bigger issue)

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    public class Stats : MonoBehaviour
    {
    PlayerD S = new PlayerD();
    private void Awake()
    {


    }
    public void save()
    {
    int W = S.wp;
    float speed = S.spe;
    PlayStats stat = new PlayStats
    {
    wp = W,
    spe=speed,
    };
    string json = JsonUtility.ToJson(stat);
    File.WriteAllText(Application.dataPath + "/savv.txt", json);
    }
    public void load()
    {
    if (File.Exists(Application.dataPath + "/savv.txt"))
    {
    Debug.Log(File.ReadAllText(Application.dataPath + "/savv.txt"));
    string saveFile = File.ReadAllText(Application.dataPath + "/savv.txt");
    PlayStats stat=JsonUtility.FromJson<PlayStats>(saveFile);
    S.wp = stat.wp;
    S.spe = stat.spe;
    Debug.Log(S.wp + " " + S.spe);
    Debug.Log(stat.wp + " " + stat.spe);
    }
    else
    {
    Debug.Log("No file");
    }
    }
    public class PlayStats
    {
    public int wp;
    public float spe;
    public Vector3 pos;
    }
    }

    and here's PlayerD

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    [System.Serializable]
    public class PlayerD
    {
    // Start is called before the first frame update
    public int wp;
    public float spe;
    public Vector3 pos;
    }
     
  11. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    also here's my player, even though it's not being called

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    public class Player: MonoBehaviour
    {
    public float[] playPos;
    public PlayerD a;
    public Vector3 position;
    CharacterController Cont;
    // Start is called before the first frame update
    void Awake() => Cont = GetComponent<CharacterController>();
    public bool IsGrounded;
    private void Start()
    {
    a.spe = 5f;
    a.wp = 1;
    }
    // Update is called once per frame
    void FixedUpdate()
    {
    float h = Input.GetAxis("Horizontal");
    float v = Input.GetAxis("Vertical");
    Vector3 dir = new Vector3(h,0, v);
    Vector3 mov = transform.TransformDirection(dir) * a.spe;
    IsGrounded = Cont.SimpleMove(mov);

    }
    void Update()
    {
    if (Input.GetKey(KeyCode.RightArrow))
    {
    a.wp += 1;
    }
    if (a.wp % 5 == 0)
    {
    a.spe += 1;
    }
    }
     
  12. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/

    To debug data problems and to help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run?
    - what are the values of the variables involved? Are they initialized?

    Knowing this information will help you reason about the behavior you are seeing.
     
    mehmeh111 likes this.
  13. mehmeh111

    mehmeh111

    Joined:
    Mar 1, 2021
    Posts:
    23
    ok, so the code overall seems to be running, but the stats on the json file are all shown at 0. The variables' initial values are 1 for WP and 5 for spe, but even those appear as 0 on the json