This file is mirrored from the libtw2 documentation and is dual-licensed under MIT or APACHE.
Teeworlds and DDNet maps get saved as datafiles. If you are not yet familiar with parsing datafiles, please go through the datafile documentation first.
integer types are usually declared in the same notation as in rust. Examples:
i32is a signed 32 bit integer
u8is a unsigned 8 bit integer,
byteis used synonymously
& is the prefix for data item indices. Those point to a data item
datafile.data section of the datafile.
opt is the prefix for optional indices. They are either a normal
-1, marking it as unused.
* is the prefix for indices that point to another item in the
*imagemeans that the field points to an image item.
*color_envelopewould mean that the field points to the envelope item with that index, which should be a color envelope.
CString is a null terminated UTF-8 string.
I32String is a CString stored in consecutive i32 values. To extract the string:
Point is a struct with two i32s, one for x, one for y. It is usually used to describe a position in the map. 0, 0 is the top-left corner.
Color is a struct with the 4 u8 values (in order): r, g, b, a. Its still usually parsed from 4 i32s, meaning each one should hold a value that fits into an u8.
item_data of an item is an array of i32s. We will split the
item_data up into its different elements, which differ for each
item type. Examples for the
 point: Point=> The next two i32 values represent the variable
point(which will be explained afterwards) which is of the type
 opt &name: CString=> The next i32 represents
