This wiki is deprecated. Visit https://ddnet.org/docs/libtw2/map for the current version of this page
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:
i32 is a signed 32 bit integeru8 is a unsigned 8 bit integer, byte is used synonymously& is the prefix for data item indices. Those point to a data item
in the datafile.data section of the datafile.
opt is the prefix for optional indices. They are either a normal
index or -1, marking it as unused.
* is the prefix for indices that point to another item in the
datafile.
*image means that the field points to an image
item. *color_envelope would 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.
the 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 item_data syntax:
[2] point: Point => The next two i32 values represent the
variable point (which will be explained afterwards) which is
of the type Point.[1] opt &name: CString => The next i32 represents name and
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 that
identifies them.
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 typeid = 0 and from there it will count upIn 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:
[3] UUID of the uuid item type that this item represents
item_data when viewing the integers as big endianitem_data, copy the
type_id from the id fieldtype_id that we just found outtype_id = 0item_data of the only version item:
[1] version
version = 1type_id = 1item_data of the only version item:
[1] (item) version
[1] opt &author: CString
[1] opt &version: CString
[1] opt &credits: CString
[1] opt &license: CString
[1] opt &settings: [CString] (DDNet only)
version = 1settings is an array of CStrings, all
consecutive, split by their null bytes (with a null byte at the very
end)type_id = 2item_data of image items:
[1] version
[1] width
[1] height
[1] external: bool
[1] &name: CString
[1] opt &data: [Pixel]
version 2 extension (Vanilla only):
[1] variant
version = 2, DDNet is at version = 1width and height specify the dimensions of the imageversion = 1, the image is of type RGBA, for version = 2
variant holds 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 data field on
-1. Those images can only be loaded by clients that have those
in their mapres directory, meaning only a small set of images
should be external. The client looks for those images by using
the name field.name must fit into 128 bytesbg_cloud1, bg_cloud2, bg_cloud3,
desert_doodads, desert_main, desert_mountains2,
desert_mountains, desert_sun, generic_deathtiles,
generic_unhookable, grass_doodads, grass_main,
jungle_background, jungle_deathtiles, jungle_doodads,
jungle_main, jungle_midground, jungle_unhookables, moon,
mountains, snow, stars, sun, winter_doodads,
winter_main, winter_mountains2, winter_mountains3,
winter_mountainseaster, generic_lamps,
generic_shadows, lighttype_id = 3item_data of envelope items:
[1] version
[1] channels
[1] start_point
[1] num_points
extension without version change:
[8] name: I32String
version 2 extension:
[1] 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.channel holds the type of the envelope
synchronized has the effect that the envelope syncs to server
time, not player join timestart_point is the index of its first envelope pointnum_points is the number of envelope points for this envelopeSee Envelope Points to see how the envelope points are stored.
type_id = 6The item_data of the only item contains all the envelope points used
for the envelopes.
version = 3version <= 2The first 6 i32 of each envelope point, depending on the envelope type it belongs to:
sound envelope point:
[1] time
[1] curve type
[1] volume
[3] -
position envelope point:
[1] time
[1] curve_type
[1] x
[1] y
[1] rotation
[1] -
color envelope point:
[1] time
[1] curve type
[4] 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
x and 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 curve_type
of the point is 5 (Bezier):
bezier point extension:
[4] in_tangent_dx
[4] in_tangent_dy
[4] out_tangent_dx
[4] out_tangent_dy
type_id = 4item_data of group items
[1] version
[1] x_offset
[1] y_offset
[1] x_parallax
[1] y_parallax
[1] start_layer
[1] num_layers
version 2 extension:
[1] clipping: bool
[1] clip_x
[1] clip_y
[1] clip_width
[1] clip_height
version 3 extension:
[3] name: I32String
version = 3start_layer and num_layers tell you which layers belong to this
group. Groups are not allowed to overlap, however, the reference
implementation has no such checks while loading.x_parallax
and y_parallax should each be 100 and the name should be “Game”.
Note that the reference implementation does not verify this but
instead just overwrites those valuestype_id = 5Layer types:
Note that:
item_data base for all layer items (different types have different extensions):
[1] _version (not used, was uninitialized)
[1] type
[1] flags
flags currently only has the detail flag (at 2^0), which is used
in Quad-, Tile- and Sound layers.type holds the type of layer:
item_data extension for tilemap layers:
[1] version
[1] width
[1] height
[1] type
[4] color: Color
[1] opt *color_envelope
[1] color_envelope_offset
[1] opt *image
[1] &data: 2d-array of the the tile type 'Tile'
version 3 extension:
[3] name: I32String
DDNet extension (no version change):
[1] opt &data_tele
[1] opt &data_speedup
[1] opt &data_front
[1] opt &data_switch
[1] opt &data_tune
Vanilla is at version = 4, DDNet at version = 3
width and height specify the dimensions of the layer
type tells you what kind of tilemap layer this is:
color, color_envelope, color_envelope_offset, 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
bits:
'Tile' tile type (consiting of bytes, used by all vanilla layers and the front layer):
[1] id
[1] flags
[1] skip
[1] - unused
skip byte is used for the 0.7 compression, which is used if
version >= 4:
data field no longer points to an 2d-array of tiles, but
instead to an array of ‘Tile’ tiles which must be expanded into
the 2d-arrayskip field of each tile in the array tells you how many
times this tile is used in a row. For example:
skip is 255skip field to 0 while expanding
skip values to 0 in this
stepDDNet only content:
version = 3 extension, meaning
you have to subtract 3 (the length of the name field) from the
data indexdata field is not actually
optional like all the other data fields. For vanilla compatibility,
the data field always points to a 2d-array of tiles of the type
‘Tile’, with the same dimensions as the actual layer, but everything
zeroed outSpecial tile types:
'Tele' tile type (consiting of bytes):
[1] number
[1] id
number is the number of the teleporter exit/entry to group them
together'Speedup' tile type (consiting of bytes):
[1] force
[1] max_speed
[1] id
[1] - unused padding byte
[2] angle: i16
'Switch' tile type (consiting of bytes):
[1] number
[1] id
[1] flags
[1] delay
number once again tells you which tiles interact with each other'Tune' tile type (consiting of bytes):
[1] number
[1] id
number stores which zone this is, zones are defined in the map
info -> settingsQuads layer
item_data extension for quads layers:
[1] version
[1] num_quads
[1] &data: [Quads]
[1] opt *image
version 2 extension:
[3] name: I32String
version = 2num_quads is the amount of quads found behind the data item
pointer dataQuad:
[2] position: Point
[8] corner_positions: [Point; 4]
[16] corner_colors: [Color; 4]
[8] texture_coordinates: [Point; 4]
[1] opt *position_envelope
[1] position_envelope_offset
[1] opt *color_envelope
[1] color_envelope_offset
Sounds layer
item_data extension for sounds layers:
[1] version
[1] num_sources
[1] &data: [SoundSource]
[1] opt *sound
[3] name: I32String
dataname must fit into 128 bytesSoundSource:
[2] position: Point
[1] looping: bool
[1] panning: bool
[1] delay (in seconds)
[1] falloff: u8
[1] *position_envelope
[1] position_envelope_offset
[1] *sound_envelope
[1] sound_envelope_offset
[3] shape: SoundShape
SoundShape:
[1] kind
[1] width / radius
[1] height / - unused
kind:
width and height)radius)Deprecated Sounds layer
item_data is the same as in the Sounds layerdeprecated SoundSource:
[2] position: Point
[1] looping: bool
[1] delay
[1] radius
[1] *position_envelope
[1] position_envelope_offset
[1] *sound_envelope
[1] sound_envelope_offset
Use the following values to convert a deprecated SoundSource:
panning = truefalloff = 0shape: kind = circle, with shared radiustype_id = 7item_data of sound items:
[1] version
[1] external: bool
[1] &name: CString
[1] &data
[1] data_size
version = 1external should always
be false and data should not be considered an option indexdata points to opus sound datauuid = 16271b3e-8c17-7839-9bd9-b11ae041d0d8item_data of auto mapper items:
[1] _version (not used, was uninitialized)
[1] *group
[1] *layer
[1] opt config
[1] seed
[1] flags
group points to a group, layer is the layer index within the
groupflags currently only has the automatic flag at 2^0, which tells
the client to auto map after any changes