Search Unity

Advice Wanted : Future-Proofing A Savegame System

Discussion in 'Scripting' started by AlwaysSunny, Apr 3, 2017.

  1. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    Hey folks,

    I'm wrapping up development on my first commercial offering - click here for shameless self promotion - and running into a potential future problem I never bothered to address. Now's the time, and I could use some advice.

    My save system serializes an object whose type is PlayerAccount into an XML file. It loads those XML files and hands me a populated PlayerAccount object.

    The obvious problem being: As soon as I alter the PlayerAccount class (or objects it holds) in any way, I've got a dead save file. I'd like to make sure I can alter my PlayerAccount class (or objects it holds) in future product updates without breaking people's saves.

    What are my options?
    I'm willing to restructure my whole savegame solution, which I assume will be necessary.
    Thanks for any input,
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Firstly, I'd hand parse the XML and not rely on a serialization engine to do it (unless said engine allows you to handle errors/name changes).

    Next, I'd have the first entry in the XML be a version number. This version number correlates with the version of PlayerAccount at that time.

    Create an interface for our serializer/deserializer... something like:
    Code (csharp):
    1.  
    2. interface ISaveEngine
    3. {
    4.     XDocument Save(PlayerAccount accnt);
    5.     PlayerAccount Load(XDocument xml);
    6. }
    7.  
    Any time the save layout changes, we create a new implementation of ISaveEngine, and associate a version number with it. The implementation of previous engines should also be modified to deal with the stuff that doesn't exist. For example, if PlayerAccount gets new fields, old versions should make sure to populate said fields with appropriate data since the save data doesn't have it.

    Then using the Factory Pattern, we load the xml and get the version number, determine the engine to use from that. Then create an instance of that engine, and deserialize accordingly.

    All new saves should use the latest version, regardless of the save file it was loaded from.
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Do note, you'll still have issues if save data relies on mechanisms in older versions.

    For example, in Minecraft the world is generated based on a seed. Thing is the seeded algorithm to build terrain may change if you add a new biome, or you change it so that it creates cooler mountains or something (which MC has gone through multiple iterations of).

    If all you save is the seed in the save file, but this mechanism is altered... then the seed from an old save file would generate a completely different world.

    In these situations, you'll also have to deal with it in game. For example you could version out the seeded mechanisms just like you did the save engine... but this could easily bloat up. This is why MC during alpha/beta repeatedly dropped support of your older maps when you updated.
     
  4. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    Hey! Speedy reply, and very illuminating. Thanks!

    Pretty sure I follow the concept you're describing entirely, including potential gottchas. Even though the class changes with each update, I'm teaching the parsers of old versions about those changes. Do I grok this correctly?

    If so, I think I can handle every part of what you're suggesting - except the all-important first step. I'm somehow going to participate in the serializing / deserializing process? I've never encountered this need, so I'm wholly in the dark.

    Can you teach me any specific keywords I should research to get schooled on this? I can't see myself forming good search phrases without some assistance. Custom XML Serializer?

    If you know of any resources offhand that'd be keen too, but if I just know what to call it, maybe I can locate some myself.

    Much obliged,
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Currently how are you turning PlayerAccount into XML?
     
  6. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    With magic mystery code I scavenged several years ago. You can't see, but I'm red. How embarrassing. :)

    This may not be the original source, but it looks identical at a glance, perhaps a derivation or re-upload.
    I used it when I found it because it worked out-of-the-box without any hassle.

    My negligent chickens are coming home to roost!

    https://github.com/Dreamcooled/sjupdater/tree/master/SjUpdater/XML
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,531
    Well, you'll notice that the code in that repository names the classes 'XmlSerializer' and 'XmlDeserializer'... so yeah, the code you're using does hand parse the xml.

    Serializing is the act of converting your data from memory to a storeable format (like xml). Deserializing is taking from that format and turning it back into usable data.

    So when you serialize (save) your PlayerAccount, you'll go through its properties one by one and copy the data into an xml document.
     
  8. AlwaysSunny

    AlwaysSunny

    Joined:
    Sep 15, 2011
    Posts:
    260
    Having looked over the borrowed code, I have a better sense of what it does. How I can inject my own logic alongside theirs is still a total mystery to me (looks like a nightmare), but apparently they've built in some kind of versioning support. Maybe I just have to figure out how they intend its use.

    Thanks for cluing me into this future-proofing approach. I still don't know exactly where to go from here, but I'm better informed now than I was before you helped out - so thanks!