adonthell-devel
[Top][All Lists]
Advanced

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

Re: [Adonthell-devel] Game saving


From: Kai Sterker
Subject: Re: [Adonthell-devel] Game saving
Date: Sun, 02 Dec 2001 21:42:19 +0100 (CET)

On Sun, 02 Dec 2001 13:24:12 -0700 Lakin Wecker wrote
> 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.

Certainly. The current files already contain version numbers but the
underlying code is bad, as updating the number requires changes at several
points ;P. If that would be done properly, it'd be just a matter of
discipline.

> 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.

Where possible this is a good idea. But there might be occasions where
assigning a default value hasn't the desired effect.

>     b) Integerity Checking of a savefile.  

Definately. I forgot about that this morning, but one advantage of
concentrating all disk operations at a single point is that we can easily
calculate a checksum for integrity checks. File corruption could still
crash the program otherwise. (As a side effect, it makes cheating harder
too.)

>     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++. 

That's worth a thought. 


> 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. 

We use zlib right now, which should be just as good. (Though bz2 might
have a slightly better compression.)

> 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. :)

True. As long as it's "reasonably" fast. Don't know if you played Gothic;
you could cook coffee during game loading ;).

Kai





reply via email to

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