Using XML Schema for Tools

XML is the de facto standard for game data, at least for intermediate data. Just about every programming language commonly in use has robust libraries for reading, writing and manipulating XML data. There are also some interesting general purpose tools for XML that not many people know very well such as XSLT (which I’ve discussed previously) and XML schema.
XML schema is most often associated with error checking (AKA validation), and that is a very powerful feature of schema. XML schema acts as a data definition language for well-formed XML data, so, once your schema is defined, you can test your XML file against it, to make sure that thew data follows the definition. This is particularly useful in situations where the data is potentially hand edited (a big no-no), corruption of data can occur, or where the definition of the data is in flux.
In the case where data definition is changing while the data is being worked on (we’ve all been there), you could use a versioning scheme that included versioned schema files to automatically fix your data, removing data that was old, and adding new data with default values defined in the schema.
And that’s not all.
The second and possibly more interesting use for schema is to add metadata to types using the annotation field using the appinfo element. The appinfo can contain any well formed XML and can be read directly by your application. This can be useful in customizing your editor to display unique controls for each data element being edited. For instance, you might have something like this:

<xs:schema xmlns:xs="http://www.roboticarmsoftware.com">
<xs:complexType name ="Unit" abstract="false">
  <xs:annotation>
    <xs:appinfo>
      <attribute name="Name" editor="TextField"/>
      <attribute name="Type" editor="EnumList" values="Infantry,Artillery,Hovercraft"/>
      <attribute name="HP" editor="Slider" range="1,100"/>
    </xs:appinfo>
  </xs:annotation>
  <xs:complexContent>
    <xs:attribute name="Name" type="xs:string" default="None"/>
    <xs:attribute name="Type" type="UnitType" default="Infantry"/>
    <xs:attribute name="HP" type="xs:integer" default="0"/>
  </xs:complexContent>
 </xs:complexType>
</xs:schema>

In our code, we’d read the appinfo and initialize the various controls for each property of the Unit type as defined above, that way, instead of just showing generic property editing controls, we can truly customize it to fit the data being edited. This is just a simple example, but you can easily come up with much more interesting (and hopefully useful) uses of the concept. You can find more detailed info on the W3Schools and MSDN websites.

Data Driven is Half The Battle

I was recently invited to do a talk at Game Forum Germany, and the talk I gave was called “Data Driven Is Half the Battle.” I’ve made the slides available on my website if you would like to take a look.

The purpose of the talk was to show that just making game systems data driven is not the end of the road to making your game configurable, especially when you want the rest of your team to be able to edit these configuration files. Formats like XML and JSON are awesome, but by design lack any context for the properties and values they control. This is good thing from a programmer’s perspective, since it means that we can define the meanings of properties and valid values, but a bad thing from the perspective of someone who has to edit those files. Either the system needs to be really well documented, you need to create a tool that ensures that people editing can only supply valid values.

Maintaining these tools can become a huge pain in the ass, though, especially when features or data modules are being added frequently.

My proposal to fix this was to use reflection, either custom coded in C++ or one offered by the language you’re using. This is the one I have the most experience with and the one I’m most comfortable using. Interestingly fellow Toolsmith Geoff Evans actually has an article in Game Developer this month about using reflection in Helium, which is worth checking out if you’re looking to implement this sort of behavior.

However, this does not mean this is the only solution, especially if you’re moving data between multiple systems and / or multiple languages. In this case, a data definition system, might be more worth your while, especially if you can just use the data definition to dynamically load the class as specified (this would be possible to do in dynamic or duck typed languages).

No matter what, the key takeaway of the talk was twofold: 1) Make it easier for people to modify data, and everyone will be happier, and 2) Make it easier for your programmers to do so, and they’ll do it more frequently, with fewer bugs., which also makes everyone happier.

Implementing Undo

One of the most basic of usability features, undo/redo is also fairly straightforward to implement.  Most engineers will tell you that undo functionality needs to be planned for from the beginning of a project.  So why is it still just an afterthought for most game development tools?  We recently had to implement an undo solution for a client in a design tool.  This is a general implementation similar to those I’ve seen at other companies.  I’m sharing it with you here so you can plan for it when you sit down to design your next tool.

For undo to work, we need an object to encapsulate the functionality of executing an action, along with the undoing of the action We also need to support redoing the action, which is a variation of the initial execution.  For those who like design patterns, this functionality fits nicely in the “command” (a.k.a. “action”) pattern.  The execute, undo, and redo are all functions that need be added to the command object to support the functionality we need, along with a specific constructor.

The constructor is responsible for storing all of the necessary data within the command class to be used later on by our execute, undo and redo functions.  We simply copy values passed in to the constructor to member variables.

The execute function does everything that would have been done had the code not been moved into an undo-able  command.  This fact makes it relatively easy (but tedious) to implement undo after much of the tool is written, or to move functionality that didn’t support undo into the undo system.

Some commands need to perform multiple actions at once.  For instance, we may need to overwrite data that existed before.  In this case, we perform two undo-able actions at once, the deletion of the old data and the creation of the new data.  So, we pass in a list of pointers to the command base class.  This list will contain this action and any other commands that need to be executed along with this one.  We’ll create and execute those actions within the execute function.  The current action is added to the list last, for consistent ordering.  The importance of this will come later.

The undo function is a simple matter of reverse engineering ourselves back to the previous state using the data passed to the constructor.  For everything the execute did, we basically do the opposite, with the exception of the multiple command functionality, which is called from code outside of this class, from the undo stack, itself.

Redo basically does everything the initial execute did, but like undo, we skip the  multiple command functionality.  We call the execute function with a null list of commands (we could use a boolean parameter) to signify we should skip the execution of the multiple command code.

In order to have more than one level of undo, we need to store these actions on a stack.  In our case, we’ll actually use two stacks (for undo and redo), encapsulated in a command stack class.  Similar to the commands themselves, there are three basic functions in our command stack — execute, undo, and redo.

A command is passed to the execute function of the command stack.  The execute function creates the list that is passed to the command’s execute function, calls that function, and pushes the resulting list (which has been populated by the command’s execute function with one or more actions) onto the undo stack.  The redo stack is then cleared, since there are no commands to redo after a brand new command has been executed.

Undo simply pops a command list from the undo stack, and executes undo on all items in the list in reverse order.  Items were added to the list in the order that they would normally be executed.  In our example above where a new item overwrote an existing one, the deletion of the existing item was first in this list. We want to restore the old item after deleting the new one.  Finally, the command list is pushed onto the redo stack.

Redo pops a command list from the redo stack, executes redo on all items in the list (beginning to end, this time), and pushes the list onto the undo stack.

Once this is ready, you simply need to create the commands where appropriate, and call execute on the command stack, with the command as parameter.  Once the commands are added to the stack, you can simply call undo and redo on the command stack from a key command or menu item.

This simple implementation will give you unlimited levels of undo functionality.  The only limitation here is that some commands can use a lot of memory.  That’s generally not a problem when talking about tools being run on PCs with virtually unlimited resources, but it can be a concern.  How the commands, themselves, are implemented will affect this, so that takes careful consideration.  A simple fix for this would be to represent the undo and redo stacks as circular buffers with fixed sizes.  Presumably, you can find a reasonable number of undo levels for your application.