Difference between revisions of "Classic Protocol Legacy"
m (Change description of packet 0x0C in the client->server table) |
|||
Line 1: | Line 1: | ||
− | Documentation on the old server protocol used by the [http://minecraft.net/servers.jsp Minecraft Classic Creative] server before PVN 6 | + | Documentation on the old server protocol used by the [http://minecraft.net/servers.jsp Minecraft Classic Creative] server before Minecraft Classic 0.0.20a (PVN 6). |
+ | This documentation covers Minecraft Classic 0.0.19a_06, but it applies to older protocol versions as well. | ||
==Minecraft.net Communication== | ==Minecraft.net Communication== |
Revision as of 12:32, 19 November 2023
Documentation on the old server protocol used by the Minecraft Classic Creative server before Minecraft Classic 0.0.20a (PVN 6). This documentation covers Minecraft Classic 0.0.19a_06, but it applies to older protocol versions as well.
Contents
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). The client/server use UTF-8 instead of US-ASCII for strings, but the client can only display US-ASCII characters |
Byte array | 1024 | Binary data padded with null bytes (0x00) |
Client → Server packets
Packet ID | Purpose | Field Description | Field Type | Notes |
---|---|---|---|---|
0x00 | Login | Packet ID | Byte | Sent by a player joining a server with relevant information.
The protocol version is 0x05. |
PVN | Byte | |||
Username | String | |||
MPPass | String | |||
0x04 | Place/Break Tile | Packet ID | Byte | Sent when a user changes a tile.
The mode field indicates whether a tile was placed (0x01) or destroyed (0x00). Tile type is always the type player is holding, even when destroying. |
X | Short | |||
Y | Short | |||
Z | Short | |||
Mode | Byte | |||
Tile type | Byte | |||
0x07 | Player Position | Packet ID | Byte | Sent every tick (20 times per second) 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 | |||
0x0C | Chat Message | Packet ID | Byte | A chat message sent by the 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 Details | Packet ID | Byte | Successful response to a joining player. The protocol version is 0x05. |
PVN | Byte | |||
Server name | String | |||
Server MOTD | String | |||
0x01 | Level Initialize | Packet ID | Byte | Notifies the player of incoming level data. |
0x02 | 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 | |||
0x03 | 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 | |||
0x05 | Update Tile | Packet ID | Byte | Sent to indicate a tile change by physics or by players.
In the case of a player change, the server will also echo the tile change back to the player who initiated it. |
X | Short | |||
Y | Short | |||
Z | Short | |||
Tile Type | Byte | |||
0x06 | Player Join | Packet ID | Byte | Sent to indicate where another player is joining the server.
If the player ID is -1, 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 | |||
0x07 | Player Teleport | Packet ID | Byte | Sent to indicate the change of another player's position.
If the player ID is -1, it will update the player's position. It is also used for teleportation and setting the initial position on the map after logging in. 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 | |||
0x08 | Player Move and Rotate | 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 | |||
0x09 | Player Move | 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 | |||
0x0A | Player Rotate | Packet ID | Byte | Sent with changes in player rotation.
Not required for server operation. |
Player ID | SByte | |||
Yaw (Heading) | Byte | |||
Pitch | Byte | |||
0x0B | Player Leave | Packet ID | Byte | Sent when a player disconnects. |
Player ID | SByte | |||
0x0C | Chat Message | Packet ID | Byte | Messages sent by players or from the console. (See how chat works - note that Classic only supports color codes.) |
Player ID | SByte | |||
Message | String | |||
0x0D | Kick | Packet ID | Byte | Sent to a player when they're disconnected from the server.
|
Disconnect reason | String |
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.
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 |