Skip to content

Multiplayer sync and the handshake

Status: Partly implemented. The mixin handshake (clight:hello, API 1.16) works. What is synced today: mod items travel as vanilla stacks with components, mod block positions go to Celestial clients over the clight:blocks payload, data-pack registries are sent by vanilla’s configuration phase, and mods sync their own state with payloads. The CLight handshake (comparing mod lists under each mod’s sync rule, registry id maps, server config sync) and configuration-phase payloads for mods are Planned.

A modded multiplayer session has to agree on three things: which mods both sides have, what mod content is, and what the mods’ state is.

What is synced today

Data How Vanilla clients
Mod items A vanilla stack of the base item with custom_data {clight:"<id>"}, item_model, item_name, max_stack_size See the base item with the mod’s name; its own model only with the mod’s resource pack
Mod blocks The base block in chunk data; the positions of mod blocks are sent to Celestial clients over clight:blocks (a reset, then adds and removes as they change) See the base block
Data-pack content (enchantments, damage types, paintings, …) Vanilla’s configuration phase (registry_data) See it too
Recipes, loot, tags, advancements Vanilla’s own packets See it too
Your mod’s state Payloads you send (Networking) Ignore them
Titles, messages, sounds, menus Vanilla packets See them

Mod content ids are virtual (0x40000000 | index) and assigned in registration order, so a client and a server with the same mods agree on them. A Celestial client with a different set of mods than the server may draw the wrong mod block at a position until the handshake (planned) checks the lists.

Sending mod data

  • Send state on change, not every tick; send what a joining player needs in player.join.
  • Validate everything a client sends.
  • Let the client half work without the server half (vanilla or old servers), and the server half without the client half (vanilla clients).
cl.on("player.join", function(event)
  local b = cl.buf.create(8)
  b:write_i32(mana_of(event.player))
  event.player:send_to_player("my_mod:mana", b)
end)

Singleplayer and LAN

In singleplayer the client and the integrated server are one process; payloads and the clight:blocks sync use the same path, so code written for multiplayer works unchanged. Mods with "side": "both" run their client and server halves in that one process (the server events from the integrated server, the client events from the client).

The mixin handshake (API 1.16)

When a Celestial client with mods joins, it sends clight:hello once the play phase starts: its mods (id, version) and its mixin injections on client targets, each marked advantage and / or predicted. A Celestial server (with or without mods) answers with its own mods (those with side server or both) and checks clight-client-mixins in server.properties:

Value Who may join
allow (default) everyone
deny-advantage clients without injections on advantage targets (entity rendering, fog, camera, input, attack cooldown)
deny clients without any client mixins

A refused client is disconnected with the list of mods to turn off. The client lets its injections on predicted targets (the local player’s movement, jumps, mining prediction, attack cooldown) run only for mods the server listed; on a vanilla or Paper server the answer never comes, so they stay inactive. In singleplayer nothing is gated. This is cooperation with honest clients, not anticheat: the server stays authoritative either way.

Planned: the full handshake

During the configuration phase, a CLight server will send clight:hello (its mods with sync required or optional, their versions and a hash of their registrations); a Celestial client answers with its own list. Then:

  1. The lists are compared under each mod’s sync rule (Sides and environments); a mismatch disconnects with a readable list of what to install or update.
  2. The server sends its id map for mod content.
  3. Server config values are sent to clients that have the mod (read-only for them).
  4. Mods can add their own configuration-phase payloads.

Vanilla clients never answer clight:hello; the server treats them as “no mods” and applies the vanilla fallbacks.