Lightweight 26.2 → 26.1 protocol translation for Fabric servers. Lets Minecraft 26.1.x clients join a 26.2-snapshot world without a proxy. Designed for performance-oriented stacks (e.g. alongside ReaperAC).
Outbound path: clientbound packets for legacy connections are rewritten in LegacyPacketHandler (Netty, after packet_handler). This is not a ViaVersion port—only a small server-side subset. For broad multi-version support, use Via on a proxy.
- GitHub Releases — primary jar for each tagged version (attach the same file to Modrinth).
- Prebuilt in repo:
prebuilt/legacylink-0.1.1.jar— convenience copy of the currentbuild.gradle.ktsversion; checksum below. - Modrinth: submit using the release jar + the dependency metadata in this README and in
fabric.mod.json.
LegacyLink is a server-side only Fabric mod. Install these on the dedicated server (clients do not install LegacyLink).
| Requirement | Role | Version this repo is built against |
|---|---|---|
| Java | JVM for the server | 25+ (see build.gradle.kts toolchain) |
| Minecraft | Game / protocol | 26.2-snapshot-3 (gradle.properties → minecraft_version) |
| Fabric Loader | Mod bootstrap | >= 0.19.1 (fabricloader in fabric.mod.json) |
| Fabric API | Library jar (fabric-api on Modrinth / Maven). Used at runtime (e.g. ServerLifecycleEvents). |
>= 0.145.5 — compile against 0.145.5+26.2 (gradle.properties → fabric_version). Use the Fabric API build that matches your exact 26.2 snapshot if yours differs. |
| MixinExtras | Embedded in the LegacyLink jar (jar-in-jar). Registers @WrapMethod and related injectors at preLaunch; not a separate mod to install. |
0.5.3 (build.gradle.kts, io.github.llamalad7:mixinextras-fabric) |
Maven coordinates for the Fabric API artifact (for reference only):
net.fabricmc.fabric-api:fabric-api— version string like0.145.5+26.2from Fabric Maven.
Aside from MixinExtras (above), there are no other bundled libraries: no ViaVersion, no PacketEvents, no optional mods required.
- Install Fabric Loader on the server.
- Put
fabric-api-<version>.jarinmods/(same line as your Minecraft build). - Put
legacylink-0.1.1.jarinmods/(or the version you built). - Run the server with Java 25+.
cp build/libs/legacylink-0.1.1.jar /path/to/server/mods/
# or the prebuilt copy:
cp prebuilt/legacylink-0.1.1.jar /path/to/server/mods/- Legacy clients: 26.1.1+ (protocol floor aligned with supported join path).
- Server: current 26.2-snapshot line this mod is built against; newer Minecraft versions require refreshing LegacyLink when protocols diverge.
- Full multi-version / old-client matrices are out of scope.
- Handshake: accepts 26.1 client protocol during login
- Registry sync: filters 26.2-only entries (sulfur blocks,
sulfur_cubearchetype,sulfur_cavesbiome) from configuration registries; drops 26.2-onlyminecraft:attributeentries (bounciness,air_drag_modifier,friction_modifier) so legacy clients keep 26.1-aligned attribute network IDs (avoids mis-decodedcamera_distance/scaleand bad third-person camera) - Block updates & chunks: remaps sulfur and 26.2-only block state IDs above the 26.1 client registry in block updates, section updates, and full chunks (
LegacyChunkTranslator) - Entity spawns: remaps
sulfur_cubeto slime for 26.1 clients - Telemetry: optional trace flags and session stats (see below)
- Mapping source of truth: block states and items are translated from bundled 26.1.2/26.2-snapshot-3 dump tables by exact ID membership, not by "max legacy ID" thresholds.
- Item stacks (wire): 26.2↔26.1 numeric item ids for legacy connections via
LegacyItemIdTable+ItemStackOptionalCodecMixin(optional stacks, including creative untrusted codec) andHashedStackActualItemMixin(container clicks). Inbound decode is scoped toPacketDecoder#decode(PacketDecoderMixin).
Set -Dlegacylink.verbose=true in JVM args for detailed translation logging.
-Dlegacylink.traceSpawn=true on the server JVM → grep logs/latest.log for [LegacyLink][SpawnTrace]. Stages: connection_send (26.2) vs post_legacy_rewrite (26.1). Types: login (incl. CommonPlayerSpawnInfo), respawn, set_default_spawn, add_entity, player_position — not per-tick move_entity spam.
-Dlegacylink.tracePositions=true on the server JVM → grep [LegacyLink][PosTrace]:
stage |
legacy |
Meaning |
|---|---|---|
connection_send |
false |
Outbound as the server emits for a 26.2 client (before Netty; anticheat may still alter later). |
post_legacy_rewrite |
true |
After LegacyLink for a 26.1 client — closest to what 26.1 receives for rewritten movement types. |
seq is not aligned across sessions; compare by order and packet type.
-Dlegacylink.traceEntityDataRewrite=true on the server JVM → grep logs/latest.log for [LegacyLink][EntityDataRewrite] — logs when remapEntityData changes metadata index sets (beforeIds vs afterIds). Also enabled when outbound capture is on (see below).
Optional: -Dlegacylink.tracePlayerEntityData=true logs player entity data index dumps as [LegacyLink][EntityDataTrace] (separate from rewrite trace).
-Dlegacylink.traceCamera=true → grep [LegacyLink][CameraTrace].
-Dlegacylink.captureOutbound=true on the server JVM, or set environment variable LEGACYLINK_CAPTURE_OUTBOUND to 1 or true (case-insensitive). Grep logs/latest.log for [LegacyLink][OutboundCapture]. Only legacy connections are logged. Stages: connection_send (as Connection.send hands off; bundles expanded) vs post_legacy_rewrite (after LegacyPacketHandler + bundle flatten — matches per-frame encode). Very verbose — disable after capture.
export JAVA_HOME="/path/to/java25"
./gradlew build -x testOutput: build/libs/legacylink-0.1.1.jar
This repository includes a prebuilt Fabric mod jar under prebuilt/ for direct deployment and Modrinth packaging.
Current file:
prebuilt/legacylink-0.1.1.jar- SHA-256:
daa00d6be2b861725fb65f0fdb1292c013e353f88520175674be251c61fdfde1
Verify:
shasum -a 256 prebuilt/legacylink-0.1.1.jarUpdate this checksum in the README whenever the prebuilt jar is replaced.
- Server: smp.thecabal.app
- Discord: Cabal SMP
Issues and pull requests are welcome on GitHub.
MIT — see LICENSE.