UDN
Search public documentation:

ConfigSavegameSystem
日本語訳
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

UE3 Home > Input / Output > Save games using the configuration system

Save games using the configuration system


Document Summary: This document explains how to use the standard configuration system to create a save game system.

Overview


The configuration system of the Unreal Engine is quite powerful and can be used for more than just saving various settings. This document presents a method to create a save game system for an RPG like game.

The save game system is pulled of by clever use of the UI datastore system and the PerObjectConfig directive.

Before you start with this document, read the ConfigurationFiles document to understand how configuration files work in the Unreal Engine.

Sapitu


Sapitu (short for: Savegames Are Possible In The UDK) implements a simple save game system for an RPG like game. It has the ability to store a character and its inventory.

You can download the full source code of this example here.

Sapitu is split up into 4 classes. The download also contains 2 additional classes: SapituGame and SapituPC, those are only used to play with the Sapitu system from within the game.

The four classes of Sapitu are as follows:

  • Sapitu : This is the main class that manages various parts of the savegame system.
  • SapituCharacter : This class stored the character information.
  • SapituInventory : This class is an inventory item which can belong to a SapituCharacter.
  • SapituItem : This class is used as a database record to create SapituInevntory items from. Instances of this class are read-only within the system.

Sapitu Class

This class defines some method to manage the creationg and loading of new characters. It also contains methods to create new inventory items, and keeps a reference of the item database.

Item database

The method loadItemDB initialized the database of SapituItem instances. It requests all definitions of SapituItem instances in the configuration files. This is part of the UI datastore system in the Unreal Engine. This system is also used to retrieve information about game types, maps, and weapons in UT3.

The getItem method provides the means to look up an actual SapituItem instance in the current database given the object's name (the Object.name property). This name (or rather identifier) is an internal name. In your final game you would probably never show this to the player.

The item database is used by the inventory system to look up the static definition of the inventory items. And it is also referenced to create new inventory items.

Characters

The Sapitu class is also the entry point to load and create SapituCharacter instances. The character system makes use of the normal configuration system and the PerObjectConfig class directive.

The getCharacters method returns a list of IDs of all registered characters. Just like the identifier of the items in the database, this refers to the Object.name property. It is not a user friendly name, but an internal identifier. This identifier is required during the loading and creation of characters. Due to the way the name is used there is an important limitation. The name should not contain spaces and various other non-alphanumeric characters. It is best to stick to using just the alphanumerical characters for the id.

Loading and creating of characters is actually similar. The both are done using the following code:

myChar = new(none, "MyCharId") class'SapituCharacter';

The magic is within the second paramater for the new operator. This defines the name of the object to create. Because the SapituCharacter character is defined as PerObjectConfig it will load the configuration for an object with that given name.

Because we want to make a clear distinction between loading and creating a new character in Sapitu we first check if a given identifier exists and then accept or reject the loading or creation.

Loading of a character is not finished by creating the proper instance. We also need to initialize it's inventory. The SapituCharacter stores a list of identifiers for SapityInventory items (SapituCharacter.inventoryRecord). In a similar way these items are created and added to the list of inventory item instances SapituCharacter.inventory. See the loadCharacter method for the exact implementation.

Inventory item creation

Inventory items need to be created in a special way. An inventory item is based on a specific SapituItem instance. the createInventory method create a new inventory item based on the given SapituItem instance. It constructs a unique identifier for the inventory instance, and then executes the special new(none, inventoryId) class'SapituInventory' constructor to create inventory item. After that it will initialize various variables that were loosely defined by the SapituItem instance, like the level, weight, and value.

The created inventory item does not belong to any character, in fact, it has not been saved to the save file. So when you exit the game, this instance is also lost. Saving of these items is left to the character instance when it has this inventory item in its inventory.

SapituCharacter class

This class is defined as

class SapituCharacter extends Object config(Sapitu) perobjectconfig;

This means that certain variables in the class will be saved in the configuration file UDKSapitu.ini, and that for each object a separate section is created. The latter is the result of the perobjectconfig class directive. The name of the object is of importance when saving the instance, because it defines part of the section name.

This class defines various config variables for the character name (which is the human friendly name), health, etc. The character's inventory is stored in a different way. Because object variables cannot be a config variable we keep a record of the identifiers of all inventory items (which are strings). And save that list instead. This means additional administration is required to manager the inventory.

Adding and removing inventory items must be done using the addInventory and removeInventory methods. These method update both the inventory and inventoryRecords arrays. The inventory array should not be modified directly. The Sapitu class does do this during load, but that's a special case.

Additionally, a saving of the character has to be done in an alternative way. You can not call SaveConfig directly, because that does not save the inventory properly. The save method iterates through the inventory array also calls SaveConfig on each item, and then calls SaveConfig on itself. This way everything belonging to this character is properly saved.

Note: that neither the SapituCharacter not the SapituInventory instances are saved any where else in the Sapitu system.

SapituInventory class

This class is an actual instance of an inventory item. It is based on an specific instance of the SapituItem class. This class is declared in the same way as the SapituCharacter class.

Because this instance is based on an SapituItem is needs special care with the regard to recreating to the proper reference. This is done by the Sapitu class as mentioned earlier.

SapituItem

This class defines an item type which can be used to create an inventory item from. This class should be considered as a readonly database entry.

Unlike the SapituCharacter and SapituInventory classes this class is a subclass of UDKUIResourceDataProvider. It is not declared as config, because the parent class is already defined as a config class. It is declared as PerObjectconfig.

Just like the other classes this also defines a couple of config variables. These are used to create an item definition.

Also notice the bSearchAllInis=true entry in the defaultproperties section. This variable is part of the UI datastore system. It defines that the datastore system should go through all configuration files to find objects of this item.

Loading of SapituItems should not be done through the previously mentioned new(none,id) constructor. To get all declared SapituItems you should use the following code:

class'UDKUIDataStore_MenuItems'.static.GetAllResourceDataProviders(class'SapituItem', ProviderList);

(see the Sapitu.loadItemDB method)

SapituItems are declared by hand. At runtime the should never change. To declare an item simply create a configuration file. And add an entry like this:

[sword1 SapituItem]
DisplayName=Short sword
level=(min=1,max=10)
weight=(base=10,levelMult=0.5)
value=(base=5,levelMult=1)

See the UDKGame\Config\SapituItemDB.ini file in the source for more examples.

Save game storage


The characters and inventory items are saved in the file UDKGame\Config\UDKSapitu.ini. See the file in the download for an existing "savegame". Note that all characters and inventory are saved in the same file.

Also note that it is saved as plain text. You could worry about possible cheating. But for a offline single player game you can always cheat by modifying the save game. It does not matter if the save game is plain text or a binary file.

Playing with Sapitu


To play with this system, simply compile the source and start a game as follows:

udk examplemap?game=sapitu.sapitugame

The SapituPC class defined a bunch of console commands you can use to play with the system:

  • createChar name
  • saveChar
  • loadChar charId
  • printChars
  • showChar
  • createRandomItem
  • createItem baseItem
  • pickupItem itemId
  • pickupAll
  • findItems
  • listItemTypes

Downloads