Config File Guide

Sometimes you need to share your knowledge. This is where you can do it. A place for POL and Script guides.
Post Reply
User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

Config File Guide

Post by Austin » Wed Nov 02, 2011 2:00 pm

Config files - Knowing how to use these is essential if you want a shard that performs well, uses less memory and is easy to make changes to.
This guide primarily targets 097 and up. If you're older, its seriously time to upgrade.

POL config files are FAST. Really fast. It only reads a path in once and caches it until unloaded.

To read a config file in the pol/config/ area you would use the path "::somefile". The "::" means go to the POL root directory.
If you want to read a config file from a single package use ":packagename:somefile" this will look for the file either in the package's root directory or the package's config subdirectory.

If you want to read in every config file in all the packages and the POL root config folder use ":*:somefile"

Note: The way you read in a config file, is how you must also unload it. Take this into consideration when you read a config file in.
":*:itemdesc" and ":pkgname:itemdesc" would have that package's itemdesc.cfg loaded twice in the cache repository. This means UnloadConfigFile(":*:itemdesc") and UnloadConfigFile(":pkgname:itemdesc")
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

What a Config File Looks Like

Post by Austin » Wed Nov 02, 2011 3:28 pm

Once you have a config file reference made from ReadConfigFile() you can use it to retrieve config elements.
A config file and its elements look like this:

myFile.cfg

Code: Select all

ElemType Example
{
    PropertyName  Value
    PropertyName  Value
    PropertyName2 Value
    SomeOtherProperty value
}

ElemType Example2
{
    Amount  1
    ItemColor  Blue
    ItemName  Sock
}

ElemType Story
{
    Food     sandwich
    Drink     beer
    WhoMakes    WOMAN
}

ElemType WhatIWant
{
     Ingredient Cheese    1
     Ingredient Bread      2
     Ingredient Meat       LOTS! I dont eat what food eats!
     Ingredient SpicyMustard   1
}
Some parts of the core require 'ElemType' be named something else like 'Armor' 'Item' 'Container'; However, in a script this isn't used - all you will care about is the element name. Most the time you can just use 'Elem' or something meaningful to you for the elem type.
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

Read A Config & Get An Elem

Post by Austin » Wed Nov 02, 2011 3:29 pm

Code: Select all

var config_file := ReadConfigFile(":*:myFile");
Using the variable config_file, you have two ways to retrieve a config elem reference.
Method 1: Use the function in cfgfile.em

Code: Select all

var config_elem := FindConfigElem(config_file, "Name");
Method 2: Use the [" "] way

Code: Select all

var config_elem := config_file["Name"];
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

Get A Single Property From an Elem

Post by Austin » Wed Nov 02, 2011 3:30 pm

In this example, it will retrieve the element "Story" from myFile.cfg and output it to the console.

Code: Select all


use cfgfile;

program SomeScript()
	var config_file := ReadConfigFile(":somepackage:myFile");
	if ( !config_file )
		Print("Could not read in myFile.cfg ->"+config_file.errortext);
		return 0;
	endif
	
	var config_elem := FindConfigElem(config_file, "Story");
	
	var food := GetConfigString(config_elem, "Food");
	var drink := GetConfigString(config_elem, "Drink");
	var from := GetConfigString(config_elem, "WhoMakes");
	
	Print("My "+from+" should get naked, then happily serve me a cold "+drink+" with a "+food+"!");
	
	return 1;
endprogram
Console output.. omitted in this example.
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

GetConfigStringArray

Post by Austin » Wed Nov 02, 2011 3:31 pm

Sometimes a config file will list a property name more than once. The functions in cfgfile.em: GetConfigInt, GetConfigString and GetConfigRealm only return the first property.
To retrieve all of them you must use GetConfigStringArray(). This example will pull some information from the elem "Example" and output it to the console.

Code: Select all


use cfgfile;

program SomeScript()
	var config_file := ReadConfigFile(":somepackage:myFile");
	if ( !config_file )
		Print("Could not read in myFile.cfg ->"+config_file.errortext);
		return 0;
	endif
	
	var config_elem := FindConfigElem(config_file, "Example");
	
	var first_set := GetConfigStringArray(config_elem, "PropertyName");
	var second_set := GetConfigStringArray(config_elem, "SomeOtherProperty");
	
	ShowContents(first_set);
	ShowContents(second_set);
	
	return 1;
endprogram

function ShowContents(byref some_array)
	foreach value in ( some_array )
		Print("Index["+_value_iter+"] == "+value);
	endforeach
	
	return 1;
endfunction
Output is

Code: Select all

Index[1] == ValueA
Index[2] == ValueB
Index[1] == valueD
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

GetConfigStringDictionary

Post by Austin » Wed Nov 02, 2011 3:39 pm

Sometimes a config element has a property, a unique identifier and a little more information after it.
In the old days you could do GetConfigStringArray() to get all of the property names then SplitWords() to parse each line.

POL097 added the feature to read in an associative array or dictionary.

This example will read in the elem 'WhatIWant' and show information about how that sandwich needs to be made.

Code: Select all


use cfgfile;

program SomeScript()
	var config_file := ReadConfigFile(":somepackage:myFile");
	if ( !config_file )
		Print("Could not read in myFile.cfg ->"+config_file.errortext);
		return 0;
	endif
	
	var config_elem := FindConfigElem(config_file, "WhatIWant");
	
	var ingredients := GetConfigStringDictionary(config_elem, "Ingredient");
		
	foreach amount in ( ingredients )
		Print("Ingredient name:"+_amount_iter+"  Amount="+amount);
	endforeach
	
	return 1;
