Inspired by the XML format for game data question, I was interested to see how my system works for storing game data. My system works a lot like Halo, where there are a variety of gametypes and configurations vary between them, but some basic items are always configurable.
For example, every game has a time limit, but team deathmatch has points per kill while capture the flag has a flag idle reset time. How should I store and load the universal and variable data? Something to note is that every game type has a variety of different variants with different config values, but the same format.
With the 5 or so gametypes we have, changing data around is pretty easy, but when we add more gametypes, I want to unify as much as possible for easy copy pasting / editing.
Currently my XML storage looks like the following (Yes this is Minecraft data):
Team Deathmatch (Slayer.xml):
<?xml version="1.0" encoding="utf-8"?>
<gametype>
<!--Core Settings-->
<name display="Slayer">Slayer</name>
<description>Kill the enemy team.</description>
<version>1.0.0</version>
<!--Team Settings-->
<teams>
<team>
<name>Red Team</name>
<display>&cRed Team</display>
<prefix>&c</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="FF0000" >LEATHER_HELMET</helmet>
<chestplate color="FF0000" >LEATHER_CHESTPLATE</chestplate>
<leggings color="FF0000" >LEATHER_LEGGINGS</leggings>
<boots color="FF0000" >LEATHER_BOOTS</boots>
</armor>
</team>
<team>
<name>Blue Team</name>
<display>&9Blue Team</display>
<prefix>&9</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="0000FF" >LEATHER_HELMET</helmet>
<chestplate color="0000FF" >LEATHER_CHESTPLATE</chestplate>
<leggings color="0000FF" >LEATHER_LEGGINGS</leggings>
<boots color="0000FF" >LEATHER_BOOTS</boots>
</armor>
</team>
</teams>
<!--Slayer Settings-->
<kill-points>1</kill-points>
<death-points>0</death-points>
<suicide-points>-1</suicide-points>
<betrayal-points>-1</betrayal-points>
<!--Game Settings-->
<score-to-win>50</score-to-win>
<time-limit>10</time-limit>
<friendly-fire>false</friendly-fire>
<betrayal-booting threshold="3">true</betrayal-booting>
<damage-multi>1.0</damage-multi>
<can-join-late>true</can-join-late>
<!--Round Settings-->
<rounds>1</rounds>
<lives-per-round>0</lives-per-round>
<!--Item Settings-->
<items initial="true" respawn="true" personal="true"/>
<loadout>
<item slot="0">STONE_SWORD</item>
<item slot="1">BOW</item>
<item slot="7" amount="16" name="Arrows">ARROW</item>
</loadout>
</gametype>
Team Deathmatch Heavies (Heavies.xml):
<?xml version="1.0" encoding="utf-8"?>
<gametype>
<!--Core Settings-->
<name display="Heavies">Heavies</name>
<description>Kill the enemy team.</description>
<version>1.0.0</version>
<!--Team Settings-->
<teams>
<team>
<name>Red Team</name>
<display>&cRed Team</display>
<prefix>&c</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="FF0000" >LEATHER_HELMET</helmet>
<chestplate color="FF0000" >LEATHER_CHESTPLATE</chestplate>
<leggings color="FF0000" >LEATHER_LEGGINGS</leggings>
<boots color="FF0000" >LEATHER_BOOTS</boots>
</armor>
</team>
<team>
<name>Blue Team</name>
<display>&9Blue Team</display>
<prefix>&9</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="0000FF" >LEATHER_HELMET</helmet>
<chestplate color="0000FF" >LEATHER_CHESTPLATE</chestplate>
<leggings color="0000FF" >LEATHER_LEGGINGS</leggings>
<boots color="0000FF" >LEATHER_BOOTS</boots>
</armor>
</team>
</teams>
<!--Slayer Settings-->
<kill-points>1</kill-points>
<death-points>0</death-points>
<suicide-points>-1</suicide-points>
<betrayal-points>-1</betrayal-points>
<!--Game Settings-->
<score-to-win>50</score-to-win>
<time-limit>10</time-limit>
<friendly-fire>false</friendly-fire>
<betrayal-booting threshold="3">true</betrayal-booting>
<damage-multi>1.0</damage-multi>
<can-join-late>true</can-join-late>
<!--Round Settings-->
<rounds>1</rounds>
<lives-per-round>0</lives-per-round>
<!--Item Settings-->
<items initial="true" respawn="true" personal="true"/>
<loadout>
<item slot="0">IRON_SWORD</item>
<item slot="1">BOW</item>
<item slot="2" name="Lightning 'Nade" amount="2">SNOW_BALL</item>
<item slot="7" amount="16" name="Arrows">ARROW</item>
</loadout>
</gametype>
Capture the Flag (CTF.xml):
<?xml version="1.0" encoding="utf-8"?>
<gametype>
<!--Core Settings-->
<name display="Capture the Flag">CTF</name>
<description>Bring the enemy flag back to base.</description>
<version>1.0.0</version>
<!--Team Settings-->
<teams>
<team>
<name>Red Team</name>
<display>&cRed Team</display>
<prefix>&c</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="FF0000" lore="Loadout Item">LEATHER_HELMET</helmet>
<chestplate color="FF0000" lore="Loadout Item">LEATHER_CHESTPLATE</chestplate>
<leggings color="FF0000" lore="Loadout Item">LEATHER_LEGGINGS</leggings>
<boots color="FF0000" lore="Loadout Item">LEATHER_BOOTS</boots>
</armor>
<flag name="&cRed Flag" durability="14">WOOL</flag>
</team>
<team>
<name>Blue Team</name>
<display>&9Blue Team</display>
<prefix>&9</prefix>
<suffix>&r</suffix>
<armor>
<helmet color="0000FF" lore="Loadout Item">LEATHER_HELMET</helmet>
<chestplate color="0000FF" lore="Loadout Item">LEATHER_CHESTPLATE</chestplate>
<leggings color="0000FF" lore="Loadout Item">LEATHER_LEGGINGS</leggings>
<boots color="0000FF" lore="Loadout Item">LEATHER_BOOTS</boots>
</armor>
<flag name="&9Blue Flag" durability="11">WOOL</flag>
</team>
</teams>
<!--CTF Settings-->
<flag-at-home>false</flag-at-home>
<flag-reset>15</flag-reset>
<flag-recover>5</flag-recover>
<flag-capture-respawn>1</flag-capture-respawn>
<flag-respawn-retry>1</flag-respawn-retry>
<!--Game Settings-->
<score-to-win>5</score-to-win>
<time-limit>10</time-limit>
<friendly-fire>false</friendly-fire>
<betrayal-booting threshold="3">false</betrayal-booting>
<damage-multi>1.0</damage-multi>
<can-join-late>true</can-join-late>
<!--Round Settings-->
<rounds>1</rounds>
<lives-per-round>0</lives-per-round>
<!--Item Settings-->
<items initial="true" respawn="true" personal="true"/>
<loadout>
<item slot="0" lore="Loadout Item">STONE_SWORD</item>
<item slot="1" lore="Loadout Item">BOW</item>
<item slot="2" amount="16">ARROW</item>
</loadout>
</gametype>
I've edited these files over SSH in vim/pico for about a year now. Seeing them in an actual text editor has immediately brought up some issues. Firstly, comments seems to be used as grouping when parent elements should be used. Teams are almost exactly the same and should be loaded from another file by an id reference. I also feel as if attributes are used in the wrong places.
In terms of loading / saving this data in Java, I read in the contents of the file and then pass the contents to the configuration constructor. It then searches for elements as shown below. eRoot
is the top <gametype>
element, element
is a defined once Element
variable that is reassigned for every search: (I use the XOM library)
element = eRoot.getFirstChildElement("rounds");
if (element != null) {
this.rounds = Integer.parseInt(element.getValue());
} else {
this.rounds = 1;
}
Different game types have different config classes that inherit the one containing the above code. Each one is responsible for loading its own data. Am I doing this in a somewhat organized manner, or is everything completely wrong?
Also an idea that has sparked my interest is storing these gametypes in SQL tables. Is there any way to make this work nicely there or should I abandon that idea. These files are loaded from a central location that works nicely when we have 1 server, but in a few weeks our servers will be split to multiple boxes and I believe that SQL would be a better platform for pulling the configuration file data.