Saving base data and changes to it independantly

Started by
5 comments, last by tonemgub 12 years, 4 months ago
I'm making a game taking place in a procedurally generated world. When the player starts a new game, they could create a new world, which currently creates a bunch of files in a worlds/[ID]/ folder. When the player saves their game, their stats are saved in a separate save game folder. The world is created area by area as the player advances through the game, not all at once.
The reason I want to do it like this is that I want the player to be able to start a new game in an existing world and play through it again, or share fun worlds with other players without changes made in their old save file affecting the experience.

I realize this is similar to what a lot of other games do with their saves. My world is just the levels that are usually man-made. But whenever I've made save systems before, it's been in simple games where the player could only save between levels and never return to previous ones. So I'm not quite sure how to accomplish this.

I can think of two ways right now:

1) Save all dynamic data in the save file, even if no changes have been made. This would be simple to implement, but feels sort of brute force-ish and like I'm just duplicating data. I can't imagine an open world game like Morrowind has an entry in their save file for every single movable object unless the player has actually done something with it. (I remember that the Xbox Morrowind used to crash for people who had played for too long and had huge save files)

2) Save the differences only. Loading this way could probably be done two ways, either by always first checking the save file for a version of the data being loaded, or by loading all the base data and then going through the save files applying the changes. Not sure which would be best. Maybe there's no definite answer.
Anyway, the biggest problem I have with saving only changes is detecting a change. How can I make it so when the game saves, it sees that Object A is the same as when it was created, while Object B has been destroyed?

Any input is appreciated. :)
Advertisement
I would prefer 1 over 2. The second option is just too complicated and lacks any real reason (what is the reason behind saving only the delta , HDD memory ?) , when not targeting limited space plattforms like Xbox, PS3 etc. Even then , the worst case scenario would still have the same issues.

A better solution would be to add some kind of compression when running into memory issues.
I suppose you're right. I've been trying to implement the second option for a while now and keep running into problems. The main reason why I don't want to go that way is that I just dislike the idea of having the same data stored in two places, and that's not really a "problem" at all really.
On second thought I realized all the problems I had run into were problems in the first approach too. Mainly how to save objects that had been unloaded but not saved by the player. The second option isn't all that complicated after all, it seems.

On second thought I realized all the problems I had run into were problems in the first approach too. Mainly how to save objects that had been unloaded but not saved by the player. The second option isn't all that complicated after all, it seems.

First you need some vision of how to persist your game world. Here are some ideas which might help you:

1. the gameworld is divided into chunks, a chunk should consist of all objects, static and dynamic, in a certain area. This includes terrain, trees, npcs, flying missiles etc.
2. Each object should be assigned to one and only one chunk. If an object crosses a border (i.e. a flying missile) it will be reassigned to the new chunk.
3. Your designed game data are only an initial version of the game chunk and will be obsoleted once a chunk has been created and saved.
4. You need to save/load always whole chunks including npcs, flying missiles, terrain etc.
5. Once you have created a chunk you need to save it, not just unload it.
6. You need some kind of smart pointer which points to object in unloaded chunks, this could consists of

class ObjectReference {
MyObjectClass* realReference;
int chunkId;
long objectId;

bool isLoaded() { return realReference!=NULL;}
..
}

You need to check if an object is loaded (realReference!=NULL) and you need to update the reference when loading/saving/unloading a chunk.
You must save all "dynamic data" by definition; the only way to save less data is making the world less dynamic.

You only need a serialization technique that doesn't waste computation time, disk space and memory: detecting "changes" when you want to save is just about the worst approach, because you need the pristine world state both on disk and in memory to compute, in complex and probably not very cache-friendly ways, differences between object graphs, which are more complicated than the objects themselves.
Just saving a snapshot of the current state is cheaper to perform and simpler to implement (straightforward object serialization without reference data, or even more cheaply memory dumps). You can perform compression separately (a filter applied to the uncompressed binary file before writing), and also compress a save file by using another save file as a reference (which is far cheaper and probably better than object-level deltas).
A third option you didn't consider is remembering and saving a command and event log that can be executed again to reconstruct the end state of a span of play, between loading and saving, from the initial state. Saving becomes extremely cheap at the expense of loading becoming expensive; complete snapshots also need to be stored from time to time.

Omae Wa Mou Shindeiru

Sorry for reborn this topic i have a question on this topic.

If you save only the dynamic information that means that you need to query the main and the save database to create your world?

This topic is closed to new replies.

Advertisement