Add ViaAxiom
Deploy / Build (push) Skipped
Pull Request Build / Build (pull_request) Failing after 17s

This commit is contained in:
Jakob Schulz
2026-11-01 15:30:21 +01:00
parent e198772885
commit f373e3d6d9
76 changed files with 4496 additions and 896 deletions
+47
View File
@@ -0,0 +1,47 @@
# Axiom protocol notes
Taken from [AxiomPaperPlugin](https://github.com/Moulberry/AxiomPaperPlugin). The "API version" is Axiom's own wire version.
## Handshake
API 9: the client sends `axiom:hello` with VarInt API, data and protocol versions. The server answers with `axiom:enable`.
API 10: the server sends `axiom:hello` first, holding a long challenge. The client replies with the same three VarInts plus that long. Failures arrive as `axiom:goodbye` with a string.
Neither handshake carries the server's Minecraft version. The hello's protocol field describes the client, and the server translates IDs itself if it differs from its own. ViaAxiom writes the backend's protocol there, so only ViaAxiom translates.
An API 9 server has no hello to send. ViaAxiom detects it from `minecraft:register` containing `axiom:hello` without `axiom:tunnel`, and makes up the challenge itself.
`axiom:enable` fields:
| API 9 | API 10 |
|---|---|
| boolean enabled | boolean enabled |
| int max buffer size | byte config version, currently 0 |
| VarInt blueprint version | VarInt blueprint version |
| VarInt custom data overrides | int tunnel split size, default 31000 |
| VarInt rotation overrides | int max tunnel packet size, default 2097152 |
| | VarInt custom data overrides, always 0 |
| | VarInt rotation overrides, always 0 |
| | VarInt count, then serverbound channel names |
## Tunnel
API 10 sends large serverbound packets through `axiom:tunnel`. Each fragment starts with a flag byte, FIRST=1 and LAST=2. The joined body is the channel name, an int uncompressed size, a flag byte (1 means Zstd), and the payload. API 9 sends those packets raw instead, which needs Paper's large payload decoder.
Translation can change a packet's size, so ViaAxiom collects all fragments, translates, and splits again.
## Payloads with block IDs
| Channel | Direction | IDs |
|---|---|---|
| `axiom:set_block` | serverbound | map of long position to VarInt state |
| `axiom:set_buffer` | serverbound | paletted sections, type 0 only |
| `axiom:response_chunk_data` | clientbound | paletted sections |
| `axiom:register_custom_block_v2` | clientbound | VarInt state, or -1 and a string |
`set_buffer` is a dimension key, a UUID, a type byte, then sections of long index, paletted container, and block entities, ending at `-9223371899415820288`.
Paletted containers lost their long array length in protocol 770 (1.21.5). Bits per value of 0 is a single value, 4 to 8 uses a local palette, and anything higher stores global IDs.
The Axiom empty state is `void_air`, which means "leave this block alone". It must never become a placeholder.