Difference between revisions of "Classic Protocol"

From wiki.vg
Jump to navigation Jump to search
m (→‎Server → Client packets: I was kicked with this message while experimenting.)
 
(28 intermediate revisions by 13 users not shown)
Line 3: Line 3:
 
==Minecraft.net Communication==
 
==Minecraft.net Communication==
 
===Heartbeats===
 
===Heartbeats===
To be able to connect to a server in Minecraft Classic from the Server List, a server must broadcast to minecraft.net a so-called "heartbeat" every few minutes.
+
To be able to connect to a server in Minecraft Classic from the server list, a server must broadcast a so-called "heartbeat" every few minutes.
  
 
The stock server broadcasts this heartbeat every 45 seconds.
 
The stock server broadcasts this heartbeat every 45 seconds.
  
A "heartbeat" takes the form of an HTTP request to http://www.minecraft.net/heartbeat.jsp.
+
A "heartbeat" takes the form of an HTTP request to http://www.minecraft.net/heartbeat.jsp. The server list has since been shut down.
 
After sending a heartbeat, the URL for the server is returned.
 
After sending a heartbeat, the URL for the server is returned.
  
Line 16: Line 16:
 
|port || Port number of the server. This is usually 25565
 
|port || Port number of the server. This is usually 25565
 
|-
 
|-
|max || Maximum number of players on the server
+
|max || Maximum number of players allowed on the server
 
|-
 
|-
 
|name || The name of the server
 
|name || The name of the server
 
|-
 
|-
|public || Whether the server is public (i.e. appears in the lobby) or not. Can be '''True''' or '''False''', in that capitalisation.
+
|public || Whether the server is public (i.e. appears in the server list) or not. Can be '''True''' or '''False''', in that capitalization.
 
|-
 
|-
|version || Minecraft version, this should be 7
+
|version || Protocol version number, this should be 7 unless you're using a client version older than 0.28.
 
|-
 
|-
 
|salt || A random, 16-character base-62 salt
 
|salt || A random, 16-character base-62 salt
Line 28: Line 28:
 
|users || Number of users connected to the server
 
|users || Number of users connected to the server
 
|}
 
|}
The simplest way to send a heartbeat is to open a TCP socket to port 80 on minecraft.net, and send the following (with the values changed, obviously):
+
The simplest way to send a heartbeat is to open a TCP socket to port 80 to the server list, and send the following (with the values changed, obviously):
  
 
'''GET /heartbeat.jsp?port=25565&max=32&name=My%20Server&public=True&version=7&salt=wo6kVAHjxoJcInKx&users=0''', plus a CRLF(Carriage-return and Line feed).
 
'''GET /heartbeat.jsp?port=25565&max=32&name=My%20Server&public=True&version=7&salt=wo6kVAHjxoJcInKx&users=0''', plus a CRLF(Carriage-return and Line feed).
Line 39: Line 39:
 
The "key" provided when a user joins the server can be compared to the MD5 checksum of the server's "salt" plus the username to verify that the user is logged in to minecraft.net with that username.  This is useful for establishing enough trust of the name provided to ban or op the player by name.
 
