Shared protocol library for the tachyne cluster: the attach protocol, canonical-770 renderer, multi-version translation chain, and the gateway session pipeline https://tachyne.com
Find a file
Wesley Channon 855ad30968 Bundles on the wire
Three pieces the engine cannot supply on its own.

bundle_contents now translates. copyFullSlot parses components explicitly by
id — payloads are not length-prefixed — and its default case refuses what it
does not recognise, so before this ANY slot carrying a bundle failed to
translate outright, not merely lost its tooltip. The case recurses through the
same copier, which is what remaps the ids of the items INSIDE the pouch rather
than just the pouch itself. Recursion is bounded at sixteen: vanilla's own
ceiling (a nested bundle costs 1/16 of the capacity), and serverbound bytes
are client-controlled, so unbounded nesting would be a stack overflow on
malformed input.

The component id is 41 canonically, 48 at 774 and 50 at 26.2, from the
per-version datagen registry reports — the same source the rest are pinned
against, and the 1.21.5 report reproduces all eight ids already shipping.

The mouse button is no longer discarded. It was read and dropped with the note
that mode disambiguates, which was true of every feature until now: a bundle
uses plain mode-0 clicks for two OPPOSITE actions, left to take a stack in and
right to tip one out.

And bundle_item_selected (serverbound 0x02, derived from GameProtocols'
ordered builder and checked against seven ids already shipping) becomes
MsgBundleSelect, so the client can say which stack the pouch hands back next.
Vanilla keeps that index out of the contents codec, so each side tracks its
own and it is never sent back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E3k8GjiCuFcFEFmBiXorba
2026-08-15 11:14:37 +02:00
.github/workflows tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
access tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
attach Bundles on the wire 2026-08-15 11:14:37 +02:00
gwsession Bundles on the wire 2026-08-15 11:14:37 +02:00
handover handover: widen stack rows for the book id column 2026-07-13 11:50:27 +02:00
protocol Bundles on the wire 2026-08-15 11:14:37 +02:00
proxyproto tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
render770 Bundles on the wire 2026-08-15 11:14:37 +02:00
shard tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
CONTRIBUTING.md tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
go.mod tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
LICENSE tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
NOTICE tachyne-common: initial public release 2026-07-10 14:43:21 +02:00
README.md README: document gwsession, shard and handover; drop the private-module setup 2026-08-03 22:19:09 +02:00

tachyne-common

tachyne is an unofficial fan project, not affiliated with Mojang, Microsoft, or Minecraft's developer/publisher in any way. See the Disclaimer at the bottom.

Project status

Work in progress. tachyne is young and moving fast: a full survival game runs today, but expect rough edges, missing vanilla features, and breaking changes between updates. Bug reports are genuinely useful — please open a GitHub Issue with your client version/edition and what you saw. Contributions are welcome too: see CONTRIBUTING.md.

Just want to run a server? The quickstart repo brings up the whole stack in one command — Docker Compose or Kubernetes, classic infinite survival by default, real-Cape-Town earth mode as a variant.

What's implemented? Gameplay features live in the world engine, not the gateways — see tachyne-world's feature matrix for what to expect (implemented / partial / missing) as a player.

Shared pure-Go module for the tachyne Minecraft cluster. This module is where the Minecraft wire format lives — the world engine (tachyne-world) has no wire code at all ("worlds are versionless"); gateways compose these packages to terminate real clients.

