Data types (v47)

From wiki.vg
Revision as of 18:13, 10 January 2024 by LassiPulkkinen (talk | contribs) (Update links to Text formatting.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

This article defines the data types used in the protocol. All data sent over the network (except for VarInt and VarLong) is big-endian, that is the bytes are sent from most significant byte to least significant byte. The majority of everyday computers are little-endian, therefore it may be necessary to change the endianness before sending data over the network.

Definitions

Name Size (bytes) Encodes Notes
Boolean 1 Either false or true True is encoded as 0x01, false as 0x00.
Byte 1 An integer between -128 and 127 Signed 8-bit integer, two's complement
Unsigned Byte 1 An integer between 0 and 255 Unsigned 8-bit integer
Short 2 An integer between -32768 and 32767 Signed 16-bit integer, two's complement
Unsigned Short 2 An integer between 0 and 65535 Unsigned 16-bit integer
Int 4 An integer between -2147483648 and 2147483647 Signed 32-bit integer, two's complement
Long 8 An integer between -9223372036854775808 and 9223372036854775807 Signed 64-bit integer, two's complement
Float 4 A single-precision 32-bit IEEE 754 floating point number
Double 8 A double-precision 64-bit IEEE 754 floating point number
String ≥ 1
≤ 2147483652
A sequence of Unicode scalar values UTF-8 string prefixed with its size in bytes as a VarInt
Chat ≥ 1
≤ 2147483652
See Text formatting Encoded as a String
VarInt ≥ 1
≤ 5
An integer between -2147483648 and 2147483647 Protocol Buffer Varint, encoding a two's complement signed 32-bit integer
VarLong ≥ 1
≤ 10
An integer between -9223372036854775808 and 9223372036854775807 Protocol Buffer Varint, encoding a two's complement signed 64-bit integer
Chunk Varies A vertical chunk column See SMP Map Format#Data
Metadata Varies See Entities#Entity Metadata Format
Slot Varies See Slot Data
NBT Tag Varies See NBT
Position 8 An integer/block position: x (-33554432 to 33554431), y (-2048 to 2047), z (-33554432 to 33554431) x as a 26-bit integer, followed by y as a 12-bit integer, followed by z as a 26-bit integer (all signed, two's complement). See also the section below.
Angle 1 A rotation angle in steps of 1/256 of a full turn Whether or not this is signed does not matter, since the resulting angles are the same.
UUID 16 A UUID Encoded as an unsigned 64-bit integer
Optional X 0 or size of X A field of type X, or nothing Whether or not the field is present must be known from the context.
Array of X count times size of X Zero or more fields of type X The count must be known from the context.
X Enum size of X A specific value from a given list The list of possible values and how each is encoded as an X must be known from the context.
Byte Array Varies Depends on context This is just a sequence of zero or more bytes, its meaning should be explained somewhere else, e.g. in the packet description. The length must also be known from the context.

Position

64-bit value split in to three parts

  • x: 26 MSBs
  • z: 26 LSBs
  • y: 12 bits between them

Encoded as followed:

((x & 0x3FFFFFF) << 38) | ((y & 0xFFF) << 26) | (z & 0x3FFFFFF)

And decoded as:

val = read_long();
x = val >> 38;
y = (val >> 26) & 0xFFF;
z = val & 0x3FFFFFF;

Note: The details of bit shifting are rather language dependent; the above may work in Java but probably won't in other languages without some tweaking. In particular, you will usually receive positive numbers even if the actual coordinates are negative. This can be fixed by adding something like the following:

if x >= 2^25 { x -= 2^26 }
if y >= 2^11 { y -= 2^12 }
if z >= 2^25 { z -= 2^26 }

Fixed-point numbers

Some fields may be stored as fixed-point numbers, where a certain number of bits represents the signed integer part (number to the left of the decimal point) and the rest represents the fractional part (to the right). Floating points (float and double), in contrast, keep the number itself (mantissa) in one chunk, while the location of the decimal point (exponent) is stored beside it.

Essentially, while fixed-point numbers have lower range than floating points, their fractional precision is greater for higher values. This makes them ideal for representing global coordinates of an entity in Minecraft, as it's more important to store the integer part accurately than position them more precisely within a single block (or meter).

Coordinates are often represented as a 32-bit integer, where 5 of the least-significant bits are dedicated to the fractional part, and the rest store the integer part.

Java lacks support for fractional integers directly, but you can represent them as integers. To convert from a double to this integer representation, use the following formulas:

 abs_int = (int)double * 32;

And back again:

 double = (double)abs_int / 32;