Best way to save game for a Dungeon Crawler?

This is a pretty open ended question, but what do you think the best way to store save information for a dungeon crawler is?

Essentially I have a bunch of rooms with and array of tiles and a linked list of entities in that room (enemies, chests) and each entity has its own different state variables and so forth. (It’s actually a bit more complicated, each room is split up into sections, of which only a few are activated at any given moment, and each section has a list off entities). There’s also a bag the player has with different items in it. I could go on…

I’d like some sort of method to save this information, so when the program is closed the player can resume the game from where they left off, preferably being able to save multiple files at the same time. Naively I’d create some text file that feeds in all the information of each room into it and then parses it back out, but figuring out how to encode that information and parsing it back out seems like a tremendous pain given how many different sorts of things id’ like to save.

There must be some more standard way to do this sort of thing, but it’s unclear to me exactly what it is. What sort of method would you employ? What classes would you utilize? Is there a guide that goes over what you think would be best?

Thanks!

If you have never done any serialisation before, I would suggest that the easiest place to start would be using .json.

.json is a tree data structure, in which nodes can have branch nodes of leaf nodes. Simply put, a branch node is a node that contains other branches and leafs, while a leaf node is like a leaf in a real tree. A leaf node might be a string, or an int, float etc. Not going to go into details, you can read more about it on the internet.

http://json.org/

The implementation would look something like this:


public class Level {
	private ArrayList<Entity> entities;

	public JsonObject getSavingJson() {
		JsonObject json;

		JsonArray jsonEntities;
		for (Entity entity : entities) {
			JsonObject jsonEntity = entity.getSavingJson();
			jsonEntities.add(jsonEntity);
		}

		json.add("entities", jsonEntities);

		return json;
	}

	public void loadFromJson(JsonObject json) {
		JsonArray jsonEntities = json.getArray("entities");

		for (int i = 0; i < jsonEntities.size(); i++) {
			JsonObject jsonEntity = jsonEntities.get(i);

			String type = jsonEntity.getString("type");

			Entity entity = null;
			if (type.equals("Entity")) entity = new Entity();
			// else if (type.equals("Player")) entity = new Player();

			entity.loadFromJson(jsonEntity);
		}
	}
}

public class Entity {
	
	private String type = "Entity";

	public JsonObject getSavingJson() {
		JsonObject json;

		json.add("type", type);

		// additional stuff
//		json.add("position", position);
//		json.add("health", health);

		return json;
	}

	public void loadFromJson(JsonObject json) {
		// load your stuff here
//		position = json.get("position");
//		health = json.get("health");
	}
}


This is really up to you and what you define as “best”. Every approach has its own pros and cons, so there is no single best solution. Do you care a lot about file size? Do you want the saves to be accessible over multiple devices? Do you want the player to be able to “hack” the save states? Or maybe you want to prevent that? Do you need this to work in JavaScript as well?

If you’re just going for the simplest in terms of the fewest lines of code you need to write, you might want to google “Java serialization” for a ton of results.

To be fair, preventing 98% of people from hacking your games saved states is pretty easy with just some simple encryption of the file.

I agree with Kevin though, you need to specify what you mean by “best”, as it really comes down to what suites you. There is a lot of answers to the question you’ve asked, so more specific details will help narrow down what choices are good for you.

Serializing and deserializing actually isn’t the problem, there are plenty of solutions out there or you invent your own stuff. The more interesting problem is how to deal with updates. If you add stuff to your game or are changing things to fix bugs or improve the game play, you have to make sure that loading an old state doesn’t interfere with your changes and break the game. That’s why a simple saving/loading of lists of objects alone doesn’t cut it.
Or you simply don’t support this and render the players’ save games useless in that case… >:(

Great replies! In terms of “best,” really what I mean is easiest for me to implement. I don’t imagine these files will get very large, I’m really just storing things like positions and health and so forth. I guess it would be preferable that people aren’t able to trivially able to alter their save states, but that doesn’t really bother me.

I thought Serializing might be what I was looking for, so it’s good to see that that is an option. Having said that, Json does seem to be what I was looking for! Thanks for including some sample code, I can definitely imagine how I should bake this thing into my project.

Interesting choice. Using JSON isn’t really any different from using a basic text file. It also requires you to introduce a dependency into your project. Serialization handles loading for you, and it comes out of the box with Java. I don’t see a benefit to using json here, unless you want this to work with JavaScript or be human-readable.

I mean I don’t really have a preference here, but I’m surprised you chose JSON if your goal was to write the least amount of extra code.

If you do really want to use JSON, try googling “convert JSON to Java bean” for libraries that do the loading for you. Similarly, you could use XML and something like JAXB.

Or you could just use serialization. Here are some decent examples on reading and writing serialized Objects.

To not having to write the serialization code yourself with a JSON API, you can use XStream with Jettison:
by doing:


XStream xstream = new XStream(new JettisonMappedXmlDriver());
// for serializing:
xstream.toXML(myObject, outputStream);
// for deserializing:
myObject = (MyObject) xstream.fromXML(inputStream);

It also supports cyclic object graphs with JSON using a custom/artifical “@reference” JSON object attribute.