Packages

  • attach/ — the domain attach protocol between gateways and world pods: the engine's ONLY external interface. Framing u32be len | u8 type | payload; JSON payloads except Chunk (JSON header + zlib binary of raw block-state/light arrays) and Ping/Pong. The frame catalog is typed end to end: core session frames 0x010x09 (Hello/Welcome/Want/Chunk/Move/Time/ Ping/Pong/Bye), clientbound domain events (entities 0x0a0x10, dig/place/ held/blockset 0x110x14, dimension/teleport/command 0x150x17, bossbar 0x1a, survival 0x1b0x1f, items/windows 0x200x27, sound/particles/worldfx 0x280x2a, misc 0x2b0x33, entity-status/swing 0x40/0x41), and serverbound typed actions 0x340x3f. entities.go (consts + struct docs) is the protocol reference — keep it current when adding frames. Events carry ABSOLUTE positions; per-viewer delta math is the renderer's job. Codec rules that bit us once: one json tag PER field, no custom marshalers on embedded structs (a promoted MarshalJSON silently dropped on_ground).

  • render770/ — the shared canonical-770 (Minecraft 1.21.5) renderer + serverbound parsers for the attach events. EntityView is the per-viewer entity tracker: relative i16-delta moves against what THIS viewer actually rendered, absolute resync on first sight / ≥7.5-block jumps / every 40th move, NoSync for entities that must never get sync_entity_position (the 776 dragon constraint). Family renderers: presence (sanitizing chat NBT, boss bars, time), survival (health/XP/effects/hurt/death), items (ItemStack with opaque canonical components, equipment, windows, entity metadata), effects (inline-by-name sounds, particles, world FX, block set), misc (game events, abilities, passengers, vehicles, velocity, trades, difficulty, command tree, respawn). parse.go holds the SID* serverbound packet-id consts + Parse* decoders gateways use to lift 770 serverbound packets into typed action frames. Tests are byte oracles: the engine's deleted packet builders were copied in verbatim as expected-output generators — a renderer change that shifts bytes fails loudly. Add an oracle (or strict re-parser) test with every new renderer.

  • protocol/ — the 770 wire/encoding substrate: VarInt/String, packet framing (plain + zlib-compressed), network NBT writer, paletted containers, positions, generated registries/damage-types/items tables, config-phase composition shared by all gateways (ConfigRegistryPackets(proto), UpdateTagsPacket(proto) — full 1.21.5 AND 26.x tag data — BrandPayload(), FeatureFlags()), and the chained multi-version translation layer (Translator, TranslatorFor(proto), translate_chain.go, generated protomaps incl. 26.x): gateways above 770 render canonical bytes then translate at the client boundary. Generators for the *_gen.go files live in tachyne-world's scripts/ and write here.

  • access/ — client for the tachyne-access policy service: fail-closed login verdicts (Check), 30 s verdict cache.

  • proxyproto/ — PROXY protocol v1 reader (ingress → gateway real client IPs).

  • gwsession/the entire shared Java gateway: the front door (listener, handshake, status ping, version gate, tachyne-access check) and the session pipeline (login → configuration → play bridge, including the silent backend swap when a player crosses a shard seam). Both Java gateway repos are a main.go over this: version pinning plus environment wiring, so a gateway bug is fixed HERE, once.

  • shard/ + handover/ — the multi-pod pieces: shard topology/ownership and the serialized player state that crosses a seam.

Consumers & workflow

Consumers: tachyne-world (the engine — attach frames, render770 types, shard and handover), tachyne-gw-java-770 and tachyne-gw-java-776 (both build their gateway from gwsession, which composes render770 and translates per connection), tachyne-gw-bedrock (Bedrock render), tachyne-ingress (protocol). The module is public — go get github.com/tachyne/tachyne-common@<sha> resolves through the Go proxy with no credentials.

Change protocol here → pin the new sha in every consumer (GOFLAGS=-mod=mod go get github.com/tachyne/tachyne-common@<sha>), go test -race each, deploy world before gateways. New client-visible features enter as: typed attach frame here → renderer/parser in render770/ (with oracle test) → engine emission → gateway wiring.

Credits

  • PrismarineJS/minecraft-data — canonical packet ids and field layouts (MIT).
  • misode/mcmeta — registry, tag and damage-type data reports.
  • Minecraft Wiki — protocol documentation (CC BY-NC-SA; factual reference).
  • ViaVersion / ViaBackwards — cross-version packet and entity differences used as a factual reference for the translation chain and entity substitution (no code reused; GPL).

Development transparency

tachyne is built by its maintainer working with an AI coding agent (Anthropic's Claude): substantial portions of the implementation were written by the model under human direction, and every change is reviewed, tested and deployed by the maintainer. The project's engineering discipline is designed for exactly this workflow — byte-oracle tests pin the wire format, full test suites gate every image build, and real-client verification signs off gameplay. Disclosed here for transparency; judge the code on its behavior.

License

Licensed under the Apache License, Version 2.0 — see LICENSE and NOTICE. Note §6: the license grants no rights to the tachyne name or any trademarks.

Disclaimer

tachyne is an unofficial, independent project. It is not affiliated with, endorsed, sponsored, or approved by Mojang Studios, Mojang Synergies AB, Microsoft Corporation, or any of their subsidiaries — the developer and publisher of Minecraft have no involvement with this project. "Minecraft" is a trademark of Mojang Synergies AB. This project contains no Minecraft game code; all game behavior is independently reimplemented, and data tables are built from openly licensed community datasets (see Credits).