BGE: Saving configparser data

In my final tutorial on saving and loading with the configparser we’ll look at how we can save data in INI style formats. We’ll return to the Duck Duck Moose game to see how we can use the configparser to save player settings. Finally, we’ll cover how to use the configparser’s dictionary mapping protocol.

All of the configparser work is done in the settings.py file (see Resources below for the game). This contains a number of functions for controlling and updating the game’s user settings. We’ll jump right in and look at the 2 key functions that deal with saving and loading settings:

import bge
import configparser

def load():
    config = configparser.ConfigParser()
    try:
        config.read_file(open('settings.cfg'))
        bge.sens = float(config['player']['sensitivity'])
        bge.difficulty = int(config['player']['difficulty'])
    except IOError:
        bge.sens = 0.005
        bge.difficulty = 3

def save():
    config = configparser.ConfigParser()
    try:
        config.read_file(open('settings.cfg'))
    except IOError:
        config.add_section('player')
    config.set('player', 'sensitivity', str(bge.cursor.sens))
    config.set('player', 'difficulty', str(bge.difficulty))
    with open('settings.cfg', 'w') as file:
        config.write(file)

I’m not going to labour the loading code, since we’ve covered a lot on loading data. However, there is a slight difference worth mentioning. This time, instead of using various get methods where treating the config file like a dictionary. This is because the configparser is designed to map as closely to a dictionary object as possible. So we can access values in the following format: configObject[‘section’][‘option’]. This will still return a string, so you still need to convert it if you don’t want one.

The save() function deals with updating and writing the user settings once the player leaves the options menu. We can change the value of options using the configparser’s .set() method. This takes the section followed by the option and finally the new value. Since everything stored by the configparser is a string we need to ensure that we convert the value to a string before trying to set it. .set() will return an error if the section does not exist. But if the option doesn’t exist it will create one for us and assign it the value passed. New sections can be created using .add_section(‘sectionName’). We do this the in except block. That way, if the config file does not exits we’ll create a new section, .set() will add the necessary options and the file will be created when it is written to.

The config parser does not write the changes to disk for us. We need to explicitly do that. The configparser has a .write() method that takes the file object to be written to as its parameter. This section of script behaves just as we have seen using built-in IO methods.

Finally, we can remove options and sections using the methods .remove_section(‘sectionName’) and .remove_option(‘optionName’). Although they are not used in this example.

Continuing with dictionary mappings

Just like we were able to access stored values like a dictionary, we can also modify and save them using the same format. So our save() function would look like this:

def save():
    config = configparser.ConfigParser()
    config['player'] = {'sensitivity' : str(bge.cursor.sens),
                        'difficulty' : str(bge.difficulty)
                        }
    with open('settings.cfg', 'w') as file:
        config.write(file)

Notice that we don’t try and load a file or have the try/except blocks this time around. This is because each time we’re creating a new, empty, configparser object then creating a new section and assigning is values, just like we would a dictionary. When the file gets written it will just overwrite any existing settings file. This is handy when you’re updating all the values, but if you were only updating one option you’ll lose  everything else. So you could do something like this:

def save():
    config = configparser.ConfigParser()
    try:
        config.read_file(open('settings.cfg'))
    except IOError:
        config['player'] = {}
    config['player']['sensitivity'] = str(bge.cursor.sens)
    config['player']['difficulty'] = str(bge.difficulty)
    with open('settings.cfg', 'w') as file:
        config.write(file)

Just like previous examples, if the file doesn’t exist we’re creating it, this time by assigning the section named ‘player’ with a empty dictionary. We can then declare option/value pairs by declaring a section name and assigning it a value (lines 7 and 8). If the option doesn’t exist then it will be created. And if it does, its value will be modified. So we could remove line 8 and just modify the sensitivity option without affecting the rest of the file.

At the end of the day

We’ve covered a lot on the configparser and looked at various different ways to use it. Of all the methods covered, taking advantage of it’s dictionary-like mapping is the recommended way to use it and is also the most pythonic. For one final exercise in understanding the configparser, try going back over the examples from previous tutorials and changing them to use the dictionary mapping protocol.

The configparser really shines when it comes to saving/loading user settings. We can incorporate loaded settings early into a game’s scripting process without having created an options menu, relying on the readability of the INI style files to enable us to edit and test out changes to these values with ease. The similarities between configparser objects and python dictionaries make it intuitive to use and easy to integrate with existing code.

As always: any questions, comments, or thoughts, leave them below. Laters.

Resources

Duck Duck Moose game

Advertisements

~ by Jay on May 18, 2014.

3 Responses to “BGE: Saving configparser data”

  1. […] stats is a reasonably tidy way to store and pass them. Plus it would make the easier to save/load (think configparser here). But for many other custom classes it wouldn’t make much sense. For instance, having lots of […]

    Like

  2. Thanks a lot for your tutorials Jay, you saved me (and lots of people i think) hours of time!

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

 
%d bloggers like this: