MineWars Data Format

The MineWars Data Format is the file format and encoding used to store MineWars game data. Specifically, this is the format of *.minewars files that can store maps and replays. It is implemented in the mw_dataformat Rust crate.

The Data Format is capable of storing:

  • Map Data
  • Other parameters and metadata of the game session
  • A stream of gameplay updates for all players in the game, multiplexed together, with timing information, to allow for watching a replay of a game.

It is not to be confused with the MineWars Player Protocol, which is what is used over-the-wire for communication between the Game Client App and Host Server for networked multiplayer gameplay.

The Player Protocol does internally use the Data Format for some purposes, such as:

  • Transmitting the map data and configuration metadata to start a game session (Initialization Sequence).
  • Encoding of most gameplay updates/events during gameplay (Game Update Messages).
  • Multiplexing the PoVs of all the players in the game for sending to spectators (Framing).

However, the Player Protocol also does a lot more. The full Player Protocol is proprietary and not publicly documented.

The Player Protocol and the Data Format are versioned separately (and separately from the MineWars client and server software), but both of their versions are important for compatibility.

Reusing the encoding of map data and gameplay updates between all of these use cases (live gameplay, spectation, replay files) makes it easier to implement all of this functionality in MineWars. That is the design goal of the Data Format.

General Properties of the Data Format

This is a custom purpose-built compact binary format.

All multi-byte values are encoded as big endian and unaligned.

All coordinates are encoded as (row: u8, col: u8) (note (Y,X) order). In places where a sequence of multiple coordinates is listed, it is recommended to encode them in sorted order. This helps compression.

Some places use a special encoding for time durations:

BitsMeaning
0xxxxxxxx milliseconds
10xxxxxx(x + 13) centiseconds
11xxxxxx(x + 8) deciseconds

PlayerId: a value between 1-15 inclusive.

PlayerSubId: a value between 0-14 inclusive.

You will also need to bring a LZ4 implementation supporting raw blocks. The lz4_flex Rust crate is perfect. :)