RTS4 UI

Its been a while since my last post! I’ve been working on my study, but have recently had some time to work on this project and make some more progress. I’ve started to build some classes to load the AOM UI files. These files are XML-based with a hierarchy of “gadgets” used to display textures, text, buttons, etc.

Some things to note while writing a UI parser:
– Many hidden elements contain invalid data, resources from elements should be lazy bound, to avoid reading from data that does not exist
– UI resources should be looked up in textures2.bar, then in textures.bar
– Element bounds are always in screen-space, they are not transformed or offset by their parents rectangle
– The UI appears to be highly coupled to the engine – pressing the menu button calls “showGameMenu”, which then must unhide an element inside the same UI file, looked up by its name. These may be defined in an external xscript file that I have not yet found
– Similar to the last point, the contents of many elements seems to be driven by the engine, looking up that element by name and setting the appropriate data (ie. chat lines), other parts follow a data binding model (ie. resources)
– To load the correct image, you need to look for a [image name]_def.xmb file, check if a civilization specialization exists to be used instead, and then add .ddt to the end of the image path.

If I’m wrong on any of these points, please tell me!

Screenshot of the in-game UI displayed in XNA:
rts4ui

Screenshot with all elements visible:
ui_all

I’m too lazy to create file locating stuff, so you’ll need to update the list of install directories before running it:
Download source and binaries (170KB)

Advertisements

Mod HQ – .BAR, .DDT and .XMB

I’ve made a lot of progress today, adding support for streaming content from .BAR archive files, reading .DDT texture files (except for the DXT sub-formats), and building an XDocument from .XMB files. The project was updated so that it can be pointed at the Age Of Mythology game folder, and it will extract all the data it needs; no need to use BAR explorer or AOMEd to get the data in a more usable format.

In case anyone else wants to know how the formats work, here is a breakdown:

.BAR

BAR files are a collection of other files. They start with a short header, then a huge binary blob of all the data from all files within it, finally there is a “directory” containing the filenames and offset/length of the binary data above that belongs to the file. (1)
– [8 bytes] The “id”, seem to always be 0’s
– [4 bytes] Skip
– [4 bytes] Item count integer
– [4 bytes] Directory size integer
– [4 bytes] Directory offset integer
– […] binary data blob
==Jump to directory offset==
[For each file (0 .. item count)]
  – [4 bytes] File offset
  – [4 bytes] File size
  – [4 bytes] File size repeated (maybe packed size?)
  – [8 bytes] Skip
  – [null terminated string] File name
==Jump to File offset==
  – [File size bytes] The file contents

.DDT

DDT files are a container for image data of a number of formats (uncompressed, Palette, Grayscale, DXT formats). It starts off with a short header, then optionally some palette data, and finally the image data.
– [4 bytes] File magic code “RTS3”
– [4 bytes] Texture usage, ignored but has significance in AOE3 (2)
– [4 bytes] Alpha bit-depth; 0: no alpha, 1: binary alpha, 4: 4-bit alpha, 8: 8-bit alpha
– [4 bytes] Texture format; 1: Uncompressed, 3: Palette, 4&5&6: DXT formats, 7: Grayscale (2)(3)
– [4 bytes] Mip levels
– [4 bytes] Texture width
– [4 bytes] Texture height
[If Format == Palette]
  – [4 bytes] Number of colours in palette
  – [4 bytes] Skip
  – [4 bytes] 16-bit palette offset (565)
  – [4 bytes] 15-bit palette offset (?)
  – [4 bytes] 15b-bit palette offset (1555)
  – [4 bytes] 12-bit palette offset (4444)
[For each image mip level]
  – [4 bytes] Image data offset
  – [4 bytes] Image data size
[If Format == Palette]
==Jump to appropriate palette offset (16-bit if 0-bit alpha, 15b-bit if 1-bit alpha, 12-bit if 4-bit alpha)==
  – [Number of colours * 2 bytes] The palette data as 16-bit packed integers (RGB565, ARGB1555, ARGB4444)
  ==Jump to each image offset==
  – [Image-length bytes] The image data

XMB

XMB files are compressed binary XML files, though in the AOM alpha, there were uncompressed versions. They start with a magic code of l33t for compressed and both compressed (after being decompressed) and uncompressed begin with X1. Compressed files are compressed using zlib deflate. The files then contain a list of element names and parameter names, then a tree of elements with ids mapping into these arrays. (3)
– [2 bytes] “X1”
– [4 bytes] Length of document
– [2 bytes] “XR”
– [4 bytes] Version Major
– [4 bytes] Version Minor
– [4 bytes] Number of element names
[For each element name]
  – [4 bytes] Length of string
  – [Length bytes] String data
  – [4 bytes] Number of parameter names
[For each parameter name]
  – [4 bytes] Length of string
  – [Length bytes] String data
[Begin read-element sub-routine]
  – [6 bytes] Skip
  – [4 bytes] Length of content
  – [Length bytes] Content data
  – [4 bytes] Index into element names
  – [If Version > 4.7]
    – [4 bytes] Source document line number
  – [4 bytes] Number of parameters
  [For each parameter]
    – [4 bytes] Index into parameter names
    – [4 bytes] Length of content
    – [4 bytes] Content data
    – [4 bytes] Number of child elements
  [For each child element]
    – […] Repeat read-element
[End read-element sub-routine]

The interface was also tweaked a little, adding images for units, a filter to show only units or buildings, and some more tabs for when more functionality is added.

(1) http://sourceforge.net/p/dragonunpacker/code/631/tree/trunk/DragonUnPACKer/plugins/drivers/default/drv_default.dpr
(2) http://aoe3.heavengames.com/cgi-bin/forums/display.cgi?action=ct&f=14,30356,,10
(3) AOMEd source code (cont+alt+shift+triple-click the window to get source)


Download, click Data source, and point it to your Age of Mythology directory.

Note to self: WPF ListBox bug appears when the parent Grid has multiple rows AND columns.

Mod HQ

A fair bit of progress has been made over the last few days with loading the proto.xml data file, and more importantly, building an awesome looking GUI. The xml structure is fairly straight forward and simple enough to use an generic serialization class for most parts. I’ve found 3 unique mappings between XML and their object model representations:

  • Attributes packed in the parent node, such as the name of a unit
    <unit name=”Hawk”>…</unit>
  • Data stored in the value of nested elements, such as the line of sight of units
    <unit> <los> 12.000 </los> </unit>
  • Data stored in attributes within nested elements with complex selections, such as the action parameters
    <action> <param name=”MaximumRange” value1=”7.5″> </param> </action>

The first two are trivial to implement, and mostly cross-compatible, allowing a generic solution to cover almost all cases. The last one is much more difficult, as it requires looking into other attributes to select the correct element, and another attribute to get the value. To support these 3 cases, the following attributes were added to properties of classes.

ElementXml(tagName, requiredAttributes)
AttributeXml(attributeName)

The first case will use just an AttributeXml, the second would use an ElementXml, and the third would use both, signifying that an element must be found, and an attribute from that element used. This combination has turned out to be extremely flexible, and has covered all cases in the file so far.

A game developer I follow spoke about how trying to break large ideas down into small projects can help see the idea through to completion, so I’ve used this xml loading to start building an AOM-compatible mod creator. The program will load the data from proto.xml and display all of the units inside, along with their data. It is incomplete at the moment, but should serve as a proof of concept.

Download (includes source, will require .Net 4.5)