Search Unity

Questions about Saving and Loading / Serialization and Deserialization

Discussion in 'Scripting' started by Aspiring_Failure, May 24, 2015.

  1. Aspiring_Failure

    Aspiring_Failure

    Joined:
    Jan 21, 2013
    Posts:
    42
    I've been trying to implement a saving/load system into my game, and started by watching the live training archive video on data persistence. The video was very helpful and gave me the gist of:

    1. Creating a special class to hold the data that you want to save.
    2. Serializing this class.
    3. Deserializing this class.
    4. Applying all the data held in that class back to the game.

    And, of course, this works very well for the demo, but is simply not practical in a game even slightly more complex, and this is where I've got some barriers that I've been struggling to get through. I could manually save all of my game's important data, one variable at a time, but this is ludicrously laborious, and it's all so hardcoded that it would be a pain to modify if anything about the game ever changed. (which, of course, is very likely to happen)

    So, I'm curious. What are the better ways of doing this?

    Is it possible for me to serialize, deserialize, and apply an entire monobehavior-derived class, such as one that might contain the player's inventory? Or even better, what about entire game objects?

    If not, is there a more dynamic way for me to store data in my special SavedData class? I imagine there might be, but that it would get complicated once I had to collect, store, and then apply that data to a bunch of different classes.

    I'm just completely confused with all this, and it feels like there's surprisingly limited documentation for this to be as literally essential to any game that it is.

    Before I wrap this up, I do want to mention that I'm not opposed to 3rd party solutions, and I'm aware that there are a few of them, but I would like to understand what's going on under the hood and, if possible, save some money by coding my own. I used Unity Serializer by whydoidoit but, besides it seeming like that excellent fella has been wiped from the face of the Earth, I don't want to use a system that's going to be incompatible with my game should I ever upgrade to Unity 5. (and that one apparently would be)

    Thanks for taking the time to read and I hope you guys can give me some clear answers or point me in the right direction here. :)
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I don't think there's any shortcut. You have to decide what data you want/need to save, and write code to save and restore that data.

    This can indeed be a major pain in the neck if your intent is to serialize the entire current state of the game. But many games get by with saving much less — you don't need to save anything you can infer or recreate on the fly.
     
  3. Bradamante

    Bradamante

    Joined:
    Sep 27, 2012
    Posts:
    300
    Hm, this issue comes up quite often here ...

    There are many ways to go about this. I strongly advise to just buy something on the Asset Store. Never waste time to code something yourself if you can just buy it. There's XML, there's JSON, what have you.

    That being said, for my save games I just de/serialize a Struct, not a Class or MonoBehavior (even though there are solutions on the Asset Store to do so) via BinaryFormatter:

    Code (csharp):
    1.  
    2. public static Structs.PilotData loadStruct ( string fileName ) {
    3.    
    4.    fileName = string.Format( "{0}.dat", fileName );
    5.    string filePath = System.IO.Path.Combine( DEFAULT_PILOT_FOLDER_PATH, fileName );
    6.    FileStream fs = new FileStream( filePath, FileMode.Open );
    7.  
    8.    BinaryFormatter bf = new BinaryFormatter();
    9.    
    10.    try {
    11.      Structs.PilotData fileStruct;
    12.      fileStruct = (Structs.PilotData) bf.Deserialize(fs);
    13.      return fileStruct;
    14.    }
    15.    finally {
    16.      fs.Close();
    17.    }
    18. }
    19.  
    20. public static void writeStruct ( Structs.PilotData pData ) {
    21.  
    22. //   createPilotFolderIfNotExistent();
    23.    
    24.    string fileName = string.Format( "{0}.dat", pData.fileName );
    25.    string filePath = System.IO.Path.Combine( DEFAULT_PILOT_FOLDER_PATH, fileName );
    26.    FileStream fs = new FileStream( filePath, FileMode.Create );
    27.    
    28.    BinaryFormatter bf = new BinaryFormatter();  
    29.    try {
    30.      bf.Serialize( fs, pData );
    31.    }
    32.    finally {
    33.      fs.Close();
    34.    }
    35. }
    36.  
    BinaryFormatter might also help prevent player-side save game tinkering, since the result is less readable than a XML- or text-based solution. But then again, human-readability or flexibility might be what you want.

    When it comes to loading game data, I just use CSV files, since sometimes I just want to do a quick and dirty edit in Excel. Unity treats them as text files and you can parse them line by line. This might also help modibility, since you can now alter ingame values by just loading a text file in your game folder. Since text files are quite small, you might even pull them from a web server every time the game starts, thus allowing for quick balancing or patching.

    That would be the "flexible" text-based solution you are looking for. Problem is that now you have to give Unity some hint what data type is required. Could be floats, ints, Vector3s, strings etc. What you can do is to reserve a field in every line of the CSV table for a type hint, like "s" for text, "f" for a float etc. The result would look like:

    Code (csharp):
    1.  
    2. key;type;EnemyType1;enemyType2;
    3. health;i;90;60;
    4. helloMessage;s;"I will get you";"Come to me";
    5. scale;v;(1.25,1.2,1.0);(1.5,1.8,2.0)
    6.  
    If you don't use "type hints" like that you would also use something more automatic. Like, if the text parser detects the field starting with a "(" treat it like a Vec3.

    Other than that, yes, save game files are a lot of manual, laborious, case-by-case work.

    That's why they call 'em save game wipes ...
     
    krougeau likes this.