Seamless, zero-loading-screen server switching for Minecraft networks (Velocity + Paper).
When a player is moved between two backend servers behind a proxy, vanilla Minecraft shows the "Downloading terrain" screen (and on 1.20.2+, a full CONFIGURATION-phase world reload). InstantTransfer removes that entirely: the world morphs in place — no screen, no disconnect, no visible transition.
🇫🇷 Version française : README_FR.md
This project patches Velocity's internals and rewrites live protocol traffic. It is a working proof of concept — repeatedly validated live on a small Paper 1.21.4 network (repeated zero-screen round-trips, knockback, death respawn relay, cross-dimension fallback) — but not a hardened product. The < 1.20.2 legacy path is implemented and unit-covered yet not yet exercised on real old servers. Expect breakage with: untested Minecraft versions, mods, other packet-level plugins, or different registries/datapacks between backends. Use it on test networks, at your own risk.
Three cooperating components (all are required):
| Component | Where | Role |
|---|---|---|
velocity-patch/ |
replaces your Velocity jar | Skips the client CONFIGURATION phase on switches (absorbs the backend's config proxy-side via a known-packs echo) and sends neither JoinGame nor Respawn — the client never leaves PLAY. Announces entity-id pairs + gamemode to the plugin. Tracks client dimension; auto-fallbacks to Respawn KEEP_ALL_DATA if backend dimension differs (brief flash, safe). |
proxy-plugin/ |
proxy plugins/ (+ packetevents-velocity) |
Tracks what the client sees (chunks, entities, effects, abilities). On arrival: lets the teleport pass, freezes the player with client-side flight until the landing chunk is delivered (no falling through unloaded ground), then removes the previous server's ghosts (entities, chunks, potion effects) and rewrites entity ids directionally (backendId→clientId server→client, clientId→backendId client→server). Timeout guard: on chunk delay sends position correction + keeps flight (configurable, default 5 s). |
backend-agent/ |
every backend's plugins/ (+ packetevents-spigot) |
Arrival grace: cancels fall damage, temporarily allows flight server-side (so the freeze can never kick), revokes it the instant the proxy signals the arrival is complete (plugin-message channel). |
Requirements for a seamless switch: backends on the same Minecraft version (any of 1.13 – latest, Spigot/Paper) with identical registries/datapacks. Cross-dimension is supported via auto-fallback to Respawn (brief flash).
Per-release maintenance is one line: add the matching map(...) entry to the Respawn decode
table in velocity-patch/seamless.patch, run scripts/check-protocol-tables.sh +
scripts/validate-patch-hunks.sh, rebuild the jar (see velocity-patch/README.md).
- Build (JDK 21, Maven + Gradle):
mvn -f pom.xml clean package # proxy-plugin + backend-agent # Velocity patch: see velocity-patch/README.md (pre-built jar included) - Replace your Velocity jar with the patched one (
velocity-patch/). - Proxy
plugins/:packetevents-velocity+proxy-plugin/target/InstantTransfer-*.jar. - Each backend's
plugins/:packetevents-spigot+backend-agent/target/InstantTransferAgent-*.jar. - Switch servers. There should be no screen at all.
| What | Where | Default |
|---|---|---|
| Disable everything (vanilla Velocity behavior) | -Dvelocity.seamlessSwitch=false |
enabled |
| Fallback mode: clean same-dimension Respawn (brief flash, no companion plugins needed) | -Dvelocity.seamlessRespawn=true |
off (zero-screen) |
| Proxy plugin master switch, debug logs | plugins/instanttransfer/config.properties |
enabled |
| Guard timeout (ms) — on timeout sends position correction + keeps flight | plugins/instanttransfer/config.properties → guard-timeout-ms |
5000 |
| Backend agent verbose logs | plugins/InstantTransferAgent/config.yml → debug |
false |
proxy-plugin/ Velocity plugin (packetevents): tracking, arrival freeze, ghost cleanup, id remap
backend-agent/ Paper plugin: arrival grace (fall/flight guard), coordination channel
velocity-patch/ Patched Velocity jar (velocity-instanttransfer.jar) + source diff + build instructions
docs/EXPERIMENTAL.md R&D log: every approach tried, what failed and why, coverage audit, roadmap
- ✅ Zero screen, no fall damage, no ghost entities/chunks/effects/weather/GUIs/cooldowns/scoreboards, directional entity-id remap, gamemode resync — validated live on Paper 1.21.4 across repeated round-trips including knockback, death respawn relay and cross-dimension fallback (Velocity patched 3.6.0-SNAPSHOT core).
- ✅ Full ghost lifecycle on every post-join switch (
/server,/transfer, API alike): snapshot at arm → purge at switch (scoreboard + entities) → release cleanup on arrival-chunk delivery (97–472 ghost chunks destroyed per switch in tests). - ✅ Supported range: MC 1.13 → latest (homogeneous networks); ≥1.20.2 via config-phase absorption, 1.13–1.20.1 via PLAY-state switch (JoinGame intercepted, never forwarded) — legacy path implemented + unit-covered, live matrix pending.
- ✅ Performance pass: raw chunk-coord reads, raw entity-id rewrite for metadata/velocity/teleport/position-sync (packetevents-wrapper-free, rollback-safe), deferred ghost-chunk unloads (deduped against destination resends), bounded chunk-tracking memory.
- ✅ Cross-dimension supported via auto-fallback to Respawn KEEP_ALL_DATA (brief loading flash, safe).
⚠️ Identical registries/datapacks required between backends (different datapacks → do not use).⚠️ A player moving during the ~300 ms handshake may get a harmless server-side position correction (moved too quicklyin logs).
Inspired by a private implementation showcased by Lodjo28 (no code published); this is an independent from-scratch implementation.