The "key" provided when a user joins the server can be compared to the MD5 checksum of the server's "salt" plus the username to verify that the user is logged in to minecraft.net with that username.  This is useful for establishing enough trust of the name provided to ban or op the player by name.
  
  if( player.key == md5( server.salt + player.name ) ) {
+
  if (player.key == md5(server.salt + player.name)) {
 
   // player is logged in via minecraft.net
 
   // player is logged in via minecraft.net
 
  } else {
 
  } else {
Line 52: Line 52:
 
==Packet Protocol==
 
==Packet Protocol==
  
Every packet starts with a byte representing the Packet ID.
+
The connection is done over TCP. Every packet starts with a byte representing the Packet ID.
  
 
=== Protocol Data Types ===
 
=== Protocol Data Types ===
 +
 +
For details on fields such as player IDs and position, see below.
 +
 +
All numbers are in [http://en.wikipedia.org/wiki/Endianness#Networking network order] (big-endian).
 +
Signed integers are in two's compliment.
 +
 +
The last 5 bits of the fixed-point types are fractional, i.e. they come after the "point".
 +
You can think of these as 32ths of a block (2<sup>5</sup>=32).
 +
To convert to a block position (integer), it needs to be rounded ''down'', this is equivalent to an arithmetic shift right by 5.
 +
 
{| class="wikitable"
 
{| class="wikitable"
!Type !! Size [bytes] !! Description
+
!Type !! Bytes !! Description
 
|-
 
|-
|Byte || 1 || Single byte integer (0 to 255)
+
|Byte || 1 || Unsigned byte (0 to 255)
 
|-
 
|-
|SByte || 1 || Single byte signed integer (-128 to 127)
+
|SByte || 1 || Signed byte (-128 to 127)
 
|-
 
|-
|Short || 2 || Signed integer, [http://en.wikipedia.org/wiki/Endianness#Endianness_in_networking network order] (-32768 to 32767)
+
|FByte || 1 || Signed fixed-point, 5 fractional bits (-4 to 3.96875)
 
|-
 
|-
|String || 64 || US-ASCII/ISO646-US encoded string padded with spaces (0x20)
+
|Short || 2 || Signed integer (-32768 to 32767)
 +
|-
 +
|FShort || 2 || Signed fixed-point, 5 fractional bits (-1024 to 1023.96875)
 +
|-
 +
|String || 64 || [https://en.wikipedia.org/wiki/ASCII US-ASCII] encoded string padded with spaces (0x20)
 
|-
 
|-
 
|Byte array || 1024 || Binary data padded with null bytes (0x00)
 
|Byte array || 1024 || Binary data padded with null bytes (0x00)
Line 80: Line 94:
 
|rowspan=5| Player Identification
 
|rowspan=5| Player Identification
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=5| Sent by a player joining a server with relevant information.  Current protocol version is 0x07.
+
|rowspan=5| Sent by a player joining a server with relevant information.  The protocol version is 0x07, unless you're using a client below 0.28.
 
|-
 
|-
 
| Protocol version || Byte
 
| Protocol version || Byte
Line 88: Line 102:
 
| Verification key || String
 
| Verification key || String
 
|-
 
|-
| Unused || Byte
+
| Unused || Byte (0x00)
 
|-
 
|-
 
|rowspan=6| 0x05
 
|rowspan=6| 0x05
Line 94: Line 108:
 
| Packet ID || Byte
 
| Packet ID || Byte
 
|rowspan=6| Sent when a user changes a block.  The mode field indicates whether a block was created (0x01) or destroyed (0x00).
 
|rowspan=6| Sent when a user changes a block.  The mode field indicates whether a block was created (0x01) or destroyed (0x00).
Block type is always the type player is holding, (even when deleting).
+
Block type is always the type player is holding, even when destroying.
  
 
Client assumes that this command packet always succeeds, and so draws the new block immediately. To disallow block creation, server must send back Set Block packet with the old block type.
 
Client assumes that this command packet always succeeds, and so draws the new block immediately. To disallow block creation, server must send back Set Block packet with the old block type.
 
The XYZ coordinates of the block are just integers representing the coordinate of the block. (As opposed to player coordinates where the lower 5 bits are fractional coordinates)
 
 
|-
 
|-
 
| X || Short
 
| X || Short
Line 113: Line 125:
 
|rowspan=7| Position and Orientation
 
|rowspan=7| Position and Orientation
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=7| Sent frequently (even while not moving) by the player with the player's current location and orientation. Player ID is always 255, referring to itself. Player coordinates are fixed-point values with the lowest 5 bits representing the fractional position (i.e. divide by 32 to get actual position in terms of block coordinates).  The angle parameters are scaled such that a value of 256 would correspond to 360 degrees.
+
|rowspan=7| Sent frequently (even while not moving) by the player with the player's current location and orientation. Player ID is always -1 (255), referring to itself.
 
|-
 
|-
| Player ID || Byte
+
| Player ID || SByte (0xFF)
 
|-
 
|-
| X || Short
+
| X || FShort
 
|-
 
|-
| Y || Short
+
| Y || FShort
 
|-
 
|-
| Z || Short
+
| Z || FShort
 
|-
 
|-
 
| Yaw (Heading) || Byte
 
| Yaw (Heading) || Byte
Line 130: Line 142:
 
|rowspan=3| Message
 
|rowspan=3| Message
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=3| Contain chat messages sent by player. (See [[Chat|How chat works]])
+
|rowspan=3| Contain chat messages sent by player. Player ID is always -1 (255), referring to itself. (See [[Text formatting#Formatting codes|how chat works]] - note that Classic '''only''' supports color codes.)
 
|-
 
|-
| Unused, maybe message color || Byte (0xFF)
+
| Player ID || SByte (0xFF)
 
|-
 
|-
 
| Message || String
 
| Message || String
Line 148: Line 160:
 
|rowspan=5| Server Identification
 
|rowspan=5| Server Identification
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=5| Response to a joining player.  The user type indicates whether a player is an op (0x64) or not (0x00)  Current protocol version is 0x07.
+
|rowspan=5| Response to a joining player.  The user type indicates whether a player is an op (0x64) or not (0x00) which decides if the player can delete bedrock. The protocol version is 0x07, unless you're using a client below 0.28.
 
|-
 
|-
 
| Protocol version || Byte
 
| Protocol version || Byte
Line 166: Line 178:
 
| Level Initialize
 
| Level Initialize
 
| Packet ID || Byte
 
| Packet ID || Byte
| Notifies player of incoming level data.
+
| Notifies the player of incoming level data.
 
|-
 
|-
 
|rowspan=4| 0x03
 
|rowspan=4| 0x03
 
|rowspan=4| Level Data Chunk
 
|rowspan=4| Level Data Chunk
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=4| Contains a chunk of gzipped map (not level.dat file). After decompression the map consists of a int(4 bytes) containing number of blocks + raw map array. (chunk is up to 1024 bytes, padded with 0x00s if less).
+
|rowspan=4| Contains a chunk of the [[#Level Data|gzipped level data]], to be concatenated with the rest. Chunk Data is up to 1024 bytes, padded with 0x00s if less.
 
|-
 
|-
 
| Chunk Length || Short
 
| Chunk Length || Short
Line 206: Line 218:
 
|rowspan=8| Spawn Player
 
|rowspan=8| Spawn Player
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=8| Sent to indicate where a new player is spawning in the world. Position and orientation are encoded the same as for packet 0x08 below.
+
|rowspan=8| Sent to indicate where a new player is spawning in the world. This will set the player's spawn point.
 
|-
 
|-
 
| Player ID || SByte
 
| Player ID || SByte
Line 212: Line 224:
 
| Player Name || String
 
| Player Name || String
 
|-
 
|-
| X || Short
+
| X || FShort
 
|-
 
|-
| Y || Short
+
| Y || FShort
 
|-
 
|-
| Z || Short
+
| Z || FShort
 
|-
 
|-
 
| Yaw (Heading) || Byte
 
| Yaw (Heading) || Byte
Line 223: Line 235:
 
|-
 
|-
 
|rowspan=7| 0x08
 
|rowspan=7| 0x08
|rowspan=7| Position and Orientation (Player Teleport)
+
|rowspan=7| Set Position and Orientation (Player Teleport)
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=7| Sent with changes in player position and rotation. Teleports player it's sent to if player ID < 0 (For sending initial position in map, and /tp)
+
|rowspan=7| Sent with changes in player position and rotation. Used for sending initial position on the map, and teleportation.
 +
Some servers don't send relative packets, opting to only use this one.
 
|-
 
|-
 
| Player ID || SByte
 
| Player ID || SByte
 
|-
 
|-
| X || Short
+
| X || FShort
 
|-
 
|-
| Y || Short
+
| Y || FShort
 
|-
 
|-
| Z || Short
+
| Z || FShort
 
|-
 
|-
 
| Yaw (Heading) || Byte
 
| Yaw (Heading) || Byte
Line 247: Line 260:
 
| Player ID || SByte
 
| Player ID || SByte
 
|-
 
|-
| Change in X || SByte
+
| Change in X || FByte
 
|-
 
|-
| Change in Y || SByte
+
| Change in Y || FByte
 
|-
 
|-
| Change in Z || SByte
+
| Change in Z || FByte
 
|-
 
|-
 
| Yaw (Heading) || Byte
 
| Yaw (Heading) || Byte
Line 265: Line 278:
 
| Player ID || SByte
 
| Player ID || SByte
 
|-
 
|-
| Change in X || SByte
+
| Change in X || FByte
 
|-
 
|-
| Change in Y || SByte
+
| Change in Y || FByte
 
|-
 
|-
| Change in Z || SByte
+
| Change in Z || FByte
 
|-
 
|-
 
|rowspan=4| 0x0b
 
|rowspan=4| 0x0b
Line 286: Line 299:
 
|rowspan=2| Despawn Player
 
|rowspan=2| Despawn Player
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=2| Sent when player disconnects.
+
|rowspan=2| Sent to others when the player disconnects.
 
|-
 
|-
 
| Player ID || SByte
 
| Player ID || SByte
Line 293: Line 306:
 
|rowspan=3| Message
 
|rowspan=3| Message
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=3| Messages sent by chat or from the console. (See [[Chat|How chat works]])
+
|rowspan=3| Messages sent by chat or from the console. (See [[Chat#Old_system|how chat works]] - note that Classic '''only''' supports color codes.)
 
|-
 
|-
 
| Player ID || SByte
 
| Player ID || SByte
Line 300: Line 313:
 
|-
 
|-
 
|rowspan=2| 0x0e
 
|rowspan=2| 0x0e
|rowspan=2| Disconnect player
+
|rowspan=2| Disconnect Player
 
| Packet ID || Byte
 
| Packet ID || Byte
 
|rowspan=2| Sent to a player when they're disconnected from the server.
 
|rowspan=2| Sent to a player when they're disconnected from the server.
Line 306: Line 319:
 
#"Cheat detected: Tile type"
 
#"Cheat detected: Tile type"
 
#"Cheat detected: Too much clicking!"
 
#"Cheat detected: Too much clicking!"
 +
#"Cheat detected: Too much lag"
 
|-
 
|-
 
| Disconnect reason || String
 
| Disconnect reason || String
 
|-
 
|-
 
|rowspan=2| 0x0f
 
|rowspan=2| 0x0f
|rowspan=2| Update user type
+
|rowspan=2| Update User Type
 
| Packet ID || Byte
 
| Packet ID || Byte
|rowspan=2| Sent when a player is opped/deopped
+
|rowspan=2| Sent when a player is opped/deopped. User type is 0x64 for op, 0x00 for normal user. This decides if the player can delete bedrock.
 
|-
 
|-
 
| User type || Byte
 
| User type || Byte
 
|-
 
|-
 
|}
 
|}
 +
 +
==Player IDs==
 +
Player IDs are treated as a signed byte.
 +
 +
The client is never told it's own player ID, when referencing itself the ID of -1 (255) is always used.
 +
 +
Some clients (notably the original), accept ''any'' negative number (128-255) as meaning the client itself, others ''only'' accept -1.
 +
This means that some clients can handle players with IDs less than -1, and others will combine them with itself.
  
 
==Player Position==
 
==Player Position==
===Fixed Point===
 
Player position is represented via X, Y, and Z fixed-point coordinates.  The fractional portion is 5 bits, so dividing the short integers received in position update packets by 32, you will have floating point coordinates for the player. This position corresponds to the center of the client viewport.
 
 
===Standing On Things===
 
===Standing On Things===
 +
A player's position corresponds to the center of the client viewport.
 +
 
The bottom of the player's feet is located 1.59375 (fixed-point: 51) units below the center of the viewport, so to position the player on top of a particular block you could send a teleport (0x08) packet specifying a Y value based on the block position as: (Y x 32 + 51)
 
The bottom of the player's feet is located 1.59375 (fixed-point: 51) units below the center of the viewport, so to position the player on top of a particular block you could send a teleport (0x08) packet specifying a Y value based on the block position as: (Y x 32 + 51)
 +
 
===Orientation===
 
===Orientation===
 
A yaw value of 0 means the player is facing in the Z=0 (negative Z) direction.  This value increases in a clockwise direction as seen from above.  If we call the negative Z direction "North", then a yaw of 64 means "East", 128 means "South", and 192 means "West".
 
A yaw value of 0 means the player is facing in the Z=0 (negative Z) direction.  This value increases in a clockwise direction as seen from above.  If we call the negative Z direction "North", then a yaw of 64 means "East", 128 means "South", and 192 means "West".
  
 
A pitch value of 0 means level and this value increases in a downward direction.  64 is down, and 192 is up.  Values of 65 to 191 should never occur because the player cannot look further up or down than the 64 → 0, 255 → 192 range. However, the Minecraft Classic client does not ignore invalid values, so it is possible to make players' heads "upside-down".
 
A pitch value of 0 means level and this value increases in a downward direction.  64 is down, and 192 is up.  Values of 65 to 191 should never occur because the player cannot look further up or down than the 64 → 0, 255 → 192 range. However, the Minecraft Classic client does not ignore invalid values, so it is possible to make players' heads "upside-down".
 +
 +
==Level Data==
 +
Level data is an array of block types, as bytes in XZY order.
 +
XZY order means you first increment the X, then the Z, then the Y.
 +
 +
Before being sent to the client, it is prefixed with its length as a big-endian int (4 bytes), and then gzipped (not zlib or plain deflate). This is then split into 1024 byte chunks, to be sent to the client in Level Data Chunk packets. The final chunk is padded with 0x00 bytes.
 +
 +
When the client receives a data chunk, it should concatenate it to the end of the previous chunks, only stripping 0x00s from the end of the final one. The entire data should then be gzip inflated.
  
 
==Color Codes==
 
==Color Codes==
Line 335: Line 366:
 
Colour coding at the start of the message will only work if the player ID byte is less than 127. If it's 127 or higher, the game automatically adds &e before the message, making it yellow. However, colour codes after the first character still work. If you use an ID below 127, it doesn't add a colour code, so the ones you use will work.
 
Colour coding at the start of the message will only work if the player ID byte is less than 127. If it's 127 or higher, the game automatically adds &e before the message, making it yellow. However, colour codes after the first character still work. If you use an ID below 127, it doesn't add a colour code, so the ones you use will work.
  
It is important to note that an ampersand at the end of a message that is not followed by a hex digit will crash all clients that receive it, so it is a must to sanitize chat messages received from clients.
+
It is important to note that an ampersand at the end of a message that is not followed by a hex digit '''will crash all clients''' that receive it, so it is a must to sanitize all chat messages received from clients.
  
 
[[File:Colors.png|thumb|Hex digit to color mapping]]
 
[[File:Colors.png|thumb|Hex digit to color mapping]]
Line 403: Line 434:
 
| &f || White || 255 || 255 || 255 || 63 || 63 || 63
 
| &f || White || 255 || 255 || 255 || 63 || 63 || 63
 
|}
 
|}
 +
 +
[[Category:Minecraft Classic]]

Revision as of 18:52, 13 January 2024

Documentation on the server protocol used by the Minecraft Classic Creative server.

Minecraft.net Communication

Heartbeats

To be able to connect to a server in Minecraft Classic from the server list, a server must broadcast a so-called "heartbeat" every few minutes.

The stock server broadcasts this heartbeat every 45 seconds.

A "heartbeat" takes the form of an HTTP request to http://www.minecraft.net/heartbeat.jsp. The server list has since been shut down. After sending a heartbeat, the URL for the server is returned.

It can be a GET or POST request. A table of the required parameters is below:

Name Details
port Port number of the server. This is usually 25565
max Maximum number of players allowed on the server
name The name of the server
public Whether the server is public (i.e. appears in the server list) or not. Can be True or False, in that capitalization.
version Protocol version number, this should be 7 unless you're using a client version older than 0.28.
salt A random, 16-character base-62 salt
users Number of users connected to the server

The simplest way to send a heartbeat is to open a TCP socket to port 80 to the server list, and send the following (with the values changed, obviously):

GET /heartbeat.jsp?port=25565&max=32&name=My%20Server&public=True&version=7&salt=wo6kVAHjxoJcInKx&users=0, plus a CRLF(Carriage-return and Line feed).

Make sure any strings, like name, are escaped.

If everything goes well, in the response body you'll receive a URL to the server. Otherwise you'll get a nice HTML error message. There aren't an HTML headers to parse, as the HTTP version is not specified so HTTP/0.9 is used, which does not have headers.

User Authentication

The "key" provided when a user joins the server can be compared to the MD5 checksum of the server's "salt" plus the username to verify that the user is logged in to minecraft.net with that username. This is useful for establishing enough trust of the name provided to ban or op the player by name.

if (player.key == md5(server.salt + player.name)) {
 // player is logged in via minecraft.net
} else {
 // player is forging the username
}

Note: This means that you should make sure your "salt" is kept a secret and shared only with heartbeat.jsp. If your server's "salt" is visible anywhere to users, it is trivial for users to produce valid-looking "key"s without being logged in to minecraft.net.

Skins

Skins for a player are downloaded by the client from http://minecraft.net/skin/skinname.png, where skinname is the name of the player. This means that the name for a player can be faked to give a desired skin.

Packet Protocol

The connection is done over TCP. Every packet starts with a byte representing the Packet ID.

Protocol Data Types

For details on fields such as player IDs and position, see below.

All numbers are in network order (big-endian). Signed integers are in two's compliment.

The last 5 bits of the fixed-point types are fractional, i.e. they come after the "point". You can think of these as 32ths of a block (25=32). To convert to a block position (integer), it needs to be rounded down, this is equivalent to an arithmetic shift right by 5.

Type Bytes Description
Byte 1 Unsigned byte (0 to 255)
SByte 1 Signed byte (-128 to 127)
FByte 1 Signed fixed-point, 5 fractional bits (-4 to 3.96875)
Short 2 Signed integer (-32768 to 32767)
FShort 2 Signed fixed-point, 5 fractional bits (-1024 to 1023.96875)
String 64 US-ASCII encoded string padded with spaces (0x20)
Byte array 1024 Binary data padded with null bytes (0x00)

Client → Server packets

Packet ID Purpose Field Description Field Type Notes
0x00 Player Identification Packet ID Byte Sent by a player joining a server with relevant information. The protocol version is 0x07, unless you're using a client below 0.28.
Protocol version Byte
Username String
Verification key String
Unused Byte (0x00)
0x05 Set Block Packet ID Byte Sent when a user changes a block. The mode field indicates whether a block was created (0x01) or destroyed (0x00).

Block type is always the type player is holding, even when destroying.

Client assumes that this command packet always succeeds, and so draws the new block immediately. To disallow block creation, server must send back Set Block packet with the old block type.

X Short
Y Short
Z Short
Mode Byte
Block type Byte
0x08 Position and Orientation Packet ID Byte Sent frequently (even while not moving) by the player with the player's current location and orientation. Player ID is always -1 (255), referring to itself.
Player ID SByte (0xFF)
X FShort
Y FShort
Z FShort
Yaw (Heading) Byte
Pitch Byte
0x0d Message Packet ID Byte Contain chat messages sent by player. Player ID is always -1 (255), referring to itself. (See how chat works - note that Classic only supports color codes.)
Player ID SByte (0xFF)
Message String

Server → Client packets

Packet ID Purpose Field Description Field Type Notes
0x00 Server Identification Packet ID Byte Response to a joining player. The user type indicates whether a player is an op (0x64) or not (0x00) which decides if the player can delete bedrock. The protocol version is 0x07, unless you're using a client below 0.28.
Protocol version Byte
Server name String
Server MOTD String
User type Byte
0x01 Ping Packet ID Byte Sent to clients periodically. The only way a client can disconnect at the moment is to force it closed, which does not let the server know. The ping packet is used to determine if the connection is still open.
0x02 Level Initialize Packet ID Byte Notifies the player of incoming level data.
0x03 Level Data Chunk Packet ID Byte Contains a chunk of the gzipped level data, to be concatenated with the rest. Chunk Data is up to 1024 bytes, padded with 0x00s if less.
Chunk Length Short
Chunk Data Byte Array
Percent Complete Byte
0x04 Level Finalize Packet ID Byte Sent after level data is complete and gives map dimensions. The y coordinate is how tall the map is.
X Size Short
Y Size Short
Z Size Short
0x06 Set Block Packet ID Byte Sent to indicate a block change by physics or by players. In the case of a player change, the server will also echo the block change back to the player who initiated it.
X Short
Y Short
Z Short
Block Type Byte
0x07 Spawn Player Packet ID Byte Sent to indicate where a new player is spawning in the world. This will set the player's spawn point.
Player ID SByte
Player Name String
X FShort
Y FShort
Z FShort
Yaw (Heading) Byte
Pitch Byte
0x08 Set Position and Orientation (Player Teleport) Packet ID Byte Sent with changes in player position and rotation. Used for sending initial position on the map, and teleportation.

Some servers don't send relative packets, opting to only use this one.

Player ID SByte
X FShort
Y FShort
Z FShort
Yaw (Heading) Byte
Pitch Byte
0x09 Position and Orientation Update Packet ID Byte Sent with changes in player position and rotation. Sent when both position and orientation is changed at the same time.

Not required for server operation.

Player ID SByte
Change in X FByte
Change in Y FByte
Change in Z FByte
Yaw (Heading) Byte
Pitch Byte
0x0a Position Update Packet ID Byte Sent with changes in player position.

Not required for server operation.

Player ID SByte
Change in X FByte
Change in Y FByte
Change in Z FByte
0x0b Orientation Update Packet ID Byte Sent with changes in player rotation.

Not required for server operation.

Player ID SByte
Yaw (Heading) Byte
Pitch Byte
0x0c Despawn Player Packet ID Byte Sent to others when the player disconnects.
Player ID SByte
0x0d Message Packet ID Byte Messages sent by chat or from the console. (See how chat works - note that Classic only supports color codes.)
Player ID SByte
Message String
0x0e Disconnect Player Packet ID Byte Sent to a player when they're disconnected from the server.
  1. "Cheat detected: Distance" - happens not only when setting tile too far away from the player (how far is maximum distance and how it is measured?), but also when player moves and then immediately builds.
  2. "Cheat detected: Tile type"
  3. "Cheat detected: Too much clicking!"
  4. "Cheat detected: Too much lag"
Disconnect reason String
0x0f Update User Type Packet ID Byte Sent when a player is opped/deopped. User type is 0x64 for op, 0x00 for normal user. This decides if the player can delete bedrock.
User type Byte

Player IDs

Player IDs are treated as a signed byte.

The client is never told it's own player ID, when referencing itself the ID of -1 (255) is always used.

Some clients (notably the original), accept any negative number (128-255) as meaning the client itself, others only accept -1. This means that some clients can handle players with IDs less than -1, and others will combine them with itself.

Player Position

Standing On Things

A player's position corresponds to the center of the client viewport.

The bottom of the player's feet is located 1.59375 (fixed-point: 51) units below the center of the viewport, so to position the player on top of a particular block you could send a teleport (0x08) packet specifying a Y value based on the block position as: (Y x 32 + 51)

Orientation

A yaw value of 0 means the player is facing in the Z=0 (negative Z) direction. This value increases in a clockwise direction as seen from above. If we call the negative Z direction "North", then a yaw of 64 means "East", 128 means "South", and 192 means "West".

A pitch value of 0 means level and this value increases in a downward direction. 64 is down, and 192 is up. Values of 65 to 191 should never occur because the player cannot look further up or down than the 64 → 0, 255 → 192 range. However, the Minecraft Classic client does not ignore invalid values, so it is possible to make players' heads "upside-down".

Level Data

Level data is an array of block types, as bytes in XZY order. XZY order means you first increment the X, then the Z, then the Y.

Before being sent to the client, it is prefixed with its length as a big-endian int (4 bytes), and then gzipped (not zlib or plain deflate). This is then split into 1024 byte chunks, to be sent to the client in Level Data Chunk packets. The final chunk is padded with 0x00 bytes.

When the client receives a data chunk, it should concatenate it to the end of the previous chunks, only stripping 0x00s from the end of the final one. The entire data should then be gzip inflated.

Color Codes

Messages sent from the server to the client can contain color codes, which allow coloring of text for various purposes.

An ampersand followed by a hex digit in the message tells the client to switch colors while displaying text.

Colour coding at the start of the message will only work if the player ID byte is less than 127. If it's 127 or higher, the game automatically adds &e before the message, making it yellow. However, colour codes after the first character still work. If you use an ID below 127, it doesn't add a colour code, so the ones you use will work.

It is important to note that an ampersand at the end of a message that is not followed by a hex digit will crash all clients that receive it, so it is a must to sanitize all chat messages received from clients.

Hex digit to color mapping
Sample Code Common Name Foreground Color Background Color
R G B R G B
&0 Black 0 0 0 0 0 0
&1 Dark Blue 0 0 191 0 0 47
&2 Dark Green 0 191 0 0 47 0
&3 Dark Teal 0 191 191 0 47 47
&4 Dark Red 191 0 0 47 0 0
&5 Purple 191 0 191 47 0 47
&6 Gold 191 191 0 47 47 0
&7 Gray 191 191 191 47 47 47
&8 Dark Gray 64 64 64 16 16 16
&9 Blue 64 64 255 16 16 63
&a Bright Green 64 255 64 16 63 16
&b Teal 64 255 255 16 63 63
&c Red 255 64 64 63 16 16
&d Pink 255 64 255 63 16 63
&e Yellow 255 255 64 63 63 16
&f White 255 255 255 63 63 63