Hi there, I save my meshes data using Binary format. I can save and load using Binary format. But I saw there a little issue in saving step. I can save then load it back. But when I launch the game and I add new variables into “MeshData” class and I save it then when I load and I see that my previous data erased in the saved file. Because the file is overwriting into existing file.
SHORTLY:
Saving the File Without Deleting What’s Already There. I do not want to overwrite the whole file. I just want to add a new line/data into existing file without erase the previous data. How to add a new data into existing Binary file?
Code to SAVE and LOAD Mesh Data:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
[System.Serializable]
public class MeshData
{
public List<float> vertices;
public List<float> uvs;
public List<float> normals;
public List<int> triangles;
}
[System.Serializable]
public class MeshDatabase
{
public MeshData[] meshDatas;
}
public class GetMeshData : MonoBehaviour
{
public MeshData[] meshDatas;
public MeshDatabase meshDatabase;
public BinaryFormatter binaryFormatter;
public FileStream fileStream;
void Update()
{
if (Input.GetKeyDown(KeyCode.S))
{
Save();
Debug.Log("SAVED");
}
if (Input.GetKeyDown(KeyCode.L))
{
Load();
Debug.Log("LOADED");
}
}
public void Save()
{
binaryFormatter = new BinaryFormatter();
fileStream = File.Create(Application.dataPath + "/StreamingAssets/Mesh.dat");
binaryFormatter.Serialize(fileStream, meshDatabase);
fileStream.Close();
}
public void Load()
{
if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
{
binaryFormatter = new BinaryFormatter();
fileStream = File.Open(Application.dataPath + "/StreamingAssets/Mesh.dat", FileMode.Open);
meshDatabase = (MeshDatabase)binaryFormatter.Deserialize(fileStream);
fileStream.Close();
}
}
}
That kind of binary stream is lacking any kind of formatting, so you need to preserve the previous shape of the datagram if you want to read it.
However, you really shouldn’t be using this format:
Don’t use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.
If you insist on using it then you need to implement your own versioning system, so that you write (perhaps) a version integer or string out that lets your code read it with the correct shape data.
This also means you must maintain separate structures for every possible previous version of the data structure you wish to support reaching back in time.
Thanks for respond Kurt. I did not know Binary stream was a secure. But I saw at this video tutorial
that Binary is a most secure. Nobody can read the binary file because it is converting to unreadable state. And also I took a look at Binary file and I could not read because of encryption. Even I saw that MINECRAFT use Binary format to save data. Still I did not understand. Also I wanted to learn use JSON to save and load data for mySQL database. But my game is not an online for right now. I think to add online later and I think that there a little things to do before to use the JSON. I will pay attention to your advice.
So I have a few question.
1) can I add a new line into JSON file without erasing the previous data/lines? Or I can not do that with this format too? 2) Is there not another easy way to add a new line without lost the previous data? Or there is not, then I need to keep the previous data then, add a new data and save these whole data again into file, Yes, like this ?
You clearly have not met any of the 12-year-olds who regularly break security by reading binary files. There is nothing different from a binary file and a JSON file. If you doubt me, just use the xxd utility (a Posix tool) and hex dump your binary and there will be all your data.
There is. You can write it to separate files. You can write it as separate chunks end to end to end. But if you change any of the underlying structure of the chunks, it won’t be trivial to read back in.
This is just how unstructured binary data works. It’s just a bag of bytes without any clue as to what is what. The “clue” comes in the shape of your program’s structure, and when you change it, well, it no longer matches!
there arent many of those 12 years old doing it, especially not for simple savegame editing. those can do it, deserve to do it but binary savegame is the fastest and easiest way as there is no parsing, also easiest to encrypt if you are worried. json xml are simply readable to anyone with a notepad and slow af. this is just a microsoft crap and we are surprised why do we need 16 cores 5ghz pc-s that should run on a 200mhz celeron
There is. You can write it to separate files. You can write it as separate chunks end to end to end. But if you change any of the underlying structure of the chunks, it won’t be trivial to read back in.
This is just how unstructured binary data works. It’s just a bag of bytes without any clue as to what is what. The “clue” comes in the shape of your program’s structure, and when you change it, well, it no longer matches![/QUOTE]
Oh, I did not know about 12 years old child hacked binary files and succeed to read binary file. This was a really import information, thanks for gave a such an important info. I don’t doubt. Then I need to use JSON later.
You said that JSON is more secure, right? If I am wrong, then you say me, I understood that JSON is more secure than Binary, am I right?
You mean by to save in different files? Create different files for each chunks and load it back and change something or add then save it, is it? And still this means that I need to load all data variables back then save these again?
I divide save files. I load variables back with variables and I adding or changing something then I need to save all previous and new variables into a file, right?
Below I load variables back into as variable and (removing or adding new variables) and I saving these whole. Is it optimized or efficient way to do, or not? Did you mean like this?
public MyData[] myDatas;
public void Load()
{
if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
{
binaryFormatter = new BinaryFormatter();
fileStream = File.Open(Application.dataPath + "/StreamingAssets/Data.dat", FileMode.Open);
myDatabase = (MyDatabase)binaryFormatter.Deserialize(fileStream);
fileStream.Close();
myDatas = new MyData[myDatas.Length];
for (int i = 0; i < myDatas.Length; i++)
{
myDatas[i] = myDatas[i];
}
}
}
So much misconception is going around in this thread… some of my thoughts around the subject:
I use JSON save file in development but binary in build. The reason is I can check on what I’m doing easily, but I don’t need to pay the endless string-processing price in build.
Best of both worlds. The only price is that I can’t test my dev saves in builds. (I can switch to binary read in dev though)
The binary formatter contains flaws which makes it unsafe to process data coming from outside sources. If you’re on a server where you are processing data from the clients, you need to forget its existence. If you’re developing a desktop application and you save and load files on the local computer, you shouldn’t care. Nothing outside comes in unless the user deliberately replaces a save file with some arbitrary file. The attack vector here is very weak.
ps: With that said, I myself also switched to BinaryWriter just because I’m maintaining code for multiple uses and if the code ends up on the server side, it shouldn’t cause a problem.
In both cases your only right way is to load the data in, make it object format, insert your new data and overwrite the file.
You do not “insert” data into a file. You can append text files though, but data-structure-wise it’s not an option.
I made like this. I load back my data into variables and I overwrite these with new and previous data into file
CODE to load back data as variables, is it right?
public MyData[] myDatas;
public void Load()
{
if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
{
binaryFormatter = new BinaryFormatter();
fileStream = File.Open(Application.dataPath + "/StreamingAssets/Data.dat", FileMode.Open);
myDatabase = (MyDatabase)binaryFormatter.Deserialize(fileStream);
fileStream.Close();
myDatas = new MyData[myDatas.Length];
for (int i = 0; i < myDatas.Length; i++)
{
myDatas[i] = myDatas[i];
}
}
}
But another way. If there are a lot of data and it takes a lot time to load a huge data. I mean with a “Huge Data” like (mesh vertices, triangles, uvs, position and rotation). My data is like this. And I need to divide to different files for not to take a long time to load and save it. And another question is, if there are trillion saved files in the game folder then it will be take a long time to search from these trillion saved files? I hope to explained well my question.
Just follow this tutorial, this way of saving is easy and much more secure.If you create your save file as one object of all data you can then find data you want replace in list and save it all again.
CreateSaveObjects();
void CreateSaveObjects()
{
//Get all new data from variables in Save method
var objectForSave = new PlanetObject(planetNumber, planetSize, planetType, planetGoal, totalMinerals, remainingMaterialsList.Count, saveList, questList,Galaxy.GetPlanetObject(Galaxy.planetToLoad).planetPosition,planetStatus);
//Get all old data
var planetList = Galaxy.GetLoadedPlanetObjectList();
var clusterPosition = Galaxy.GetClusterObject(Galaxy.clusterToLoad).clusterPosition;
var clusterList = Galaxy.GetLoadedClusterObjectList();
var galaxyNumber = Galaxy.GetGalaxyObject().galaxyNumber;
//Find and replace old object with new object in loaded list
planetList[planetList.FindIndex(ind => ind.planetNumber.Equals(Galaxy.planetToLoad))] = objectForSave;
cO = new ClusterObject(Galaxy.clusterToLoad, planetList, clusterPosition);
//Find and replace old object with new object in loaded list
clusterList[clusterList.FindIndex(ind => ind.clusterNumber.Equals(Galaxy.clusterToLoad))] = cO;
gO = new GalaxyObject(clusterList, galaxyNumber);
//Save object with replaced data
SaveManager.SaveGalaxy(this, galaxyNumber);
}
public static void SaveGalaxy(TerrainManager gO, int clusterNumber)
{
string planetDirectory = StaticRuntime.GetApplicationPath() + "/save/galaxy/";
if (!Directory.Exists(planetDirectory))
{
Directory.CreateDirectory(planetDirectory);
}
string saveGameFileName = clusterNumber.ToString();
string saveGamePath = StaticRuntime.GetApplicationPath() + "/save/galaxy/" + saveGameFileName + ".pgpro";
if (File.Exists(saveGamePath))
{
File.Delete(saveGamePath);
}
BinaryFormatter formatter = new BinaryFormatter();
FileStream stream = new FileStream(saveGamePath, FileMode.Create);
GameData data = new GameData(gO);
formatter.Serialize(stream, data);
stream.Close();
}
[System.Serializable]
public class GameData
{
public GalaxyObject _gO;
//SaveManager
public GameData(TerrainManager terrainManager)
{
_gO = terrainManager.gO;
}
}
I will try this code, if I have problems then I will let you know here in this post. But Brackeys save and load system is similar like mine. But your code is not look like in the video. I think this is a scriptable object saving type which you gave in the code. I will try this code.
In my code i am using c# objects Galaxy is constructed from List of Cluster objects and Cluster object is constructed from list of Planet objects and Planet object is constructed from other objects… point is if i save i only save Galaxy object since it is in top of this hierarchy, all what is inside of this object is saved.