- Home /
Saving and Loading in Binary corrupted save help
My save data script works fine on standalone. It even works on android for the most part. Out of all my friends only me and my fiance have experienced data loading corruptions on our galaxy phones. Please look at my script and let me know if there is anything I can change to fix this. I've been researching for hours and looked at the device logs with debugs over and over with no concrete solution.
What happens is after closing the game and reopening it all saved integers go to 0, even the playable levels array integers which causes every level to appear unlocked but not playable essentially crashing and corrupting the save data.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
[System.Serializable]
public class SaveData {
public bool[] isPlayable;
public int[] highScore;
public int[] stars;
public int lives;
public int catnip;
public int badgeMatch;
public int badgeBreakable;
public int colorBombs;
public int columnBombs;
public int rowBombs;
public int freeSpins;
public bool adsEnabled;
}
public class GameData : MonoBehaviour {
public static GameData gameData;
public SaveData saveData;
void Awake ()
{
if (gameData == null)
{
DontDestroyOnLoad (this.gameObject);
gameData = this;
Debug.Log ("Created Save Script");
}
else
{
Destroy (this.gameObject);
}
Load ();
}
private void Start()
{
}
public void Save()
{
//Create Binary formatter to read binary files
BinaryFormatter formatter = new BinaryFormatter();
//Create a route from the program to the files(data stream)
FileStream file = File.Create(Application.persistentDataPath + "/save.dat");
//Create a copy of save data
SaveData data = new SaveData();
data = saveData;
//save data
formatter.Serialize(file, data);
//close data stream
file.Close();
Debug.Log ("Saved Game");
}
public void Load()
{
//Check if the save game file exists
if (File.Exists (Application.persistentDataPath + "/save.dat"))
{
//Create a Binary Formatter
BinaryFormatter formatter = new BinaryFormatter ();
FileStream file = File.Open (Application.persistentDataPath + "/save.dat", FileMode.Open);
saveData = formatter.Deserialize(file) as SaveData;
file.Close ();
Debug.Log ("Loaded File");
}
else
{
//saved variables
saveData = new SaveData ();
saveData.isPlayable = new bool[60];
saveData.stars = new int[60];
saveData.highScore = new int[60];
saveData.isPlayable [0] = true;
saveData.lives = new int ();
saveData.catnip = new int ();
saveData.badgeMatch = new int ();
saveData.badgeBreakable = new int ();
saveData.colorBombs = new int ();
saveData.columnBombs = new int ();
saveData.rowBombs = new int ();
saveData.freeSpins = new int ();
saveData.adsEnabled = new bool();
Debug.Log ("Created New Save Data");
}
}
private void OnApplicationQuit()
{
Save ();
}
private void OnDisable()
{
Save ();
}
Answer by toddisarockstar · Jan 08, 2019 at 08:01 AM
if your having problems here is a couple tools i made for myself that work every time which might be handy to convert ints to bytes and bytes to ints for saving. Getting comfortable handling and converting byte arrays yourself might be a good thing. this is a basic example for just combining the single ints. if you are interested in this approach i can repost more help to support your arrays and bools. Dont be afraid of byte arrays they don't bite. or maybe they do....but only 8 times. LOL.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;
public class Tools {
public static byte[] IntsToBytes(params int[] a){
// 4 bytes in a int
byte[] r = new byte[a.Length*4];
int i = 0;while (i<a.Length) {
byte[] b = BitConverter.GetBytes(a[i]);
int i2 = 0;while(i2<4){
r[(i*4)+i2]=b[i2];
i2++;}i++;}return r;}
public static int[] BytesToInts(byte[] b){
int[] r = new int[b.Length/4];
int i = 0;while (i<r.Length) {
r[i] = BitConverter.ToInt32(b,i*4);
i++;}return r;}
}
[System.Serializable]
public class SaveData {
public int lives;
public int catnip;
public int badgeMatch;
public int badgeBreakable;
public int colorBombs;
public int columnBombs;
public int rowBombs;
public int freeSpins;
public byte[] bytes {get{return Tools.IntsToBytes(
lives,catnip,badgeMatch,
badgeBreakable,colorBombs,
columnBombs,rowBombs,freeSpins);}}
public void loadme(byte[] b){
int[] ii = Tools.BytesToInts (b);
int i = 0;
lives = ii [i];i++;
catnip = ii [i];i++;
badgeMatch = ii [i];i++;
badgeBreakable = ii [i];i++;
colorBombs = ii [i];i++;
columnBombs = ii [i];i++;
rowBombs = ii [i];i++;
freeSpins = ii [i];i++;}
}
public class GameData : MonoBehaviour {
public byte[] testfile;
public SaveData saveData ;
public SaveData saveData2 ;
void Start(){
testfile = saveData.bytes;
//save and load testfile bytes to drive here;
saveData2 = new SaveData ();
saveData2.loadme (testfile);
}
}
is this as safe and protected as using binary saving? I'm very unfamiliar with byte saving plus if i change my save script that much I'm afraid current players would lose their saves from my current saved script. However if no one can tell me there is something wrong with my script I will definitely have to try this method or another regardless of it deleting current players save data, at least before I market it on a larger scale.
I'm hoping there is just a $$anonymous$$or change I could make like using Path.Combine ins$$anonymous$$d of File.Open but I couldn't figure out the right syntax to use it properly. I read that was a solution for a similar issue as $$anonymous$$e.
Hey, just wondering what you ever did to fix this? I'm having a very similar problem with my save data and I'm not sure what to do.
Well, using the BinaryFormatter is not really a great solution for save games in general. If you change anything in the layout of your data (adding / removing / rena$$anonymous$$g any fields) it would break any previously saved data. Using the BinaryFormatter does not even protect the data in any way from being altered by the user. It just adds a small layer of obfuscation. The binary format of the BinaryFormatter is a well known, well documented format. So with a little bit of efford you can change any value you stored with it. Apart from that the save format is very verbose. It actually contains the whole structure of your saved class. So one could simply read out all the data without knowing anything about your game.
It would be simpler to just use a more robust format like json. You can add a simple obfuscation at the end to make it harder to read by casual users. You can not protect data on the client side completely. Though of course you still have to be careful whenever you change something in the saved data format.