FabricMC / fabric

Essential hooks for modding with Fabric.
Apache License 2.0
2.39k stars 420 forks source link

Network handshake design #463

Open sfPlayer1 opened 4 years ago

sfPlayer1 commented 4 years ago

The network handshake ensures that all mods have compatible counterparts between client and server. It also determines when mods can do their own handshakes, send initial data and when the game may continue the login process.

Compatibility levels

The API supports the following approaches for various compatibility schemes:

  1. don't check or communicate
  2. require absence or... 2.1 some version range on the other side(from both sides, may be * for any) 2.2 same version on the other side
  3. require presence... 3.1 with some version range on the other side (from both sides, may be * for any) 3.2 with the same version on both sides

Option 1 is for mods that don't communicate with their own copy on other side and have nothing that has to be registered/present on both sides. It is also suitable for anything with a custom handshake or its own presence detection+validation, e.g using the register plugin channel.

Option 2 is for mods that can run stand-alone like in 1, but have an optional communication component depending on presence and compatibility. This is frequently seen in client mods that improve or enable extra features if their server part is available and vice versa. In order to let the mods using this option enable those features, the Fabric handshake carries the mod presence and version information back across the network. Specifying * in the version range disables any checking, making it announce only.

Option 3 is what mods content mods should use. It guarantees that the desired version is present after the handshake, otherwise the connection will have been dropped.

2.2 and 3.2 can be represented by a version range as in 2.1/3.1, it just eliminates the need to specify the own mod's version in multiple places.

Most mods will likely use 3.2, the default may have to be 1 for a while to retain compatibility.

Interaction with differently specified requirements

Mismatched requirement specifications happen when using different versions of a mod and the mod changed its requirements. The allowed version range acts as the intersection of the two ranges, the presence requirement as the strictest. Announcements from 2.x happen as usual.

Mod-side declaration

Mods specify their c<->s compatibility requirements declaratively using their fabric-mod.json. The specific format/keys are TBD, but likely standardized properties outside the custom block with the rationale that Fabric API acts as an implementation of a certain Loader feature provision.

One option is:

requireNetworkPresence=true
acceptNetworkVersion="same"

where requireNetworkPresence is true for 3.x, false for 1 and 2.x and acceptNetworkVersion is same for 2/3.2 or a version range as used by dependencies for 2/3.1. The mod id to check against is the same as the declaring mod.

Implementation

Instead of relying on sending the entire mod list to the other side or asking for versions of certain mods and verifying the response, a demand based scheme can save both bandwidth and latency.

Each side demands the presence of mods with specific version ranges and react to the other side's demands. Depending on whether the demands can be satisfied, it'll respond with a disconnect or an acknowledge. The ack also serves to communicate the exact presence and version information back.

This is not less safe because the other side could have lied about its mods in the first place.

The packet exchange happens as follows, where individual packets are separated by , and a new line implies the reception of the previous line's packets.

s: plugin request fabric handshake
c: plugin response fabric handshake, local needs, require-protected c->s data
s: local needs, require-protected s->c data, response to client's needs, potential disconnect
c: response to server's needs, potential disconnect, optional-protected c->s data
s: optional-protected s->c data

local needs are the tuple (mod id, req. version range, isOptional) for each local mod with compatibility level 2.x or 3.x. require-protected data is the start of any mod login communication guarded by compatibility level 3.x. This is safe because the other side will disconnect if the requirements are not met before trying to process the data. Fabric registry sync data is one example for this. optional-protected data is the start of any mod login communication guarded by compatibility level 2.x.

The needs response is a standard disconnect packet with a reason or the acknowledge as described above. The ack packet contains the tuple (mod id, version) for each local needs tuple. Entries for non-optional tuples with a fixed version can be omitted since they can be inferred from not disconnecting.

Requirements specified differently between client and server inherently act as the intersection and strictest-first with this scheme.

Extra API

The API to retrieve the handshake results around presence of optional dependencies and the actual versions from ranges is TBD.

Mods not satisfied by the capabilities of the declarative scheme can do their own custom handshake in parallel to the one described here. They need to know when to start and the implementation needs to delay the game's login process until all handshakes are done.

Open questions

i509VCB commented 3 years ago

We can actually get this show on the road since networking-v1 has been merged.

FredsMedia commented 11 months ago

Any progress on this? would be very helpful for my fabric server!

TheModdersDen commented 8 months ago

Any progress on this? would be very helpful for my fabric server!

I'll second this! I have been looking into a way to check and detect when a player joins my Paper based server with Fabric mods and have yet to find a conclusive answer/documentation. I know that there is a system in place for Forge, but I don't know of, or have yet to hear of one, for Fabric.

Maybe I'm posting in the wrong place (and if I am, I apologize, someone feel free to redirect me to the right place), but I would love to see a similar method implemented with Fabric. For server security and player convenience, at the end of the day, mod handshakes really do seem important. 😄

Looking forward to an official response (hopefully)!