Architecture

How cross-play actually works

A real explanation of how Java and Bedrock players end up in the same world — Geyser, Floodgate, ViaVersion, and the trade-offs.

Java Edition and Bedrock Edition are two different games that happen to share a name. They speak different network protocols, use different authentication systems, and ship on different release cadences. Yet on play.aowmc.com, a player on a Windows PC running Java and a player on a Nintendo Switch running Bedrock can stand in the same chunk, trade items, and chat in the same channel. This page explains exactly how that works — and where the seams still show.

1 The fundamental problem

Before we talk about bridges, it's worth being honest about what we're bridging. Java and Bedrock are not just "the same game with different launchers." They differ at every layer of the stack.

Layer Java Edition Bedrock Edition
Transport TCP on port 25565 UDP (RakNet) on port 19132
Protocol Mojang Java protocol, version-locked to the server jar Bedrock protocol, version-locked to the client
Auth Mojang / Microsoft account (Java entitlement) Xbox Live account (Bedrock entitlement)
Encryption Per-session AES, optional secure profile signatures Per-session, baked into RakNet handshake
UI primitives Chest GUIs, anvil text input, written books Forms (modal / simple / custom), system chat input
Engine Java VM, OpenGL renderer C++ engine, native renderer per platform
Why this matters: a vanilla Bedrock client physically cannot connect to a vanilla Paper server. The first packet it sends is a RakNet handshake on UDP — Paper, listening on TCP, will never even see it. Cross-play is not a setting you toggle. It's three different programs translating between two distinct dialects in real time.

So our job is to put something in front of Paper that speaks Bedrock to the player and Java to the server. That "something" is actually three plugins working together: Geyser, Floodgate, and ViaVersion.

2 The three bridges

Here's the actual packet path on AoW SMP. Java players take the direct route on the left. Bedrock players take the translated route on the right.

Java player PC, official Java client add server play.aowmc.com Bedrock player Switch / iOS / Xbox / Win10 play.aowmc.com : 19132 TCP 25565 UDP 19132 (RakNet) Geyser-Spigot 2.10.1-SNAPSHOT Bedrock RakNet → Java protocol auth-type: floodgate emulated Java client Floodgate 2.2.5 Xbox auth key.pem secret ViaVersion 5.10.1 + ViaBackwards Geyser's emulated version → 1.21.8 protocol translation only PaperMC 1.21.8 (build 69) · port 25565 · world: world Sees every connection as a clean Java client. Game logic, plugins, world data live here.

The key trick: Paper itself does not know or care that Bedrock players exist. By the time a packet from a Switch reaches Paper, it has been re-written into a perfectly valid Java protocol packet at version 1.21.8. Every plugin we run — including all 75 of our custom ones — treats every player as a normal Java player. That is what makes cross-play actually scale.

3 Geyser, in depth

Geyser is the heart of the operation. It runs inside Paper as a Spigot plugin (so it shares the JVM and can talk to other plugins), opens its own UDP listener on port 19132, and pretends to be a Java server to the inside while pretending to be a Bedrock server to the outside.

What Geyser does on every Bedrock connection

  1. Accepts the incoming RakNet handshake on UDP/19132.
  2. Spins up a virtual emulated Java client session inside the same JVM.
  3. Translates each Bedrock packet (movement, block break, inventory click, form response) into the equivalent Java packet.
  4. Translates each Java packet coming back (chunk data, entity spawn, chat, GUI) into the equivalent Bedrock packet, including swapping chest GUIs for Bedrock Forms where appropriate.

Our Geyser config

KeyValueWhy
bedrock.port19132Standard Bedrock port so clients find us via "Add Server" with no custom port.
remote.auth-typefloodgateBedrock players use Xbox auth via Floodgate. No Java account required.
remote.use-direct-connectionfalseForces Geyser to connect to Paper through the normal network stack, so ViaVersion can sit in the middle and translate.
passthrough-motdtrueBedrock server list shows our real MOTD: AoW SMP - Java + Bedrock crossplay.
The use-direct-connection: false gotcha. The default in Geyser is true — it shortcut-pipes packets straight into the server, skipping the network layer for speed. That is great if your server is exactly the version Geyser emulates. It is broken for us, because we need ViaVersion in the pipeline to translate Geyser's emulated client version into Paper 1.21.8. We pay a small CPU tax for going through the loopback; we get a working bridge in exchange.

4 Floodgate, in depth

Floodgate is what lets us keep online-mode=true while still admitting Bedrock players who do not own a Java account. Without it, the only way to let Bedrock players in would be to disable Java authentication entirely — which means anyone could log in as anyone. Hard no.

What Floodgate does

  • Generates a shared secret at install time: plugins/Geyser-Spigot/key.pem, which Geyser reads and Floodgate verifies. This is how Paper trusts that a "Bedrock" login is genuinely an Xbox- authenticated player and not someone spoofing it.
  • Issues each Bedrock player a deterministic offline UUID derived from their Xbox account, so permissions, balances, homes, and claims persist correctly across sessions.
  • Prefixes Bedrock usernames with a . so they never collide with a real Java name. If a Bedrock player's gamertag is Steve, in-game they appear as .Steve.

The dot prefix in practice

Want to send a message, pay, or teleport-request a Bedrock player? Include the dot.
/msg .Steve hey, want to trade?
/pay .Steve 250
/tpa .Steve
/trust .Steve
Java player names do not have the prefix — type them as normal.

Paper settings that make this safe

