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_mountains
easter
, generic_lamps
,
generic_shadows
, light
type_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 data
Quad:
[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
data
name
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 radius
type_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-b11ae041d0d8
item_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