endprogram
Console Output

Code: Select all

Ingredient name:Bread  Amount=2
Ingredient name:Cheese  Amount=1
Ingredient name:Meat  Amount=LOTS! I dont eat what food eats!
Ingredient name:SpicyMustard  Amount=1

If GetConfigStringArray() was used, the output would look like this:

Code: Select all

Ingredient name:1  Amount=Cheese    1
Ingredient name:2  Amount=Bread      2
Ingredient name:3  Amount=Meat       LOTS! I dont eat what food eats!
Ingredient name:4  Amount=SpicyMustard   1
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

Re: Config File Guide

Post by Austin » Wed Nov 02, 2011 4:01 pm

This last bit will cover one alternative to using GetConfigString() GetConfigInt() and GetConfigReal() and is frequently seen in scripts.

The lines inside a config file are described as properties. This example should demonstrate why! (They can be used as properties of the config elem object)
POL will automatically determine the type as string, integer or a double.

Code: Select all

use cfgfile;

program SomeScript()
	var config_file := ReadConfigFile(":commands:myFile");
	if ( !config_file )
		Print("Could not read in myFile.cfg ->"+config_file.errortext);
		return 0;
	endif
	
	var config_elem := FindConfigElem(config_file, "Example2");
	
	var amount := config_elem.Amount;
	var color := config_elem.ItemColor;
	var name := config_elem.ItemName;
	
	Print("I am still looking for "+amount+" "+color+" "+name+".");
	
	return 1;
endprogram
Console output

Code: Select all

I am still looking for 1 Blue Sock.
-Austin

User avatar
Austin
Former Developer
Posts: 613
Joined: Wed Jan 25, 2006 2:30 am
Contact:

Re: Config File Guide

Post by Austin » Wed Nov 02, 2011 4:26 pm

Now lets put this into something more practical.

Someone wants every sword of object type 0x1000 to have a flag on it called 'CanBeMadeMagical' that will exist for all swords of this type.

The wrong approach is to add a cprop to the itemdesc.cfg elem such as

Code: Select all

CProp	CanBeMagical	i1
Then doing

Code: Select all

if ( GetObjProperty(item, "CanBeMagical") ) 
     //...code 
endif
Why is this the wrong approach? Because you are storing a value for every instance of that object that will exist in your world.

Instead it would be better to approach it like this:

Add to the itemdesc.cfg elem for the item 'CanBeMagical 1' (note there is no CProp before CanBeMagical and its just 1 rather than i1)

Code: Select all

var itemdesc_cfg := ReadConfigFile(":*:itemdesc");
var itemdesc_elem := FindConfigElem(itemdesc_cfg, sword.objtype);

if ( itemdesc_elem.CanbeMagical )
     // Code here
endif
-Austin

Yukiko
Distro Developer
Posts: 2506
Joined: Thu Feb 02, 2006 1:41 pm
Location: San Antonio, Texas
Contact:

Re: Config File Guide

Post by Yukiko » Mon Nov 07, 2011 6:46 am

Austin,

Are element names case sensitive? I had trouble with the day/night cycle and discovered that light.cfg had LightRegion Background but my script was looking for "background" with a lowercase "b" and so my day/night cycle wasn't working.
Sincerely,
Yukiko

I would tell you a UDP joke but you might not get it.

Titus 2:13

Polytropon
New User
Posts: 19
Joined: Wed Sep 15, 2010 9:47 pm

Re: Config File Guide

Post by Polytropon » Tue Nov 08, 2011 1:41 pm

Yukiko wrote: Are element names case sensitive? I had trouble with the day/night cycle and discovered that light.cfg had LightRegion Background but my script was looking for "background" with a lowercase "b" and so my day/night cycle wasn't working.
It´s easier write a test-textcmd than to ask :)

For a file containing something like:

Code: Select all

elem Alpha
{
blah 123
}
elem alpha
{
blah 321
{
FindConfigElem(cfgfile, "alpha"); >>>> points to "Alpha"
FindConfigElem(cfgfile, "Alpha"); >>>> points to "Alpha"
FindConfigElem(cfgfile, "ALPHA"); >>>> points to "Alpha"
FindConfigElem(cfgfile, "alPHa"); >>>> points to "Alpha"
GetConfigStringKeys(cfgfile); >>>>>> returns "Alpha", ignoring the other element

So we could say it´s not case-sensitive, and the first element in the file takes priority if there are two elems with the same name. At least in 098 (but I don´t see any changes in the log)

Yukiko
Distro Developer
Posts: 2506
Joined: Thu Feb 02, 2006 1:41 pm
Location: San Antonio, Texas
Contact:

Re: Config File Guide

Post by Yukiko » Thu Nov 10, 2011 4:56 am

Thanks Polytropon.
Yep. I took a look at the day cycle script again. I had misunderstood the way regions are handled. Being they are controlled by the core I guess I was confused because the regions are defined in *.cfg files. Since the SetRegionLightLevel passes a string literal to the core specifying the region to be lit it makes sense that there is case sensitivity there but not in normal cfg handling.

Anyway, this series of guides is great.
Sincerely,
Yukiko

I would tell you a UDP joke but you might not get it.

Titus 2:13

Post Reply