Zh:Minecraft Forge Handshake

From wiki.vg
Revision as of 14:01, 17 October 2021 by Minecraftkuhei (talk | contribs) (Created page with "该页是关于 '''[https://minecraftforge.net/ Minecraft Forge] 协议'''的文档,包含如何连接到Minecraft Forge的服务器和Minecraft Forge相较于原版修改...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

该页是关于 Minecraft Forge 协议的文档,包含如何连接到Minecraft Forge的服务器和Minecraft Forge相较于原版修改了哪些协议。

FML protocol (1.7 - 1.12)

本节主要基于Pokechu22's work on getting Minecraft Console Client to connect to Forge servers,描述了用于 Minecraft 1.7.X 到 1.12.X 的 FML 协议。

Server List Ping的更改

When forge is installed, the Server List Ping changes with additional mod information:

{
    "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.

Warning.png 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 (where \0 is a Wikipedia:null character) (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.

Huh.png The following information needs to be added to this page:
Why does it send the CompleteHandshake packet to itself? How does it keep synchronized (especially near the end with the ACKs)?
  • S→C: REGISTER forge's plugin channels: FML|HS, FML, FML|MP, FML, FORGE (yes, FML is there twice; technically, it does not need to be there twice but that is the way that Forge sends it and sending it that way will act more similar to forge)
  • 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

Huh.png The following information needs to be added to this page:
Explain exactly what registries are, and figure out what Substitutions and Dummies are

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
Number of dummies Varint Number of dummies in the array below. May not be present in older versions of forge; check if there still is data remaining in the packet before continuing to read data.
Dummies Array of strings Each dummy?

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

Causes the client to recomplete the entire handshake from the start. There is no payload beyond the discriminator byte.

The normal forge server does not ever use this packet, but it is used when connecting through a BungeeCord instance, specifically when transitioning from a vanilla server to a modded one or from a modded server to another modded server.

Channel Bound To Field Name Field Type Notes
FML|HS Client Discriminator Byte Always -2 (254) for HandshakeReset

FML|MP and multipart packets

Forge supports splitting large clientbound plugin message packets into smaller multipart packets. This functionality does not exist serverbound. This system is available in all versions.

This system starts by sending an FML|MP packet to indicate what the actual packet is (note that this is within the plugin message itself):

Channel Bound To Field Name Field Type Notes
FML|MP Client Channel String (20) The wrapped channel
Parts Unsigned byte Total number of parts (equal to ceil(dataLength / (double)(1048495))
Length Int Total length of wrapped data

This is followed by a series of additional FML|MP packets which write the payload. Each packet is prefixed with the part number as an unsigned byte (starting at 0), followed by the rest of the packet containing up to 1048495 bytes of the actual message. Each packet must be sent in order.

Up to 52424750 bytes (~52 megabytes) may be sent through this system.

Differences from Forge 1.7.10

Forge for Minecraft 1.8 made some changes from the 1.7.10 version.

The most important thing to keep track of isn't (entirely) a forge change. In 1.7.10, plugin channel packets are length prefixed, while in 1.8 they are not. However, forge makes some more changes to the server to client packet (but not the client to server packet): Rather than using a short for the length, a varshort is used. Due to the way that varshorts work, this is backwards compatible, but if this is not accounted for you may receive forge packets that seem corrupted as there is an extra byte that appears seemingly randomly.

Warning.png While it may seem like you can get away with not handling varshorts, on servers with lots of mods (EG FTB), this will appear.

Additionally, in 1.7.10 the registries packet is instead "ModIdData":

ModIdData

Contains numeric ID mapping for blocks and items.

Huh.png The following information needs to be added to this page:
Again, what are blockSubstitutions and itemSubstitutions?
Channel Bound to Name Type Notes
FML|HS Client Discriminator Byte Always 3 for ModIdData
Mapping length VarInt Length of the following mapping
Mapping Name Array String Name of the block/item. Prefixed with a discriminator byte, 01 = block, 02 = item.
ID VarInt Numeric ID of the item.
Block substitutions length VarInt Length of the following array
Block substitutions Array of strings Block substitutions
Item substitutions length VarInt Length of the following array
Item substitutions Array of strings Item substitutions

FML2 protocol (1.13 - Current)

This section is also mostly based off research on making Minecraft Console Client join 1.13+ Forge servers. As a result, it only describes the necessary steps for joining a Forge server, but not all its network protocol.

Changes to Server List Ping

When forge is installed, the Server List Ping changes with additional mod information. Example for 1.13.2:

{
  "description": {
    "text": "A Minecraft Server"
  },
  "players": {
    "max": 20,
    "online": 0
  },
  "version": {
    "name": "1.13.2",
    "protocol": 404
  },
  "forgeData": {
    "channels": [
      {
        "res": "ironchest:main_channel",
        "version": "1",
        "required": false
      }
    ],
    "mods": [
      {
        "modId": "forge",
        "modmarker": "ANY"
      },
      {
        "modId": "ironchest",
        "modmarker": "1.13.2-8.0.2"
      }
    ],
    "fmlNetworkVersion": 2
  }
}

Warning.png The key modId has a capital 'I', unlike modid pre-1.13 for the previous FML protocol.

Changes to Handshake packet

Forge adds a marker to the Server Address field of the Handshake packet: \0FML2\0 is added to the end of the server's address, where \0 is a null character. Unless the Forge server has no mods installed, attempting to connect to a Forge server without making any changes results in getting immediately disconnected with the message This server has mods that require Forge to be installed on the client. Contact your server admin for more details.. Inferring the correct marker to use is possible by examining the Server List Ping response from the server. FML2 will set the forgeData > fmlNetworkVersion to 2.

References:

Handshake Protocol

After receiving the Login Start packet, the Forge server communicates with the Forge client using Login Plugin Request and Login Plugin Response packets before allowing the vanilla login phase to proceed as usual. Each packet must be understood and replied accordingly by the client, or the login attempt is rejected with a Disconnect (Login) packet.

Login Wrapper

As per FMLLoginWrapper.java, the Login Plugin Request and Login Plugin Response are formatted as follows:

  • Channel is fml:loginwrapper
  • Data has the following layout:
Field Name Field Type Notes
Channel Identifier Name of the plugin channel. fml:handshake for FML handshake.
Inner Packet Packet Same layout as vanilla packets. Forge uses Minecraft's PacketBuffer class to decode the packet.

Handshake Channel

Packets exchanged on the fml:handshake channel are described below. As per Login Plugin Request and Login Plugin Response requirements, each request sent by the server expects exactly one packet back from the client, wrapped as described in Login Wrapper. The client can only respond to requests from the server. The FML handshake completes successfully once the client has correctly responded to all requests from the server.

References:

Mod List

Advertises the list of Mods, Plugin channel and Registries on the Forge server.

Packet ID Bound To Field Name Field Type Notes
1 Client Mod Count VarInt Length of the Mods array
Mod Names Array of String List of Mods installed on the Server
Channel Count VarInt Length of the Channels array
Channels Name Array Identifier Name of the Plugin channel
Marker String Version of the Plugin channel
Registry Count VarInt Length of the Registries array
Registries Array of Identifier List of Registries on the Server

The client is supposed to check the list of mods against its own list, and abort login if a mismatch is detected. Otherwise, it should reply with Mod List Reply to continue the handshake process.

Mod List Reply

Advertises the list of Mods, Plugin channels and Registries on the Forge client, in reply to Mod List.

Packet ID Bound To Field Name Field Type Notes
2 Server Mod Count VarInt Length of the Mods array
Mod Names Array of String List of Mods installed on the Server
Channel Count VarInt Length of the Channels array
Channels Name Array Identifier Name of the Plugin channel
Marker String Version of the Plugin channel
Registry Count VarInt Length of the Registries array
Registries Name Array Identifier Name of the registry
Marker String Version of the registry

Compared to Mod List, this packet also includes a Marker for each Registry. As of MC 1.16, the Forge server only checks the contents of the mod list, so a client just wanting to pass the server-side check can reply with the data provided by the server and leave an empty string in the Registry Marker field.

Server Registry

Advertises a registry to the client. The Forge server will send one request/packet per registry.

Huh.png The following information needs to be added to this page:
The Forge Snapshot data format is not documented yet.
Packet ID Bound To Field Name Field Type Notes
3 Client Registry Name Identifier Name of the registry
Snapshot Present Boolean Indicates if a Snapshot is present
Snapshot Forge Snapshot Snapshot of the registry

A client is expected to process the registry and reply with an Acknowledgement packet.

Configuration Data

Advertises configuration data to the client.

Packet ID Bound To Field Name Field Type Notes
4 Client File Name String Name of the configuration file
Data Array of Bytes File contents (may be a String)

A client is expected to process the configuration data and reply with an Acknowledgement packet.

Acknowledgement

Acknowledges a Server Registry or Configuration Data packet.

Packet ID Bound To Field Name Field Type Notes
99 Server

This is a dummy packet sent back when no reply payload is required, as each request sent by the server expects a packet back from the client.