Andrew's public notes

Classic protocol

Based on the ancient texts from wiki.vg, with some modern changes

Classicube.net communication

Heartbeats

Servers can advertise themselves to the ClassiCube server list by sending a GET or POST request to https://www.classicube.net/server/heartbeat or https://www.classicube.net/heartbeat.jsp with certain specific request parameters. It doesn’t make a huge difference if you use POST over GET, but POST is generally regarded as “more secure” when transmitting sensitive information.

The parameters the heartbeat endpoint expects are...

Field Description
port int 1-65535 Which port the server is using. For public servers, this must be accessible or the server won’t be listed publicly.
max int 1-? Maximum amount of players allowed on the server.
name string The name of the server. Should be relatively short, preferably under 256 characters, and should only contain alphanumeric and some basic ASCII symbols.
public bool true/false Whether or not the server should be publicly listed. The server will be tested by an automated port tester to ensure that it’s public - if the connection fails, the server will not be listed and an error will be returned.
version int 7 Latest protocol version supported by the server. For all existing clients, this is either 6 or 7, and ClassiCube.net officially only supports protocol 7 at this time. Note: CPE extensions don’t affect the server’s version number.
salt string A random 16-character base-62 string that will be used in authentication. Users that obtain this string can log into your server using any name, so keep this secret. It’s recommended to rotate salts every 24-48 hours. More details on how the salt plays into authentication below...
users int 0-? The number of users currently playing on the server.
software string A name to identify the server software being used.

The heartbeat endpoint returns a URL for the server if everything is valid.

User authentication/validation

The mppass that is provided during the network handshake by the user is used to validate that the user is who they claim to be.

If the user received the mppass from ClassiCube.net (e.g. they are logged in and want to join your server), the mppass will match an md5sum of salt + username. In other words:

if (md5(salt + player_name) == mppass) {
  // valid login
} else {
  // invalid or expired mppass
}


Note: since the salt is used for user authentication, you should make sure to keep it a secret.

Since md5 is generally not very secure, the official recommendation is to generate long salts and change your server salt every 24-48 hours to ensure that even the fastest md5 hash bruteforcers can’t reverse it in time to use it.

Skins

Skins are png files that can be found at https://www.classicube.net/skins/{case-sensitive-username}.png

They’re uploaded by visiting the account page on ClassiCube.net while logged in as the user you would like to change the skin for.

The aforementioned path will either directly serve or redirect you to the canonical path for a skin, or redirect you to the default skin. To skip a redirect step in the process, you can directly request a skin from our CDN at https://cdn.classicube.net/skin/{case-sensitive-username}.png - note that a missing skin will return a 403 response code at this time.

Note: A missing skin will return a 403 response code
Note: The redirect from ClassiCube.net to the CDN will always redirect to http at this time, even when originally requested from https.


Goodly’s skin
AndrewPH’s skin
UnknownShadow200’s skin

Faces

Similar to skins, ClassiCube.net provides a rendered head for use in avatars, etc.

They can be found at https://www.classicube.net/face/{case-sensitive-username}.png - which will redirect you to an image file every time - or directly at the CDN via https://cdn.classicube.net/face/{case-sensitive-username}.png.

Note: The ClassiCube.net path will always take you to an image, but entails a redirect. Calling the CDN directly will skip that redirect but return a 403 response code for faces that don’t exist/haven’t been created yet.

Goodly’s face
AndrewPH’s face
UnknownShadow200’s face

Packet protocol

All communication is done over TCP on one port. Every packet begins with a single byte representing the Packet ID

Protocol data types

