Minecraft Forge Handshake
Work in progress!
|
This page will document the changes made in the Minecraft Forge protocol.
Largely based on my own attempts to document the protocol and allow connection to forge servers here.
Contents
Changes to Server List Ping
When forge is installed, the Server List Ping changes with an additional modinfo
. Example:
{
"description": "A Minecraft Server",
"players": {
"max": 20,
"online": 0
},
"version": {
"name": "1.8",
"protocol": 47
},
"modinfo": {
"type": "FML",
"modList": [
{
"modid": "mcp",
"version": "9.05"
},
{
"modid": "FML",
"version": "8.0.99.99"
},
{
"modid": "Forge",
"version": "11.14.3.1512"
},
{
"modid": "rpcraft",
"version": "Beta 1.3 - 1.8.0"
}
]
}
}
So, to test whether forge is installed, look for the modinfo
key and then a type
of FML
The modList
contains each installed mod's version and ID.
The key modList
has a capital 'L', unlike any other key in the ping result!
This is injected in ServerStatusResponse by calling FMLNetworkHandler.enhanceStatusQuery().
Connection to a forge server
Attempting to connect to a forge server without making any changes results in getting immediately disconnected with the message "This server requires FML/Forge to be installed. Contact your server admin for more details.
". This message is displayed in FMLCommonHandler and is injected in a modified 0x00 Handshake packet.
If \0FML\0
is added to the end of the server's address (again, in the 0x00 handshake packet), the server will not immediately reject you. However, you still will not complete the connection.
This occurs because Minecraft Forge has an additional set of handshakes (for determining mods and block IDs), that must be completed before the server allows logging in.
Forge handshake
Forge's handshake occurs in the middle of the normal login sequence, right after 0x02 Login Success is received by the client.
In addition to the normal packet debugging for the server, if -Dfml.debugNetworkHandshake=true
is passed to the forge server, some more information about the current handshake status will be outputted.
- S→C:
REGISTER
forge's plugin channels: FML|HS, FML, FML|MP, FML, FORGE (yes, FML is there twice). - S→C: A ServerHello packet is sent on
FML|HS
including the player's dimension (0 if it's the first login) - C→S:
REGISTER
the plugin channels: FML|HS, FML, FML|MP, FML, FORGE. - C→S: A ClientHello packet is sent on the
FML|HS
channel. - C→S: A ModList packet is sent.
- Server checks that the mod list is compatible. If incompatible, the player is disconnected with an explanatory message. Otherwise, continue.
- S→C: A ModList packet is sent.
- Client checks that the mod list is compatible. If incompatible, it disconnects. Otherwise, continue.
- C→S: A HandshakeAck packet is sent, with the phase being
WAITINGSERVERDATA
(2). - S→C: A series of RegistryData packets is sent, with hasMore being true for all packets except the last.
- Client reads and stores each RegistryData, continuing reading until hasMore is false. Once hasMore is false, it checks whether it has all of the needed blocks/items. If it does not, it disconnects. Otherwise, continue.
- C→S: A HandshakeAck packet is sent with phase being
WAITINGSERVERCOMPLETE
(3). - S→C: A HandshakeAck packet is sent with phase being
WAITINGCACK
(2). - C→S: A HandshakeAck packet is sent with phase being
PENDINGCOMPLETE
(4). - S→C: A HandshakeAck packet is sent with phase being
COMPLETE
(3). - The server sends a "CompleteHandshake" packet to itself. (Not sure why)
- C→S: A HandshakeAck packet is sent with phase being
COMPLETE
(5). - The client sends a "CompleteHandshake" packet to itself. (Not sure why)
Definitions
Minecraft Forge uses an additional type not covered in data types for some things -- a varshort. This is essentially the same as a regular short, except that if the top byte (what is normally sign) is set, it is followed by an additional byte. This allows forge to retain backwards compatibility but extend the length of certain numbers -- the varshort is only used in places where, in vanilla Minecraft, the sign bit would not have been set. It is implemented in ByteBufUtils.
Discriminator bytes are the way that Minecraft Forge allows sending multiple messages on one plugin channel. They aren't part of the original specification, but a similar concept is used with the MC|AdvCdm
plugin channel (used for command blocks). That packet decides whether a block location is being sent or an entity ID (minecart command blocks) is being sent based off of the value of the first byte in the packet.
In the same way, forge uses the first byte of the plugin message to specify which packet to use. It uses FMLIndexedMessageToMessageCodec to automatically switch the value.
Discriminator bytes change depending on the channel: 0 for FML|HS
means something different from 0 for FML
.
FML|HS
Packet structure
FML|HS
is used to perform the handshake. Discriminator bytes are found in FMLHandshakeCodec.
ServerHello
Starts the handshake.
Channel | Bound To | Field Name | Field Type | Notes |
---|---|---|---|---|
FML|HS
|
Client | Discriminator | Byte | Always 0 for ServerHello |
FML protocol Version | Byte | Determined from NetworkRegistery. Currently 2 .
| ||
Override dimension | Optional Int | Only sent if protocol version is greater than 1. |
ClientHello
Response from the client to the ServerHello packet.
Channel | Bound To | Field Name | Field Type | Notes |
---|---|---|---|---|
FML|HS
|
Server | Discriminator | Byte | Always 1 for ClientHello. |
FML protocol Version | Byte | Determined from NetworkRegistery. Currently 2 .
|
ModList
Contains a list of all mods installed on the server or client. Sent from the client to the server first, and then the server responds with its mod list. The server's mod list matches the one sent in the ping.
Channel | Bound To | Field Name | Field Type | Notes | ||
---|---|---|---|---|---|---|
FML|HS
|
Both | Discriminator | Byte | Always 2 for ModList | ||
Number of mods | Varint | Number of mods below | ||||
Mods | Mod name | Array | String | Name of the mod | ||
Mod version | String | Version of the mod |
RegistryData
The following information needs to be added to this page: | |
Explain exactly what registries are, and figure out what Substitutions is |
The server sends several of this packet, one for each registry. It'll keep sending them until the hasMore value is no longer true.
Channel | Bound To | Field Name | Field Type | Notes | ||
---|---|---|---|---|---|---|
FML|HS
|
Both | Discriminator | Byte | Always 3 for RegistryData. | ||
Has more | Boolean | Marks whether another RegistryData packet will be sent after this. | ||||
Name | String | Name of the registry for this packet | ||||
Number of ids | Varint | Number of ids sent below | ||||
Ids | Name | Array | String | Name of the thing | ||
Id | Varint | Numerical id of the thing | ||||
Number of substitutions | Varint | Number of substitutions sent below | ||||
Substitutions | Array of strings | Each substitution |
HandshakeAck
Confirms that the client is able to use the settings sent previously.
Channel | Bound To | Field Name | Field Type | Notes |
---|---|---|---|---|
FML|HS
|
Both | Discriminator | Byte | Always -1 (255) for HandshakeAck |
Phase | Byte | The current phase, which is the ordinal (0-indexed) in the FMLHandshakeClientState or FMLHandshakeServerState enums (if the server is sending it, it is in the ServerState enum, and if the client is sending it, it is the ClientState enum). |
HandshakeReset
The following information needs to be added to this page: | |
Is this ever actually sent? |
Causes the client to recomplete the entire handshake from the start. Does not appear to be sent. There is no payload beyond the discriminator byte.
Channel | Bound To | Field Name | Field Type | Notes |
---|---|---|---|---|
FML|HS
|
Client | Discriminator | Byte | Always -2 (254) for HandshakeReset |