Search Unity

HELP Binary save system

Discussion in 'Scripting' started by SonGokuBg, May 7, 2020.

  1. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    PLEASE someone to give me a code or help me!!!
    Since 2 weeks I am trying different Binary systems from youtube tutorials and no one works for me :(

    Here is the last one:

    SaveSystem
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using UnityEngine;
    6.  
    7. public class SaveSystem : MonoBehaviour
    8. {
    9. #region Instance
    10.     private static SaveSystem instance;
    11.  
    12.     public static SaveSystem Instance
    13.     {
    14.         get
    15.         {
    16.             if (instance == null)
    17.             {
    18.                 instance = FindObjectOfType<SaveSystem>();
    19.                 if (instance == null)
    20.                 {
    21.                     instance = FindObjectOfType<SaveSystem>();
    22.  
    23.                     instance = new GameObject("Spawned SaveSystem", typeof(SaveSystem)).GetComponent<SaveSystem>();
    24.                 }
    25.             }
    26.  
    27.             return instance;
    28.         }
    29.  
    30.         set
    31.         {
    32.             instance = value;
    33.         }
    34.     }
    35.  
    36.  
    37.  
    38.  
    39.     #endregion
    40.    
    41.     [Header("Logic")]
    42.     [SerializeField] private string savefileName = "saves.s";
    43.  
    44.     private PlayerData data;
    45.     public  PlayerData Data { get => data; set => data = value; }
    46.     private BinaryFormatter formatter;
    47.  
    48.     void Awake ()
    49.     {
    50.         formatter = new BinaryFormatter();
    51.         DontDestroyOnLoad(this.gameObject);
    52.     }
    53.  
    54. public void SaveData()
    55.     {
    56.         if (Data == null)
    57.         {
    58.             Data = new PlayerData();
    59.  
    60.  
    61.             var file = new FileStream(savefileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    62.  
    63.             formatter.Serialize(file, Data);
    64.             file.Close();
    65.          
    66.             Debug.Log("Data Saved");
    67.            
    68.         }
    69.  
    70.     }
    71.  
    72.     public void LoadData()
    73.     {
    74.         try
    75.         {
    76.             var file = new FileStream(savefileName, FileMode.Open, FileAccess.Read);
    77.             Data = (PlayerData)formatter.Deserialize(file);
    78.             file.Close();
    79.  
    80.             Debug.Log("Data Loaded");
    81.        
    82.         }
    83.         catch
    84.         {
    85.             Debug.LogError("Save file not found in " + savefileName);
    86.             SaveData();
    87.         }
    88.  
    89.     }
    90. }
    91.  
    The data that I want to save and load:
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [System.Serializable]
    7. public class PlayerData
    8. {
    9.     public float coins { set; get; }
    10.     public  bool isLaserBought { set; get; }
    11. }
    12.  
    P.S. I want to be able to ''interact' with the data' to get and set it
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    What is it that "doesn't work" about it? What happens when you try to save it?
     
    matkoniecz likes this.
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,914
    I would highly recommend something human readable like JSON to make your save system. It's 10x easier to debug issues because you can just open the file and see at a glance what's being written to the file. With binary saves you have to pull out a hex editor to tell what's going on and even then it's really easy to miss things :confused:
     
    Kurt-Dekker, matkoniecz and StarManta like this.
  4. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    When I try to add value to the coins variable
    upload_2020-5-8_0-23-3.png

    i get upload_2020-5-8_0-25-30.png
     
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    The error happens in a script called GameManagerScript, which you haven't posted. What is going on around line 51 of GameManagerScript.cs?
     
  6. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.SceneManagement;
    4. using UnityEngine.UI;
    5. public class GameManagerScript : MonoBehaviour
    6. {
    7.     public AudioSource inGame;
    8.     public DataMono dataMono;
    9.    
    10.  
    11.     public GameObject playerObject;
    12.     public SaveSystem saveSystem;
    13.     public static PlayerMovement movement;
    14.  
    15.  
    16.     public GameObject DieUi;
    17.     [SerializeField]
    18.     public static bool isGameEnded;
    19.     public bool gameAlreadyEnded;
    20.     void Awake ()
    21.     {
    22.      // var saveSystem = SaveSystem.Instance;
    23.      
    24.  
    25.  
    26.         gameAlreadyEnded = false;
    27.         movement = playerObject.GetComponent<PlayerMovement>();
    28.         isGameEnded = false;
    29.         movement.enabled = false;
    30.     }
    31.  
    32.     void Update()
    33.     {
    34.      //   var saveSystem = SaveSystem.Instance;
    35.         if (isGameEnded == true)
    36.         {
    37.             if(gameAlreadyEnded == false)
    38.             {
    39.              
    40.             EndGame();
    41.                 gameAlreadyEnded = true;
    42.             }
    43.         }
    44.     }
    45.  
    46.     public void EndGame()
    47.     {
    48.  
    49.            var saveSystem = SaveSystem.Instance;
    50.        
    51.         saveSystem.Data.coins += 2f;
    52.         //SaveSystem.Instance.Data.isLaserBought = true;
    53.  
    54.         saveSystem.SaveData();
    55.         saveSystem.LoadData();
    56.         Debug.Log(saveSystem.Data.coins);
    57.         inGame.Stop();
    58.         Debug.Log("END GAME");
    59.         movement.enabled = false;
    60.  
    61.        
    62.    Invoke("LoadDieUi", 1.5f);
    63.      
    64.     }
    65.  
    66.     void LoadDieUi ()
    67.     {
    68.         DieUi.SetActive(true);
    69.     }
    70.  
    71. }
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    You try and access saveSystem.Data before you save or load it, so saveSystem.Data is null. Maybe you should be calling saveSystem.LoadData in GameManagerScript's Awake or Start?
     
  8. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I tried like that
    Code (CSharp):
    1.    
    2.         saveSystem.LoadData();
    3.  
    4.         saveSystem.Data.coins += 2f;
    5.         saveSystem.SaveData();
    6.         Debug.Log(saveSystem.Data.coins);
    but it doesn't really save and increase the coins
     
  9. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Please someone :(
     
  10. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    no one use binary ?
     
  11. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    You're not doing yourself any favors with how little information you are providing. You say you ran the above and it "doesn't really save". Well what does it "really" do specifically? LoadData has Debug lines, so which one was output to the console?
     
    Suddoha likes this.
  12. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    You complicated it too much for yourself by having everything in different scripts.

    If you are just starting to learn try saving a simple file with methods and classes all from the same script
     
  13. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    The coins that I am increasing doesn't save. I know that because the Debug.Log always show the same amount of coins.
     
  14. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I am doing it with tutorials exactly the same as the video. No one works
     
  15. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    try this code and let me know

    put it in a new script called savetest

    you can just use the inspector to mess around with it

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using UnityEngine;
    7.  
    8. public class savetest : MonoBehaviour
    9. {
    10.     public BinaryFormatter bf = new BinaryFormatter();
    11.     public FileStream fs;
    12.  
    13.     public int Coins;
    14.     public bool TriggerSave;
    15.     public bool TriggerLoad;
    16.  
    17.     [Serializable]
    18.     public class SaveClass
    19.     {
    20.         public int Save_Coins;
    21.     }
    22.  
    23.     public void SaveMethod()
    24.     {
    25.  
    26.         if (Directory.Exists(Application.dataPath + "/Save/") == false)
    27.         {
    28.             Debug.Log("creating dir");
    29.             Directory.CreateDirectory(Application.dataPath + "/Save/");
    30.         }
    31.  
    32.         fs = File.Create(Application.dataPath + "/Save/saved.coins");
    33.  
    34.         sv = new SaveClass();
    35.         sv.Save_Coins = Coins;
    36.         bf.Serialize(fs, sv);
    37.  
    38.         fs.Close();
    39.    
    40.     }
    41.  
    42.  
    43.     public void LoadMethod()
    44.     {
    45.  
    46.         if (File.Exists(Application.dataPath + "/Save/saved.coins") == true)
    47.         {
    48.  
    49.             fs = File.Open(Application.dataPath + "/Save/saved.coins", FileMode.Open);
    50.             sv = (SaveClass)bf.Deserialize(fs);
    51.             Coins = sv.Save_Coins;
    52.             fs.Close();
    53.  
    54.  
    55.         }
    56.  
    57.  
    58.     }
    59.  
    60.     void Update()
    61.     {
    62.  
    63.         if (TriggerSave == true)
    64.         {
    65.             SaveMethod();
    66.             TriggerSave = false;
    67.         }
    68.         if (TriggerLoad == true)
    69.         {
    70.             LoadMethod();
    71.             TriggerLoad = false;
    72.         }
    73.     }
    74.  
    75. }
     
    Last edited: May 13, 2020
  16. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Thank you for the reply. I get an error error CS0103: The name 'sv' does not exist in the current context
     
    brigas likes this.
  17. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
  18. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    sorry forgot this, replace the code with this

    Code (CSharp):
    1.     using System;
    2.     using System.Collections;
    3.     using System.Collections.Generic;
    4.     using System.IO;
    5.     using System.Runtime.Serialization.Formatters.Binary;
    6.     using UnityEngine;
    7.    
    8.     public class savetest : MonoBehaviour
    9.     {
    10.         public BinaryFormatter bf = new BinaryFormatter();
    11.         public FileStream fs;
    12.         public SaveClass sv;
    13.    
    14.         public int Coins;
    15.         public bool TriggerSave;
    16.         public bool TriggerLoad;
    17.    
    18.         [Serializable]
    19.         public class SaveClass
    20.         {
    21.             public int Save_Coins;
    22.         }
    23.    
    24.         public void SaveMethod()
    25.         {
    26.    
    27.             if (Directory.Exists(Application.dataPath + "/Save/") == false)
    28.             {
    29.                 Debug.Log("creating dir");
    30.                 Directory.CreateDirectory(Application.dataPath + "/Save/");
    31.             }
    32.    
    33.             fs = File.Create(Application.dataPath + "/Save/saved.coins");
    34.    
    35.             sv = new SaveClass();
    36.             sv.Save_Coins = Coins;
    37.             bf.Serialize(fs, sv);
    38.    
    39.             fs.Close();
    40.      
    41.         }
    42.    
    43.    
    44.         public void LoadMethod()
    45.         {
    46.    
    47.             if (File.Exists(Application.dataPath + "/Save/saved.coins") == true)
    48.             {
    49.    
    50.                 fs = File.Open(Application.dataPath + "/Save/saved.coins", FileMode.Open);
    51.                 sv = (SaveClass)bf.Deserialize(fs);
    52.                 Coins = sv.Save_Coins;
    53.                 fs.Close();
    54.    
    55.    
    56.             }
    57.    
    58.    
    59.         }
    60.    
    61.         void Update()
    62.         {
    63.    
    64.             if (TriggerSave == true)
    65.             {
    66.                 SaveMethod();
    67.                 TriggerSave = false;
    68.             }
    69.             if (TriggerLoad == true)
    70.             {
    71.                 LoadMethod();
    72.                 TriggerLoad = false;
    73.             }
    74.         }
    75.    
    76.     }
    77.  
     
    SonGokuBg likes this.
  19. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Awesome, it works! But I have 2 questions.
    1. How can I add more variables to save like: public bool isLaserBought ?
    2. Why you are using TriggerLoad and TriggerSave when you can call the methods directly?
     
  20. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    1) add them in your declarations and in the save class
    Code (CSharp):
    1.  
    2. public bool LaserBought;
    3. [Serializable]
    4.         public class SaveClass
    5.         {
    6.             public int Save_Coins;
    7. public bool Save_LaserBought;
    8.         }
    dont forget that you have to include them in the save and load part like this
    Code (CSharp):
    1.  sv = new SaveClass();
    2.             sv.Save_Coins = Coins;
    3.             sv.Save_LaserBought = LaserBought;
    4.             bf.Serialize(fs, sv);
    5.  
    6.             fs.Close();
    Code (CSharp):
    1.                 sv = (SaveClass)bf.Deserialize(fs);
    2.                 Coins = sv.Save_Coins;
    3.                 LaserBought = sv.Save_LaserBought;
    4.                 fs.Close();
    2) I made those triggers so you could click the bools on the inspector to help you learn how it works
     
  21. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Thank You, but there is a very bad bug. When I close the Unity editor all save progress is being lost like the file doesn't exist
     
  22. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    This should be using Application.persistentDataPath, not Application.dataPath.

    (Not sure if that's the only issue but it's definitely AN issue.)
     
  23. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    application.datapath should be fine on pc, its the path to the assets folder

    You can change it anyway to anything you like, for now go check on your project folder under assets/save and see if you have the file there
     
  24. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    ....which you shouldn't be saving game data to?

    As mentioned, it may not be the only problem, because most likely it should still at least work. But, it's still a bad idea.
     
  25. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    Its just an easy directory to debug hes having trouble as it is, if you start sending his saves to appdata folders it will just create more confusion
     
  26. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    switched to Application.persistentDataPath, but still the same problem
     
  27. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I have this upload_2020-5-13_21-1-29.png
     
  28. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    looks like the file is there

    describe what you are doing that makes you think the save is not there
     
  29. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    looking at the inspector coins and the debug.log
     
  30. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    so what happens when you press triggerload
     
  31. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    when I restart unity it's 0
     
  32. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    did you change the code?
     
  33. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Hmm, it works now...I will test again tomorrow. Can I add array in the same way that I added bool? Hope you will be here tomorrow
     
  34. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    good

    depends on what array, array of int yes, array of vector3 no

    what is important is that you understand what is going on in the code
     
  35. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    array of materials? I still don't understand what was wrong with the last binary systems I tried
     
  36. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    It was just confusing at least for me, but your main mistake was that you were saving empty files

    if you realize in your original save method you create a new save but you never input which values you want to save into it.

    Code (CSharp):
    1. public void SaveData()
    2.     {
    3.         if (Data == null)
    4.         {
    5.             Data = new PlayerData();
    6.             var file = new FileStream(savefileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
    7.             formatter.Serialize(file, Data);
    8.             file.Close();
    9.        
    10.             Debug.Log("Data Saved");
    11.          
    12.         }
    13.     }
    you create new player data, then you create new file, then you save the file then you close the file, meawhile you didnt put anything inside the file, at least thats what im seeing, the rest of the code is filled with ( try, get, set,catch, static const and findobjects, stuff that can be good if you are doing higher lvl stuff but in this case for learning it would be best to just keep the code clean and simple)
     
  37. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I don't know .. When you type in google ''Unity binary save system'' I tried all of them, but no one worked for me.. Did you make that from scratch for me?
     
  38. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    I also have a save system like this in my game so I copied it to here and made it as simple as possible
     
    SonGokuBg likes this.
  39. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Can you be my teacher? :D
     
  40. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    hehe I can help you if you have more questions about save =)
     
  41. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I just deleted my prefab folder :(((((
     
  42. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Oh, I restored it from the trash box
     
  43. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I started getting error when I try this from another script
    Code (CSharp):
    1.     void Awake ()
    2.     {
    3.        saveSystem.TriggerLoad = true;
    4.     }
    I only changed the script name and the Coins from int to float
    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.IO;
    5. using System.Runtime.Serialization.Formatters.Binary;
    6. using UnityEngine;
    7.  
    8. public class SaveSystem : MonoBehaviour
    9. {
    10.     public BinaryFormatter bf = new BinaryFormatter();
    11.     public FileStream fs;
    12.     public SaveClass sv;
    13.  
    14.     public float Coins;
    15.     public bool LaserBought;
    16.  
    17.     public bool TriggerSave;
    18.     public bool TriggerLoad;
    19.  
    20.     [Serializable]
    21.     public class SaveClass
    22.     {
    23.         public float Save_Coins;
    24.         public bool Save_LaserBought;
    25.  
    26.     }
    27.  
    28.     public void SaveMethod()
    29.     {
    30.  
    31.         if (Directory.Exists(Application.persistentDataPath + "/Save/") == false)
    32.         {
    33.             Debug.Log("creating dir");
    34.             Directory.CreateDirectory(Application.persistentDataPath + "/Save/");
    35.         }
    36.  
    37.         fs = File.Create(Application.persistentDataPath + "/Save/saved.coins");
    38.  
    39.         sv = new SaveClass();
    40.         sv.Save_Coins = Coins;
    41.         sv.Save_LaserBought = LaserBought;
    42.         bf.Serialize(fs, sv);
    43.  
    44.         fs.Close();
    45.  
    46.     }
    47.  
    48.  
    49.     public void LoadMethod()
    50.     {
    51.  
    52.         if (File.Exists(Application.persistentDataPath + "/Save/saved.coins") == true)
    53.         {
    54.  
    55.             fs = File.Open(Application.persistentDataPath + "/Save/saved.coins", FileMode.Open);
    56.             sv = (SaveClass)bf.Deserialize(fs);
    57.  
    58.             Coins = sv.Save_Coins;
    59.             LaserBought = sv.Save_LaserBought;
    60.             Debug.Log(Coins);
    61.             Debug.Log(LaserBought);
    62.  
    63.             fs.Close();
    64.  
    65.  
    66.         }
    67.  
    68.  
    69.     }
    70.  
    71.     void Update()
    72.     {
    73.  
    74.         if (TriggerSave == true)
    75.         {
    76.             SaveMethod();
    77.             TriggerSave = false;
    78.         }
    79.         if (TriggerLoad == true)
    80.         {
    81.             LoadMethod();
    82.             TriggerLoad = false;
    83.         }
    84.     }
    85.  
    86. }
    87.  
    upload_2020-5-14_16-40-38.png
     
  44. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    try switching back to application.datapath or a path on your computer that doesnt need admin access, and also make sure that you change the name also on the script file name, and make sure to not have the folder open in windows while you save.

    When you change things in your project you need to delete your old saves, you cant load old saves created with different code.
     
  45. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    upload_2020-5-14_17-56-3.png
     
  46. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
  47. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    you need to correct the capitalizations

    Code (CSharp):
    1. Application.dataPath
     
  48. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    Do you have idea why the text is not updating? The Debug.Log in my LoadMethod shows the correct amount of Coins
    Code (CSharp):
    1. using TMPro;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class AvailableCoins : MonoBehaviour
    6. {
    7.     public SaveSystem saveSystem;
    8.     public TextMeshProUGUI availableCoins;
    9.  
    10.     void Awake ()
    11.     {
    12.        saveSystem.TriggerLoad = true;
    13.  
    14.  
    15.        availableCoins.text = saveSystem.Coins.ToString("F1");
    16.     }
    17. }
    18.  
    no errors
     
  49. brigas

    brigas

    Joined:
    Oct 4, 2014
    Posts:
    522
    yes, the trigger load only works on update so you are setting the text before loading

    now is a good time to change trigger load just to
    Code (CSharp):
    1. saveSystem.LoadMethod();
     
  50. SonGokuBg

    SonGokuBg

    Joined:
    Apr 16, 2020
    Posts:
    146
    I don't know how I didn't try that....