Table of Contents
Server component scripting can access custom data stored in XML files. These would typically be used to store game data resources, for example, anything from gameplay tables to configuration data. The data is stored in an XML hierarchy, accessible by traversing the tree defined in the each XML file.
Suppose that a data file is defined as in the example below:
<root> <character> Sir Manfred <description> White knight </description> <modelName> sets/main/characters/knight.model </modelName> <race> human </race> <gender> 0 </gender> </character> <character> Sofia <description> Evil queen </description> <modelName> sets/main/characters/queen.model </modelName> <race> undead </race> <gender> 1 </gender> <slaves> <character> Underling <description> Hapless underling </description> <modelName> sets/main/characters/guard.model </modelName> <race> undead </race> <gender> 1 </gender> </character> <character> Servant <description> Unpaid slave </description> <modelName> sets/main/characters/servant.model </modelName> <race> undead </race> <gender> 1 </gender> </character> </slaves> </character> </root>
Example XML file ‐
<res>
/scripts/data/Characters.xml
You can access this data by creating a new
DataSection
using the
ResMgr
.openSection
method.
The path argument used is relative to the resources path. This is
illustrated in the example below:
ds = ResMgr.openSection( 'scripts/data/Characters.xml' ) # this will retrieve "Sir Manfred" ds.child( 0 ).asString # this will retrieve "White knight" ds.child( 0 )['description'].asString # this will retrieve 1 ds.child( 0 )['gender'].asInt
Reading an XML data file
You can access a section within the XML file by adding the name of the section to the end of the path given to ResMgr.openSection:
dsChild = ResMgr.openSection( 'scripts/data/Characters.xml/character' )
Reading an XML data file ‐ Accessing a specific section
If there are multiple elements with the same under the root element, then the first one is returned.
The available data types are:
Data type | Accessed by |
---|---|
64-bit floating-point numbers | .asDouble |
64-bit integers | .asInt64 |
Data blob | .asBlob |
Floating-point numbers | .asFloat |
Integers | .asInt |
Matrix | .asMatrix |
Raw binary representation of the XML node | .asBinary |
String | .asString |
Vector2 | .asVector2 |
Vector3 | .asVector3 |
Vector4 | .asVector4 |
Wide strings | .asWideString |
Available data types in XML
For more details, see the Client Python API's entry Class List → DataSection.
You can write to properties by referencing the appropriate
.as
property, then saving the XML file.
<data type>
Note
This feature is for use only on server tools, and you should avoid using it in game scripts.
An important limitation to be aware of is that it is only possible
to save a DataSection
that has been opened by
reference to an XML document. It is not possible to directly save a
section that is retrieved by a path to a sub-element within a file.
For example, the code below will not work:
# this will not work, throws IOError dsChild = ResMgr.openSection( 'scripts/data/Characters.xml/character' ) dsChild.asString = "Sir Lancelot" dsChild.save()
Example of incorrect procedure for writing to XML
The code excerpt below, on the other, will work:
# this will work dsRoot = ResMgr.openSection( 'scripts/data/Characters.xml' ) dsChild = dsRoot.child( 0 ) dsChild.asString = "Sir Lancelot" dsRoot.save()
Example of correct procedure for writing to XML
You can also add or remove child elements from each data section:
# get the document data section dsRoot = ResMgr.openSection( 'scripts/data/Characters.xml' ) # this will delete the first character dsRoot.deleteSection( 'character' ) # create a new character, which is appended to the top-level newChild = dsRoot.createSection( 'character' ) newChild.asString = "King Arthur" newChild.createSection( 'description' ) newChild.createSection( 'modelName' ) newChild.createSection( 'race' ) newChild.createSection( 'gender' ) newChild.createSection( 'slaves' ) newChild['description'].asString = "The King of Camelot" newChild['modelName'].asString = 'sets/main/character/knight.model' newChild['race'].asString = 'human' newChild['gender'].asInt = 0 dsRoot.save()
Deleting sections and adding new ones
Running the code excerpt below, and assuming a
Characters.xml
as described in Accessing Data, the result will be the file below:
<root> <character> Sofia <description> Evil queen </description> <modelName> sets/main/characters/queen.model </modelName> <race> undead </race> <gender> 1 </gender> <slaves> <character> Underling <description> Hapless underling </description> <modelName> sets/main/characters/guard.model </modelName> <race> undead </race> <gender> 1 </gender> </character> <character> Servant <description> Unpaid slave </description> <modelName> sets/main/characters/servant.model </modelName> <race> undead </race> <gender> 1 </gender> </character> </slaves> </character> <character> King Arthur <description> The King of Camelot </description> <modelName> sets/main/character/knight.model </modelName> <race> human </race> <gender> 0 </gender> <slaves> </slaves> </character> </root>
Resulting
<res>
/scripts/data/Characters.xml
Accessing the XML files on disk can potentially halt game processing. This can occur from disk I/O and parsing of the resulting data. This halt to processing can occur for both reading as well as writing of XML files and should be avoided as much as possible.
Due to the adverse impact this can cause to game development and resulting behaviour, a separate document has been written to address these issues. For more details please refer to the document How To Avoid Files Being Loaded in the Main Thread.
ResMgr
documents the
DataSection
's methods, and can be found in the
BaseApp Python API, CellApp Python API, and Client Python API.