Everything in the base Classic Protocol uses these definitions when encoding and decoding packet structures.

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 decimal point. You can think of these as 32nds of a block (2^5 = 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 Byte length Description
Byte 1 Unsigned byte representing 0 to 255
SByte 1 Signed byte representing -128 to 127
FByte 1 Signed byte representing fixed-point number with 5 fractional bits from -4 to 3.96875
Short 2 Signed integer representing -32768 to 32767
FShort 2 Signed fixed-point integer representing number with 5 fractional bits from -1024 to 1023.96875
String 64 US ASCII encoded string padded with space characters (0x20) to 64 bytes in length.
Byte array 1024 Binary data padded with null bytes (0x00)

Note: Some packets will use alternative byte lengths when certain CPE extensions are enabled.

Client -> Server packets

Player identification

ID: 0x00
Sent by a player joining a server with relevant information. The protocol version is 0x07, unless you're using a client below 0.28.


Field name Field type
Packet ID Byte
Protocol version Byte (0x07 for clients compatible with 0.28 and higher)
Username String
MPPass String
Unused (Used to indicate CPE support) Byte (0x00 for the core protocol)

Set block

ID: 0x05
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 a Set block packet with the old block type.

Field name Field type
Packet ID Byte
X Short
Y Short
Z Short
Mode Byte (0x00 or 0x01)
Block type Byte

Position and orientation

ID: 0x08
Sent frequently (even while not moving) by the player with the player's current location and orientation. Player ID provided in this packet is always -1 (or 255 depending on how you interpret it), referring to itself.


Field name Field type
Packet ID Byte
Player ID SByte (0xFF AKA -1 AKA 255)
X FShort
Y FShort
Z FShort
Yaw (Heading) Byte
Pitch Byte

Message

ID: 0x0d
Contains chat messages sent by player. Player ID provided in this packet is always -1 (255 depending on how you interpret it), referring to itself.


Note: May contain public/Classic_Colors.
Note: The meaning of the Player ID field may change based on CPE extension support.


Field name Field type
Packet ID Byte
Player ID SByte (0xFF)
Message String

Server -> Client packets

Server Identification

ID: 0x00
Response to a joining player. The user type indicates whether a player is an op (0x64) or not (0x00), which indicates if the player can delete bedrock.


The protocol version is 0x07, unless you’re targeting a client that implements an earlier protocol, e.g. a version of Minecraft Classic prior to 0.28

Field nameField type
Packet IDByte
Protocol versionByte
Server nameString
Server MOTDString
User typeByte

Ping

ID: 0x01
Sent to clients periodically. The only way a client can disconnect in the base protocol is to force the connection closed, which does not usually let the server know immediately. The ping packet is used to determine if the connection is still open.


Field nameField type
Packet IDByte

Level Initialize

ID: 0x02
Notifies the player that level data is about to come down the pipe.


Field nameField type
Packet IDByte

Level data chunk

ID: 0x03
Contains a chunk of the gzipped level data, to be concatenated with the rest.


Chunk data is 1024 bytes, padded at the end with 0x00s if less than 1024 bytes is left.

Field nameField type
Packet IDByte
Chunk lengthShort
Chunk dataLevel Data
Percent completeByte

Level finalize

ID: 0x04
Sent after the level data has been fully sent to the client. Provides map dimensions, where Y is up.


Field nameField type
Packet IDByte
X sizeShort
Y sizeShort
Z sizeShort

Set block

ID: 0x06
Sent to indicate a block change by either physics or another player. In the case of a player-initiated change, the server should also send this packet to the player that caused the event.


Field nameField type
Packet IDByte
XShort
YShort
ZShort
Block typeByte

Spawn player

ID: 0x07
Sent to indicate where a new player is spawning in the world. This will set the player’s spawn point.


Field nameField type
Packet IDByte
Player IDSByte
Player nameString
XFShort
YFShort
ZFShort
YawByte
PitchByte

Set position and orientation/Player teleport

ID: 0x08
Sent to change the position and rotation of players. Also used to send the initial position on the map, as well as teleportation.


Field nameField type
Packet IDByte
Player IDSByte
XFShort
YFShort
ZFShort
YawByte
PitchByte

Relative position + orientation update

ID: 0x09
Optional. Relative update of player position since last position update, as well as an orientation update. Not required for the server to operate.


Field nameField type
Packet IDByte
Player IDSByte
Change in XFByte
Change in YFByte
Change in ZFByte
YawByte
PitchByte

Relative position update

ID: 0x0A
Optional. Relative-position-only version of the position/orientation packet. Only changes the players position, relative to their prior position. Not required for the server to operate.


Field nameField type
Packet IDByte
Player IDSByte
Change in XFByte
Change in YFByte
Change in ZFByte

Orientation update

ID: 0x0B
Optional. Orientation-only version of the position/orientation packet. Only changes the player’s orientation. Not required for the server to operate.


Field nameField type
Packet IDByte
Player IDSByte
YawByte
PitchByte

Despawn player

ID: 0x0C
Sent to other players when a player disconnects to indicate that the player entity should be deleted.


Field nameField type
Packet IDByte
Player IDSByte

Message

ID: 0x0D
Messages from other players or the console. May contain color codes.


Field nameField type
Packet IDByte
Player ID (Unused in core protocol)SByte
MessageString

Disconnect player

ID: 0x0E
Sent to a player to indicate that they should display a screen telling the player why they’ve been disconnected.


Note: The server must assume the client won’t respect this packet, and must terminate the connection after sending it.

Field nameField type
Packet IDByte
Disconnect reasonString

Update user type

ID: 0x0F
Sent when a player’s admin status has changed (whether or not they can delete bedrock). User type is 0x64 for op (can delete bedrock), or 0x00 for normal user (cannot delete bedrock).


Field nameField type
Packet IDByte
User typeByte