Fabric API

Fabric API

106M Downloads

Network handshake design

sfPlayer1 opened this issue ยท 3 comments

commented

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

  • Are any important use cases missing?
  • Is the global requirements specification generally sufficient or is it likely to differ between client and server? E.g. is it desirable to require a mod only on the client or on both client&server, but not exclusively on the server? Similar with version ranges, e.g. is it likely to demand a stricter version range from one side?
  • What should happen if an optional dependency as in 2.x is present, but has the wrong version? Should it be treated as absent or failure? Is it useful enough for the mod to decide between those?
  • What is the best mod.json declaration syntax?
  • Is it too limiting to restrict the c<->s dependencies to the own mod? Note that extending this to arbitrary mods complicates the json declaration, while the implementation is largely unaffected.
  • The 2nd (s->c) needs query can be replaced by the client including its mod list in the query to save another trip. Alternatively it can get greatly reduced by assuming the client doesn't query for mods it doesn't have and that its requested version range contains the client's mod version. If we send a mod list, do we want to offer mods to hide themselves?
commented

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)!

commented

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

commented

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