Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Best Way to Save Game State

Discussion in 'Scripting' started by Venryx, Oct 3, 2012.

  1. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
    There are apparently many ways to serialize and save a game's data.

    BinaryFormatter, XMLFormatter (and the like), manual text-based formatting, UnitySerializer, etc.

    Is there any method which allows you to save any data types you want in one game-state-object, change the variables in that game-state-object without making changes to the core saving code, and works on all (or almost all) of Unity's supported platforms?

    The best candidate I've find is this: http://wiki.unity3d.com/index.php?title=Save_and_Load_from_XML

    Will this work on all, or at least most, of Unity's supported platforms? Does it successfully save classes like Vector3? Will it be able to read at least some of the data from incompatible saves? Can I change the game-state-object variables without making additional changes to the serialization code?

    Which methods do you use in your own projects?

    Thanks,
    Venryx

    P.S. (Btw, I'm fine with the game-data being readable and editable)
     
  2. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
    Just wanted to let anyone reading this know that I decided on using the XMLFormatter, because it requires the least maintenance, can serialize most objects (such as Vector3 and List, unlike BinaryFormatter), and is in a human-editable format. (which I consider good--if you want open-save-games, great, if not, then you just encrypt it or something so it can't be messed with.) Also, I like it because, you can add new variables to a serializable class and mess-around with it, and it's still capable of parsing the values of the other variables! This is great, because you can add new features to a game, and add new save data, and not always need to break compatibility with old saves.

    Here's the code I use now:
    Code (csharp):
    1. using System;
    2. using System.IO;
    3. using System.Xml;
    4. using System.Xml.Serialization;
    5. using System.Text;
    6.  
    7. public class XMLSerializer
    8. {
    9.     public static string SerializeObject(System.Object obj)
    10.     {
    11.         try
    12.         {
    13.             string _XmlizedString = null;
    14.             MemoryStream _memoryStream = new MemoryStream();
    15.             XmlSerializer _xs = new XmlSerializer(obj.GetType());
    16.             XmlTextWriter _xmlTextWriter = new XmlTextWriter(_memoryStream, Encoding.GetEncoding("ISO-8859-1"));
    17.  
    18.             _xs.Serialize(_xmlTextWriter, obj);
    19.             _memoryStream = (MemoryStream)_xmlTextWriter.BaseStream;
    20.             _XmlizedString = ByteArrayToString(_memoryStream.ToArray());
    21.  
    22.             return _XmlizedString;
    23.         }
    24.         catch (Exception e)
    25.         {
    26.             System.Console.WriteLine(e);
    27.             return null;
    28.         }
    29.     }
    30.  
    31.     public static T DeserializeObject<T>(string xml)
    32.     {
    33.         try
    34.         {
    35.             XmlSerializer _xs = new XmlSerializer(typeof(T));
    36.             MemoryStream _memoryStream = new MemoryStream(StringToByteArray(xml));
    37.             //XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.GetEncoding("ISO-8859-1") );
    38.             return (T)_xs.Deserialize(_memoryStream);
    39.         }
    40.         catch (Exception e)
    41.         {
    42.             System.Console.WriteLine(e);
    43.             return default(T);
    44.         }
    45.     }
    46.    
    47.     public static byte[] StringToByteArray(string s)
    48.     {
    49.         byte[] b = new byte[s.Length];
    50.  
    51.         for (int i=0;i<s.Length;i++)
    52.             b[i] = (byte)s[i];
    53.  
    54.         return b;
    55.     }
    56.  
    57.     public static string ByteArrayToString(byte[] b)
    58.     {
    59.         string s = "";
    60.        
    61.         for (int i=0;i<b.Length;i++)
    62.             s += (char)b[i];
    63.    
    64.         return s;
    65.     }
    66. }
    It really does work like a charm. :)
     
    Last edited: Oct 3, 2012
  3. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
    And by the way here's the BinaryFormatter, if you prefer it over XML:
    Code (csharp):
    1. using System.Collections;
    2. using System;
    3. using System.IO;
    4. using System.Runtime.Serialization;
    5. using System.Reflection;
    6. using System.Runtime.Serialization.Formatters.Binary;
    7.  
    8. public class Serializer
    9. {
    10.     public static BinaryFormatter bf = new BinaryFormatter();
    11.    
    12.     public static String SerializeObject(object obj)
    13.     {
    14.         MemoryStream memoryStream = new MemoryStream();
    15.         bf.Serialize(memoryStream, obj);
    16.        
    17.         bf.Binder = new VersionDeserializationBinder();
    18.  
    19.         return System.Convert.ToBase64String(memoryStream.ToArray());
    20.     }
    21.  
    22.     public static object DeserializeObject(string obj)
    23.     {
    24.         MemoryStream memoryStream = new MemoryStream(System.Convert.FromBase64String(obj));
    25.        
    26.         bf.Binder = new VersionDeserializationBinder();
    27.        
    28.         return bf.Deserialize(memoryStream);
    29.     }
    30. }
    31.  
    32. public sealed class VersionDeserializationBinder : SerializationBinder
    33. {
    34.     public override Type BindToType(string assemblyName, string typeName)
    35.     {
    36.         if (!string.IsNullOrEmpty(assemblyName)  !string.IsNullOrEmpty(typeName))
    37.         {
    38.             Type typeToDeserialize = null;
    39.  
    40.             assemblyName = Assembly.GetExecutingAssembly().FullName;
    41.  
    42.             //The following line of code returns the type.
    43.             typeToDeserialize = Type.GetType(String.Format( "{0}, {1}", typeName, assemblyName));
    44.  
    45.             return typeToDeserialize;
    46.         }
    47.  
    48.         return null;
    49.     }
    50. }
     
    Last edited: Oct 3, 2012
  4. whydoidoit

    whydoidoit

    Joined:
    Mar 12, 2012
    Posts:
    365
    I was just wondering what you thought was missing from Unity Serializer? Apart from the human readable format (which I don't use because it gets too big quickly) - it should have been able to support all of your needs. Though I guess you probably didn't need all of the extra functionality to do with level saving - it would handle classes with robustness for property changes etc. I'm always keen to understand why people choose different solutions in case it leads me to add further features or better document my project.

    Thanks

    Mike
     
  5. Foxxis

    Foxxis

    Joined:
    Jun 27, 2006
    Posts:
    1,108
    Just wanted to reply to Mike as we have gone down the Unity Serializer route and have some perspective on the choice between a custom solution and a complete "off-the-shelf" solution like Unity Serializer.

    While Unity Serializer is awesome and for most users should work right away with a minimum ammount of coding, there is one major drawback. When things go wrong, you are completely left out to whoever wrote the package you are using. This is not criticism directed at Mike, it is common to all code packages you decide to use that wasn't written internally.

    In our case, UnitySerializer worked fine until recently when something broke. We have no idea what and short of going through UnitySerializer and hunting down the bug there's nothing we can do about it. So now we are very close to writing our own custom solution to get out of this dependency.
    Will it be as complete and easy to use as Unity Serializer? Probably not. But it will be ours, and if something goes wrong we'll know what to do to fix it in very little time. And that can be worth quite a lot.

    Again, UnitySerializer is an awesome package. We have used it and donated quite a bit of money towards its future support and development. So please do not interpret this post as criticism of Mike and the package itself. It is more a reflection on the choice between a custom solution and one where you are dependent on a third party.
     
  6. Venryx

    Venryx

    Joined:
    Sep 25, 2012
    Posts:
    444
    Nothing was really missing. It seems to work very well. But I decided on using a custom saver for four reasons.

    First, because I would be writing the system myself for the XMLSerializer, I would be familiar with how it worked, so if something went wrong I could easily find out how to fix it.

    Second, I'm more used to using code-based systems, (I'm new to Unity), so I felt more comfortable seeing the save/load system sitting nicely in a single class rather than using the Unity infrastructure. (I don't like having part of the system "out there" in Unity rather than the C# scripts; unless of course it's necessary)

    Third, I needed the saves to be somewhat backwards-compatible, and I knew the XMLSerializer had this whereas UnitySerializer I wasn't sure about.

    Fourth, the setup for the UnitySerializer felt slightly disorganized. It wasn't too clear from the panels and buttons what to do first, then second, then third. It probably wouldn't have been too hard to figure out, but it was a little deterring.

    Anyway, I think mostly it boils down to my want for complete and instant control that I can have with XMLSerializer. Other than that, I think UnitySerializer would have worked just fine.
     
  7. bloomingdedalus

    bloomingdedalus

    Joined:
    Aug 13, 2012
    Posts:
    139
    You're epic with your advertisement of this thing... A portion of people using Unity are new to scripting so it's good for us to learn what to do. I'm looking over your C# code right now and learning tons about C# I didn't know just from trying to understand your script.
     
  8. hasanbayat

    hasanbayat

    Joined:
    Oct 18, 2016
    Posts:
    630
    One of the best and free ways to save game is Save Game Free.
    Save Game Free is a free, powerful and secure save game solution that allows you to save your game data in any format and securing it by encryption.

    Features
    • Cross Platform
    • Web & Cloud
    • Encryption
    • Auto Save
    • Easy to use
    • Free to use
    • Open Source
    • Simple but Powerful
    Getting Started | Source Code | Community Thread | Support and News

    But also, you can make your own save system using our serialization libraries:
    Hope this helps.
    Thanks.