SettingWhereValueWhy
online-modeserver.propertiestrueReal Mojang auth for Java clients. Floodgate handles Bedrock separately.
enforce-secure-profilepaper-global.ymlfalseBedrock players don't have Mojang-signed chat keys, so we must not enforce them.
perform-username-validationpaper-global.ymlfalseThe .Steve name contains a character Paper would otherwise reject.

5 ViaVersion + ViaBackwards

Here is the subtle bit. Paper runs 1.21.8. Geyser, at any given moment, internally emulates the Java protocol version it was last built against — which may or may not be exactly 1.21.8. If those don't line up, the connection fails with a vague "Outdated server" message.

ViaVersion sits between Geyser's emulated client and Paper, and rewrites packets so they look like whatever protocol Paper is happy with. ViaBackwards handles the opposite direction — Paper sends packets at 1.21.8, ViaBackwards re-encodes them at the older version Geyser expects.

ViaVersion 5.10.1-SNAPSHOT
Translates incoming client packets up to the server's version. Pure protocol math; no game logic.
ViaBackwards 5.10.1-SNAPSHOT
Translates outgoing server packets down to the client's version. Same trick, reversed.
Why we need both
A bridge needs lanes in both directions. Without ViaBackwards, the chunks Paper sends would arrive as gibberish.
Performance note from history: the VPS was originally provisioned with 2 vCPU and 8 GB RAM. Geyser plus ViaVersion translation under load pegged a core and produced visible lag. The mid-session upgrade to 4 vCPU / 16 GB on the same KVM 4 plan resolved it. Cross-play translation is not free CPU; size the host accordingly.

6 What works flawlessly

Once the three bridges are wired up correctly, a startling amount of the game just works for Bedrock players. The translation layer is mature enough that most of our 6 consolidated in-house packs were written without anyone touching Bedrock-specific code.

Chest GUIsAuction house, kits, shops Written books/guide tappable links work Item dropsIdentical drop tables; same pickup rules Mob behaviorMythic Champions, gear, loot all apply Chat & commandsFull Adventure formatting Particles & soundsTranslated to Bedrock equivalents ClaimsGolden-shovel works; /trust .Name Skills XPAuraSkills tracks Bedrock players normally Economy/pay, /balance, /ah, /daily Homes & warpsEssentials data is shared

The auction house is a particularly nice case. GlobalMarketplace is Bedrock-Forms-aware: when a Java player opens /ah, they see a chest GUI; when a Bedrock player opens the same command, they see a native Bedrock Form. Same data, two presentations. The plugin handles the fork; the player never notices.

7 What feels different on Bedrock

Cross-play is excellent, but it is not invisible. Bedrock players should know the small papercuts going in — almost all of them are downstream of how Bedrock the game works on consoles, not of anything we can fix server-side.

Friction Why it happens Workaround
Typing chat commands is awkward on a controller Bedrock chat input is a system text box, not a free overlay We expose tappable links in the welcome book (/guide) and in /help
No F3 debug screen / no live coords F3 is a Java-client-only feature Turn on coordinates in Bedrock world settings; use /spawn + /backtrack
No client-side mods (OptiFine / Sodium / minimap) Bedrock has no mod loader — only Marketplace add-ons Use the squaremap web map at map.aowmc.com and pin shared landmarks before long trips.
Anvil renaming feels different Bedrock anvil UI is a native form, not a free text field Just works; the field is at the top of the form
Some signs / written books look slightly off Font metrics differ between editions We keep server signs short and avoid hex colors on critical UI
Custom textures from Java resource packs don't apply The two editions use entirely different texture formats We use vanilla items/blocks only — by design — so the two editions render identically
/msg requires the dot prefix for Bedrock recipients Floodgate prefixes Bedrock names to prevent collisions Tab-complete works; or just remember: dot for Bedrock
PvP feel: Bedrock has touch input and aim assist; Java has mouse precision. We run Survival/Easy and lean cooperative, so this rarely matters. But it's worth knowing if you do organize a fight — the editions don't play identically, even when the server treats them identically.

8 Why plugins and not mods

A reasonable question: if we wanted custom mobs, custom loot, custom worldgen, why not just write a Forge or Fabric mod? The short answer is that mods would break Bedrock cross-play, which is the whole point of this server.

Mods change the client too
A Forge mod that adds a new item type requires every connecting client to also run that mod. Bedrock clients cannot run Java mods at all. The moment you ship a mod, Bedrock players are locked out.
Plugins are server-only
A Paper plugin runs entirely on the server. The client — Java or Bedrock-via-Geyser — just sees normal vanilla packets. That is why all 75 of our custom plugins are vanilla items and blocks only: it is the one shape that survives the translation layer with zero loss.
No client install for anyone
Java players add the server. Bedrock players add the server. Nobody downloads anything. That low friction is why the server actually has people on it.

This is the single most important rule in our custom-plugin charter: paper-api dependency only, Adventure API for text, vanilla items and blocks only, server-side ADD-only logic. Every plugin we ship — the guidebook/onboarding module in AoWInfra, the Champions module in AoWMythic, AoWChestLoot, all of them — was written against that rule. The reward is that cross-play keeps working as we add features.

9 Quick reference

25565Java TCP port
19132Bedrock UDP port
1.21.8Paper version target
3Plugins on the bridge
.Bedrock name prefix
trueonline-mode

Connect strings

# Java client
Multiplayer → Add Server → play.aowmc.com

# Bedrock client (any platform)
Servers → Add Server
  Name:   AoW SMP
  Address: play.aowmc.com
  Port:    19132