adonthell-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Adonthell-devel] Game saving


From: Lakin Wecker
Subject: Re: [Adonthell-devel] Game saving
Date: Sun, 02 Dec 2001 13:24:12 -0700

On December 2, 2001 04:43 am, you wrote:
> I had some more thoughts on this matter, so here is my suggestion:
>
> According to that design pattern
> (http://rampages.onramp.net/~huston/dp/MementoDemos.cpp), each class that
> has to be state-saved needs a "data_class" that will hold all the data in
> need of saving. The only thing our class does on saving is to return the
> data-class properly filled.

Correct.

> Here's the first change I suggest: instead of using normal variables in
> the data_class, why not store everything as key/value pairs? 

Sounds good.

>Assuming
> we only have ints and strings to save it would not be a problem.

Why not other data types? (see explanation below)

> One question is what happens with complex data, like a map that contains
> various submaps, or a character that contains an inventory. 

The approach I would take would be to define a class called say Any (or use 
one that is already available: http://www.boost.org/libs/any/index.html).
This is a class which can hold any type of variable that you want, so it 
works with Integers, Strings, Lists, Maps, etc.  It dynamically figures out 
what it holds, and has all the proper overloaded operators, and copy 
constructor functions.  So it acts like any normal type. 
Example:

Any myValue = 1;  // you now have an integer 
if(myValue == 1) //is true...

myValue = "myName"; // you now have a string
if(myValue==1) //is false.

std::map<string, string> myMap;
//add values and keys to myMap.
myValue = myMap;  // you now have a map. 

etc... etc..

so in your base_data("memento class") you have a 
std::map<string, any> myValues;

The saveToFile function can convert the the map to a format which is 
represented by a string or we could write some utility functions to do that.  
I would serve to have a standard format to convert an "any" value to a 
string.  That way an "any" value could be streamed over a socket to 
communicate between server and client.    

The formats I would suggest would be python format and/or Bach format.  

The tricky parts about this are the actual converting something to a string, 
and back again.  
It requires a bit of tricky input and output code, including a few stacks 
etc.  Regardless, I think it would serve well here.

> So you had for example:
>
>     // save character
>     base_data *data = my_character->save ();
>     data->save (file);

If done properly with an any class, and some simple recursion to make sure 
you get everything, the above code would save the entire character and his 
inventory to a file.

> I think the benefit of this is that all the actual saving code of all
> classes we want to save is grouped at one point. It further is flattened,
> so you no longer have method calls through several classes in order to
> save a complex object, which helps preventing coding errors.

> Actual file access happens in one class only, so we can easily react to
> I/O-Errors and such.

Agreed.
As Kai pointed out the "Database" layer should be seperate from the program 
so that it is transparent.  So if for some strange reason you decided to 
being storing savegames and stuff in MySQL it would be possible(i don't 
recommend this, it's just the principle. ;P )

> And why store everything as key/value pairs? Right now, if the savegame is
> not recent we most likely crash. Any change to the format will make it
> incompatible with prior versions.
> With the key/value pairs however, removing data from a savegame won't
> render old savegames invalid. The superflouos pair will simply be ignored.
> (We can do that now as well, but it means keeping obsolete code in the
> load function).
> Adding data to the savegame is a bigger problem. At least we can detect
> that data is missing (instead of reading wrong data), and maybe we can
> even substitute a default value for not so critical data to remain
> compatible.
> Even if we can't, writing a save game converter is not hard, as it needs
> not to know the structure of each object in the file. It just needs to
> know the part to be modified. If we add additional control information to
> the file, finding and modifying all items in a save game is quite simple.
> With a binary save file, it's much harder.

Here are my views of the saving/loading functions and classes.

1) They should have distinctive versions.
2) Each version should have a python script(or two) with these uses.
    a) Converting to this version which includes  removing
        Superfluous lines and data that isn't needed, and Adding
        Default keys and default values when missing.
    b) Integerity Checking of a savefile.  Used before loading the 
        save game.  If the check fails the user should be asked if
        they would like to convert this save game.  Conversion 
        should create a "new" savegame and leaving the old one.
    c) i feel that because you already have python scripting this script
        could also be used to actually save and load the game.  This 
        would not only allow for on the fly conversion, but would save us
        the tricky bit about string parsing and handling in C++. 
3) The save file format would contain a key value pair for each 
    savegame which lets us know which version it is.  This allows us 
    to turn integrity checks off to save time and yet safely consider 
    the possibility of loading this save game.  The user can be asked
    to convert the save game. Etc.

Let me know what you think and if I have been confusing when writing this 
then don't hesitate to ask questions.

> The remaining question is whether this adds too much overhead and slows
> down loading/saving uneccesarily. I'd say no. The limiting factor is the
> disk access. I guess the size of the data file won't be a lot bigger, as
> text compresses better than binary data. Apart from that, player and quest
> attributes are stored as key/value pairs already. So there wouldn't change
> much.

I don't think it will.  Using bz2 to compress it while we write it to the 
file would be also work to save on file size. 
Even if it does add a little time to the loading and saving of the game, it 
would be nice to have the integrity checks, and converting information 
available.  I think players will forget extra half seconds spent loading the 
game when cirrus dazzles them with his graphics, but they _will_ remember a 
segfault. :)

Lakin



reply via email to

[Prev in Thread] Current Thread [Next in Thread]