nameand is an optional data item index to a CString.
General map structure: > Info > Images > Envelopes > Envelope Points > Groups > Layers > Auto Mappers (DDNet only) > Sounds (DDNet only)
Maps consist of various elements that each have a
type_id mappings: 0 -> Version 1 -> Info 2 -> Images 3 -> Envelopes 4 -> Groups 5 -> Layers 6 -> Envelope Points 7 -> Sounds (DDNet only) 0xffff -> UUID Index (see below, DDNet only)
Use them to figure out which purpose each of the item types in the
datafile.item_types section of the datafile has.
Things to keep in mind:
datafile.item_types, it means that there must be at least one item of that type
id= 0 and from there it will count up
In DDNet, some item types won’t be assigned a type_id, but instead an uuid.
To find the correct item type (in
datafile.item_types for uuid item
types, you will need their
type_id. You will need to figure out the
type_id manually by looking into the UUID Index items.
UUID Index Item structure: type_id: 0xffff id: type_id of the uuid item type that this item represents item_data:  UUID of the uuid item type that this item represents
item_datawhen viewing the integers as big endian
item_data, copy the
type_idthat we just found out
item_data of the only version item:  version
item_data of the only version item:  (item) version  opt &author: CString  opt &version: CString  opt &credits: CString  opt &license: CString  opt &settings: [CString] (DDNet only)
settingsis an array of CStrings, all consecutive, split by their null bytes (with a null byte at the very end)
item_data of image items:  version  width  height  external: bool  &name: CString  opt &data: [Pixel] version 2 extension (Vanilla only):  variant
version= 2, DDNet is at
heightspecify the dimensions of the image
version= 1, the image is of type RGBA, for
variantholds the type:
external= false and have the image data stored in the data field. The image data is simply a 2d-array of pixels in row-major ordering. RGBA pixels are 4 bytes each, RGB pixels 3 bytes each.
external= true and the
-1. Those images can only be loaded by clients that have those in their
mapresdirectory, meaning only a small set of images should be external. The client looks for those images by using the
namemust fit into 128 bytes
item_data of envelope items:  version  channels  start_point  num_points extension without version change:  name: I32String version 2 extension:  synchronized: bool
version= 2, Vanilla chooses 3 for all envelopes when one of them uses a bezier curve, but falls back to 2 when there is none.
channelholds the type of the envelope
synchronizedhas the effect that the envelope syncs to server time, not player join time
start_pointis the index of its first envelope point
num_pointsis the number of envelope points for this envelope
See Envelope Points to see how the envelope points are stored.
item_data of the only item contains all the envelope points used
for the envelopes.
The first 6 i32 of each envelope point, depending on the envelope type it belongs to:
sound envelope point:  time  curve type  volume  - position envelope point:  time  curve_type  x  y  rotation  - color envelope point:  time  curve type  color: I32Color
time is the timestamp of the point, it should increase
monotonously within each envelope
curve_type holds how the curve should bend between this point and
the next one
y hold the movement
I32Color actually means that the color values for r, g, b, a are i32 values
If bezier curves are used anywhere (envelope version 3), then there are
16 more i32 for each point. These are only non-zero if the
of the point is 5 (Bezier):
bezier point extension:  in_tangent_dx  in_tangent_dy  out_tangent_dx  out_tangent_dy
item_data of group items  version  x_offset  y_offset  x_parallax  y_parallax  start_layer  num_layers version 2 extension:  clipping: bool  clip_x  clip_y  clip_width  clip_height version 3 extension:  name: I32String
num_layerstell you which layers belong to this group. Groups are not allowed to overlap, however, the reference implementation has no such checks while loading.
y_parallaxshould each be 100 and the
nameshould be “Game”. Note that the reference implementation does not verify this but instead just overwrites those values
item_data base for all layer items (different types have different extensions):  _version (not used, was uninitialized)  type  flags
flagscurrently only has the detail flag (at 2^0), which is used in Quad-, Tile- and Sound layers.
typeholds the type of layer:
item_data extension for tilemap layers:  version  width  height  type  color: Color  opt *color_envelope  color_envelope_offset  opt *image  &data: 2d-array of the the tile type 'Tile' version 3 extension:  name: I32String DDNet extension (no version change):  opt &data_tele  opt &data_speedup  opt &data_front  opt &data_switch  opt &data_tune
Vanilla is at
version = 4, DDNet at
version = 3
height specify the dimensions of the layer
type tells you what kind of tilemap layer this is:
image are only
used by the tiles layer
all tile types consist of bytes (u8)
all 2d-arrays of tiles use row-major ordering
all tile types have the
id byte, which identifies its use
many have a
flags byte, which is a bitflag with the following
'Tile' tile type (consiting of bytes, used by all vanilla layers and the front layer):  id  flags  skip  - unused
skipbyte is used for the 0.7 compression, which is used if
datafield no longer points to an 2d-array of tiles, but instead to an array of ‘Tile’ tiles which must be expanded into the 2d-array
skipfield of each tile in the array tells you how many times this tile is used in a row. For example:
skipfield to 0 while expanding
skipvalues to 0 in this step
DDNet only content:
version= 3 extension, meaning you have to subtract 3 (the length of the
namefield) from the data index
datafield is not actually optional like all the other data fields. For vanilla compatibility, the
datafield always points to a 2d-array of tiles of the type ‘Tile’, with the same dimensions as the actual layer, but everything zeroed out
Special tile types:
'Tele' tile type (consiting of bytes):  number  id
numberis the number of the teleporter exit/entry to group them together
'Speedup' tile type (consiting of bytes):  force  max_speed  id  - unused padding byte  angle: i16
'Switch' tile type (consiting of bytes):  number  id  flags  delay
numberonce again tells you which tiles interact with each other
'Tune' tile type (consiting of bytes):  number  id
numberstores which zone this is, zones are defined in the map info -> settings
item_data extension for quads layers:  version  num_quads  &data: [Quads]  opt *image version 2 extension:  name: I32String
num_quadsis the amount of quads found behind the data item pointer
Quad:  position: Point  corner_positions: [Point; 4]  corner_colors: [Color; 4]  texture_coordinates: [Point; 4]  opt *position_envelope  position_envelope_offset  opt *color_envelope  color_envelope_offset
item_data extension for sounds layers:  version  num_sources  &data: [SoundSource]  opt *sound  name: I32String
namemust fit into 128 bytes
SoundSource:  position: Point  looping: bool  panning: bool  delay (in seconds)  falloff: u8  *position_envelope  position_envelope_offset  *sound_envelope  sound_envelope_offset  shape: SoundShape SoundShape:  kind  width / radius  height / - unused
Deprecated Sounds layer
item_datais the same as in the Sounds layer
deprecated SoundSource:  position: Point  looping: bool  delay  radius  *position_envelope  position_envelope_offset  *sound_envelope  sound_envelope_offset
Use the following values to convert a deprecated SoundSource:
shape: kind = circle, with shared
item_data of sound items:  version  external: bool  &name: CString  &data  data_size
externalshould always be false and
datashould not be considered an option index
datapoints to opus sound data
item_data of auto mapper items:  _version (not used, was uninitialized)  *group  *layer  opt config  seed  flags
grouppoints to a group,
layeris the layer index within the group
flagscurrently only has the
automaticflag at 2^0, which tells the client to auto map after any changes