adonthell-devel
[Top][All Lists]
Advanced

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

[Adonthell-devel] Game saving


From: Kai Sterker
Subject: [Adonthell-devel] Game saving
Date: Sun, 02 Dec 2001 12:43:37 +0100 (CET)

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.

Here's the first change I suggest: instead of using normal variables in 
the data_class, why not store everything as key/value pairs? Assuming
we only have ints and strings to save it would not be a problem.

So we had a generic base_data class, with a single container that holds
all data as (string key, string value).

That would allow the following design (hope I got it right):


    +---------------+          +----------------+
    |   base_data   |----------| state_saveable |
    +---------------+          +----------------+
            ^                           ^
            |                           |
            |                           |
    +---------------+          +----------------+
    |   xyz_data    |          |       xyz      |
    +---------------+          +----------------+


//// Some base classes we need

class base_data
{
public:
    bool save (ogzstream& file);
    bool load (igzstream& file);

protected:
    map <string, string> data;    
};

class state_saveable
{
public:
    virtual base_data *save () = 0;
    virtual bool load (base_data*) = 0;    
};


//// An actual class that needs to be state-saved

class xyz_data : public base_data
{
    friend xyz;    

public:
    xyz ( /* all data that needs be saved */ );
};

class xyz : public state_saveable
{
    base_data *save () 
    { 
        return new xyz_data ( ... ); 
    }
    
    bool load ( base_date* data ) 
    {
        // grab all data, do index to pointer conversion, etc ...
    }
};


One question is what happens with complex data, like a map that contains
various submaps, or a character that contains an inventory. I think that a
global save_load class should take care of that. That means it must know
all classes that are to be state-saved, but that shouldn't matter (as the
classes need not to know the save_load class).

So you had for example:

    // save character
    base_data *data = my_character->save ();
    data->save (file);

    state_saveable *my_inventory = my_character->inventory ();
    data = my_inventory->save ();
    data->save (file);
    
    for (state_saveble* my_item = my_inventory->begin (); ...; ...)
    {
        data = my_item->save ();
        data->save (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.



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.

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.


One last point:
This suggestion only includes the state loading/saving. It wouldn't change
anything for the data right now. Espacially I wouldn't suggest saving
image or audio data as textual key/value pairs ;). However we should also
try to flatten saving/loading of complex objects like animations and such.


Comments please,

Kai





reply via email to

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