3
\$\begingroup\$

Is there a simple way to 'serialize' the game data of my game, but protected it from being unloadable if I add new fields? I have all the data in a single class, GameData.java, and I want to avoid having to manually read/write each field from it. If I serialise it using standard java function, but add new fields to the class, it will render it unserializable.

I'd like to be able to save the class and the reload it from a file, and it use default values for any new fields that are missing from the save file. XML may be a solution, but is there an existing library to automate the process?

Thanks!

\$\endgroup\$
  • 1
    \$\begingroup\$ One existing library? There are dozens. But your question is not really game-development related. You will likely find lots of helpful answers to this on stackoverflow.com. \$\endgroup\$ – Philipp Apr 18 '16 at 10:37
  • \$\begingroup\$ Have you tried to serialize into JSON format? Maybe Gson will work for you. \$\endgroup\$ – JordiVilaplana Apr 18 '16 at 10:41
  • \$\begingroup\$ What game development library are you using? LibGdx has built-in JSON parsing capabilities. \$\endgroup\$ – JDSweetBeat Apr 18 '16 at 13:35
  • \$\begingroup\$ I'm currently using JMonkeyEngine to develop the game. This has its own way of saving data, but is analogous to standard serialization and comes with the same problems. \$\endgroup\$ – Steve Smith Apr 18 '16 at 15:12
3
\$\begingroup\$

I use the libGdx Json functionality to save my game state to JSON;

public class GameInstance
{
    //Some fields, constructors, utilities

    public void saveState(GameState state)
    {
        String save = json.prettyPrint(state);

        //Save to the file using FileHandle
    }

    public void loadState(FileHandle file)
    {
        String stateText = file.toString();
        json.setIgnoreUnknownFields(true);
        state = json.fromJson(stateText);
    }
}

In my GameState I store the version of my app;

public class GameState
{
    //some fields
    public final String versionID = "0.1.1";

    //game access functions
}

Before I access the modified field, I check to see if the versionID is correct and will allow me to read it. This allows me to write simple fallback mechanics that help provide as much of the new functionality as possible.

EDIT:

I keep a field-changes.txt file that I use to log changes that I make in my fields for each class. I almost never remove a field entirely for compatability reasons. When I do I try to add functions that can work out a suitable replacement value.

Now, without libGdx you can just use the Jackson JSON API(link to tutorial on how to use Jackson). The details can be found in this Stack Overflow question. In short, there is apparently an annotation that you can use that has this purpose in mind specifically.

The accepted answer says you should do this;

import org.codehaus.jackson.annotate.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Foo
{
    //...
}

Also check out the next best answer. Either way, the idea is still the same; to store the version of your GameState in each saved state and refactor the code to use the old data in alternative ways that makes the newest functionality possible.

Note: I only use libGdx and its Json library. Alternatively, if you wanted to use its Json library you could go and get the Json sourcecode. You would also need to copy the libGdx-specific collections and primitive collections to your project and fix the setup. You would have to do some minor editing to make it work.

\$\endgroup\$
  • \$\begingroup\$ Instead of keeping the changes in changes.txt, you could cleverly codify it in your code (in the comments, with a special syntax), and build an external tool to gather that info and produce the changes.txt :P \$\endgroup\$ – Vaillancourt Apr 18 '16 at 14:17
  • \$\begingroup\$ @AlexandreVaillancourt That is probably a better way to do it. \$\endgroup\$ – JDSweetBeat Apr 18 '16 at 14:24
  • \$\begingroup\$ Yeah, it requires more work at first, though :) In a one-person team, your method is great and will work just fine, but if the team gets bigger, things need to be more formalized in the code I guess. \$\endgroup\$ – Vaillancourt Apr 18 '16 at 14:26
  • \$\begingroup\$ This sounds like an ideal solution, but I don't use LibGDX so it seems a bit of overkill to include it in my project purely to use it's Json functionality. \$\endgroup\$ – Steve Smith Apr 18 '16 at 15:32
  • \$\begingroup\$ @SteveSmith Check it out now; helpful? \$\endgroup\$ – JDSweetBeat Apr 18 '16 at 16:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.