A continued series of replay file format discussion. Yesterday I started it off with an introduction and information on how to get the World of Tanks version out of the replay file. Today, there's more. So put on that offset, bits, bytes and length hat, and let's go to town, more after the jump since it's another long-assed post!

Yesterday I left off at reading the version out of the replay. This series assumes that you've done all previous steps in the series, because unless otherwise mentioned, offsets are relative to where we left off the last time.

Player name

This you can easily get from the JSON parts, but for completeness sake it's included here. To read the player name, do the following:

  • After reading the version, seek forward 35 bytes.
  • You then want to read 1 byte. This is the length of the players' name, we'll call it length
  • Next, read length bytes of data.

You have now obtained the player name!

Battle Level

The battle level is the tier cap for a battle. It can in fact go higher than 10 (13 I think is the highest) and is an indication of what the top dogs in the battle are. A battle level of 6 will see tier 6 as their top. To get the battle level, take the following steps:

  • After reading the player name, you want to seek forward 5 bytes.
  • You then want to read 1 byte. This is the length of the next bit of data, we'll call it length.
  • Next, read length bytes of data.

The data is stored as a Python pickle, and as such you will need Python to decode it. I have butchered together my own unpickler in Perl, which is part of my parser. Keep in mind, it is (as the comments indicate), a total ghetto thing and may or may not work properly. Usually it works, sometimes it just blows up.

After running the data through cPickle.loads and serializing it to JSON, you will end up with the following:

{ battleLevel: x }

Where "x" is a number. Congratulations, your next chunk of useable data!

Battle Roster

The battle roster is a very interesting beast, and contains more information than the roster list you can get from the JSON parts of a replay file. To obtain the battle roster, you want to do the following:

  • After reading the battle level, you want to seek forward 33 bytes.

Here it gets interesting, allow me to interrupt a little bit. Python allows for multiple pickles to exist in a single file, and can in fact read them all in sequence. This bit of data has no length indication, so we need to take our file handle, seek it to the proper position, and then feed that to cPickle.load - the load method does not seek in the file at all and will just start reading until it reaches the end of the pickle.

  • cPickle.load the file so you obtain the battle roster pickle.

The roster is (in Python parlance) a list of tuples. In Perl, we'd refer to it as an array of arrays. Each item in the list represents a single player, and each player is represented by an array of data.

The fields more or less correspond to those in thevehicles section of the JSON data you get out of a regular (encrypted and packed) replay. The following field offsets are "known":

  • 0 - Vehicle ID - The Vehicle ID is a database ID for a record that apparently stores the combination of player, vehicle, and match on WG's servers.
  • 1 - Raw data - we'll get to this later so keep reading!
  • 2 - Player name - rather obvious :)
  • 3 - Player team - a number indicating which team a player is on
  • 4, 5, 6 - Unknown at this time
  • 7 - The player's account ID. For some reason this is not included in the JSON data, but is immensely useful to construct links to the players' profile on the WoT site, as well as it being used in teamkill data that for some reason links to an account, and not a player (or "avatar" I should say).
  • 8 - Clan ticker - The clan ticker the player is in. Will be an empty string if the player is not in a clan.
  • 9 - The clan ID.
  • 10 - The platoon ID. If this value is set, it contains an ID number of a record that apparently records the members of a platoon. Players with the same platoon ID are in the same platoon. How to turn this into the numbers 1 to whatever is left as an exercise for the reader ;)

Now, the raw data is a very interesting piece of work, it's actually the same data that parsers for 0.7.1 replays used to obtain their data from. It is a byte string, with a variable length, but will be at least 12 bytes long.

The raw data contains the following data at the listed offsets:

  • 0 - The country ID. Possible values:
    • 0x01 - USSR
    • 0x11 - Germany
    • 0x21 - USA
    • 0x31 - China
    • 0x41 - France

  • 1 - The tank currently being used. You can in theory obtain the list of ID's by looking at the res/scripts/item_defs/vehicles//list.xml file - how to decode BigWorld's packed XML is again left as an exercise to the reader.
  • 2 - The tracks fitted to the tank. You can obtain the ID's in a similar fashion as above, but from the file res/scripts/item_defs/vehicles//components/chassis.xml
  • 3 - A null byte
  • 4 - The engine fitted to the tank. The file to look at: res/scripts/item_defs/vehicles//components/engine.xml
  • 5 - A null byte
  • 6 - The fuel tank fitted to the tank. Not a user-fittable module, but as you can guess, check that res/scripts/item_defs/vehicles//components folder for the proper file to get the ID's from.
  • 7 - A null byte
  • 8 - The radio fitted to the tank
  • 9 - A null byte
  • 10 - The turret fitted to the tank
  • 11 - A null byte
  • 12 - The gun fitted to the tank

Now, that information will always be there. However, if the byte string is longer than 12 bytes, there are a few extra bits and pieces of information you can obtain:

  • 13, 14 - Unknown at this time
  • 15 - Equipment fitted into the first slot (equipment is what I call rammers, gun laying drives, and so on. Wargaming.net calls these things "optional devices")
  • 16 - A null byte
  • 17 - Equipment fitted into the second slot
  • 18 - A null byte
  • 19 -Equipment fitted into the third slot

Apparently, if you have an empty slot in the middle, offset 19 will be empty and 15 and 17 will contain your equipment. So, to get your hands on the proper ID's for the equipment, you want to check the res/scripts/item_defs/vehicles/common/optional_devices.xml file.

Now, it is possible for the byte string to go up another 7 bytes to a length of 26; what this contains is unknown. They are never the same between tanks of the same nation, with the same crew number, and the same skills and the same consumables, so that information is apparently not part of the battle roster; but some poking and digging is still ongoing.

Hope you enjoy the series so far, and happy replay file spelunking to all of you.