Saturday, March 17, 2012

Using Configuration Files in UnrealScript

Configuration files are files in plain text format with the extension ".ini" with informations that will be used by the game.

In the folder "..\UDK-20??-??\UDKGame\Config" you will find various configuration files used by the UDK. As an example, the file "DefaultInput.ini" that is used for key binds.

The main advantage in using configuration files is to allow the setting of a game without having to recompile the source code. Thus a Game Designer can make the adjustments of the data of a game without relying on a programmer.

To use a configuration file in a class, add the modifier config as follows:
class ClassName extends SuperClass config(ConfigName); 

To identify what are the variables that will get their values from the configuration files, also use the config modifier when declaring the variables:
var config int exampleVar;

The next step is to create in the folder "..\UDK-20??-??\UDKGame\Config" a configuration file named "DefaultConfigName.ini" containing the values to be stored in variables. When the game runs it will look for a file called "UDKConfigName.ini". If this file is not found, the game will look for "DefaultConfigName.ini" in order to create the "UDKConfigName.ini" with default values. You should not edit the file "UDKConfigName.ini" because at some time it may be overwritten and you will lose your changes.

We can use the function "SaveConfig()" to save in the file "UDKConfigName.ini" new values of configuration variables that were modified during the execution of the game. There is another function called "StaticSaveConfig()" which allows the default values to be restored. This is a common option in the settings screen of games, as can be seen in the image below.


The function "StaticSaveConfig()" is static, that means it does not need an object to be executed. The static functions are like class functions, to run it just use the class name plus the word static as in this example:
class'ClassName'.static.StaticSaveConfig();

As an example, I made a class that draws on the screen some information that was obtained in a configuration file, as can be seen in the image below.


I created a configuration file called "DefaultWarrior.ini" containing the following information:
[RomeroScripts.CyberWarrior]
codename=DeadLocker
age=33

implants=Bionic Eye
implants=Night Vision
implants=Thermal Resistence

Attributes=(strength=12, agility=10, baseExperience=5000, currentExperience=6000)

The first line shows what is the class that will use this file. "RomeroScripts" is the name of the package that I use and "CyberWarrior" is the name of the class.

The class "CyberWarrior" defines the configuration variables. Then it uses a Timer of 1 second to increase the Current Experience and uses another Timer of 10 seconds to save the data of the player. The function "DrawHUD()" draws the informations on the screen.
class CyberWarrior extends SimplePawn
      config(Warrior);

var config string codename;      
var config int age;

var config Array<string>    implants;

struct stAttributes
{
    var int strength, agility, baseExperience, currentExperience;
};

var config stAttributes Attributes;

event simulated PostBeginPlay()
{
    SetTimer(1, true);
    SetTimer(10, true, 'SaveWarrior');
}
function Timer()
{
    Attributes.currentExperience++;    
}
function SaveWarrior()
{
    SaveConfig();
}

simulated function DrawHUD( HUD H )
{
    local int i;
    
    super.DrawHUD(H);
    
    H.Canvas.SetDrawColor(255, 255, 255); // White   
    
    H.Canvas.SetPos(50, 10);   
    H.Canvas.DrawText("Codename:" @ codename @ "- Age:" @ age) ;
    
    H.Canvas.SetPos(50, 40);
    H.Canvas.DrawText( "*** Attributes ***" );
    H.Canvas.SetPos(50, 55);
    H.Canvas.DrawText( "Strength :" @ Attributes.strength);
    H.Canvas.SetPos(50, 70);
    H.Canvas.DrawText( "Agility :" @ Attributes.agility);
    H.Canvas.SetPos(50, 85);
    H.Canvas.DrawText( "Base Experience :" @ Attributes.baseExperience);
    H.Canvas.SetPos(50, 100);
    H.Canvas.DrawText( "Current Experience :" @ Attributes.currentExperience);
    
    H.Canvas.SetPos(300, 40);
    H.Canvas.DrawText( "*** Implants ***");
    for( i =0; i < implants.Length; i++)
    {
       H.Canvas.SetPos(300, 55 + i * 15);       
       H.Canvas.DrawText( implants[i] );
    }    
} 

To use this class we need to create the new GameInfo that will reference the class CyberWarrior:
class GameWarrior extends SimpleGame;

defaultproperties
{        
    DefaultPawnClass=class'RomeroScripts.CyberWarrior'    
}

I'm using as the base class "SimpleGame" because it is easier to write on the screen in "SimpleGame" than using the "UTGame".

When running the game you will see that the information "Current Experience" is changed every second. Wait at least 10 seconds before leaving the game to be saved the current state of the class. When you exit the game, look for the file "UDKWarrior.ini" in the configuration folder. You'll see that "currentExperience", which is within the "Attributes", was modified. Also appear in this file other configuration variables that belong to the superclass "SimplePawn".

For more information:
Configuration files