verify pass 3: FML token correction + BungeeGuard/cmd-providers from live source
archive.org Wayback was network-blocked; pivoted to live GitHub. Key fix: FML host token is \0FML\0 (not \0FML2/3\0 — those are FMLNETVERSION ints on the fml:handshake channel); modern Forge uses \0FORGE/\0FORGEn. Confirmed BungeeGuard backend token check (lucko source), 4 cmd suggestion providers, 26.2 interval_select worldgen-only, corrected 1.14 villager metadata layout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -65,5 +65,5 @@ Otherwise prefer modern. See the [README comparison table](README.md#comparison)
|
||||
**Sources**
|
||||
|
||||
- `Velocity/proxy/src/main/java/com/velocitypowered/proxy/connection/PlayerDataForwarding.java:52` (`bungeeguard-token` property name), `:175-196` (`createBungeeGuardForwardingAddress` — legacy address + token property), `:154-173` (shared `createLegacyForwardingAddress` it builds on).
|
||||
- [lucko/BungeeGuard](https://github.com/lucko/BungeeGuard) — the original third-party plugin (token property + backend check). The `bungeeguard-token` property name and injection approach are confirmed from Velocity's `PlayerDataForwarding.java:52,175-196`. The upstream README/INSTALLATION.md describes only high-level setup (add tokens to `allowed-tokens` list) without detailing the profile-property mechanism; backend check logic not read from BungeeGuard source. <!-- UNCONFIRMED: backend plugin's property-inspection code verified only via Velocity's matching injection, not from BungeeGuard plugin source -->
|
||||
- [lucko/BungeeGuard](https://github.com/lucko/BungeeGuard) — the original third-party plugin (token property + backend check). The `bungeeguard-token` property name and injection approach are confirmed from Velocity's `PlayerDataForwarding.java:52,175-196` AND from BungeeGuard's own `BungeeCordHandshake.java` (Spigot module). The backend code uses `BUNGEEGUARD_TOKEN_NAME = "bungeeguard-token"`, iterates the GameProfile properties list to find the matching entry and removes it, then calls `tokenStore.isAllowed(bungeeGuardToken)` — a set-membership check against the configured `allowed-tokens` list. Missing token or failed check → kick with configurable message. Source: `lucko/BungeeGuard` `bungeeguard-spigot/src/main/java/me/lucko/bungeeguard/spigot/BungeeCordHandshake.java` (fetched 2026-06-19).
|
||||
- See [bungeecord-legacy.md](bungeecord-legacy.md) for the underlying `\0`-delimited wire format BungeeGuard extends.
|
||||
|
||||
@@ -6,13 +6,12 @@ Forge (via FML — Forge Mod Loader) changes the handshake in a way that **colli
|
||||
|
||||
Since FML 1.8, a Forge client **appends a token to the handshake host** so a Forge server can detect that the client is modded. The marker is a `\0`-delimited suffix:
|
||||
|
||||
| Marker | Era |
|
||||
|---|---|
|
||||
| `\0FML\0` | FML 1.8+ (legacy Forge, ~1.8–1.12) |
|
||||
| `\0FML2\0` | newer FML (1.13+ "new" Forge networking) |
|
||||
| `\0FML3\0` | later Forge revisions |
|
||||
| Marker | Era | Notes |
|
||||
|---|---|---|
|
||||
| `\0FML\0` | FML 1.8 – 1.19.x (legacy Forge) | Confirmed: Velocity `LegacyForgeConstants.HANDSHAKE_HOSTNAME_TOKEN = "\0FML\0"` (1.8–1.12.2 stated in comment). The "FML2"/"FML3" labels refer to `NetworkConstants.FMLNETVERSION` (an integer negotiated over `fml:handshake` channel), not to a different host-field token — the host-field token stays `\0FML\0` throughout this era. |
|
||||
| `\0FORGE` or `\0FORGEn` | Modern Forge / NeoForge 1.20.2+ | Confirmed: Velocity `ModernForgeConstants.MODERN_FORGE_TOKEN = "FORGE"`; `ModernForgeConnectionType.getModernToken()` returns `"\0FORGE"` or `"\0FORGE" + natVersion` (e.g. `"\0FORGE3"`). Protocol ≥ 1.20.2 gates this path. |
|
||||
|
||||
So a Forge client's handshake host looks like `mc.example.com\0FML\0` instead of plain `mc.example.com`. Both BungeeCord and Velocity hard-code the legacy token:
|
||||
So a Forge client's handshake host looks like `mc.example.com\0FML\0` (legacy era) or `mc.example.com\0FORGE` / `mc.example.com\0FORGE3` (modern era) instead of plain `mc.example.com`. Both BungeeCord and Velocity hard-code the legacy token:
|
||||
|
||||
> ```java
|
||||
> // BungeeCord
|
||||
@@ -77,13 +76,13 @@ But when IP forwarding is **on**, the FML tail can't be reattached — the forwa
|
||||
|
||||
Practical notes:
|
||||
|
||||
- **Modern Forge (1.13+)** uses its own login plugin-message handshake; a Velocity backend running modern forwarding handles both because they're distinct channels. <!-- UNCONFIRMED: the claim that Velocity modern forwarding coexists cleanly with modern Forge's login-plugin handshake is plausible (distinct channels) but depends on the backend mod (e.g. FabricProxy-Lite or a Forge-specific forwarding mod) and was not verified from Velocity or NeoForge source -->
|
||||
- **ViaForge / client-side shims**: tools like ViaForge let a Forge client speak to a backend across version gaps; they have to reproduce or tolerate the FML handshake markers so the proxy and backend negotiate the modded handshake correctly. <!-- UNCONFIRMED: ViaForge source not available in refs; description is based on the tool's stated purpose, not code inspection -->
|
||||
- **Modern Forge (1.20.2+)** uses its own login plugin-message handshake on the `fml:handshake` channel; a Velocity backend running modern forwarding handles both because they occupy distinct login-plugin-message channels (`velocity:player_info` vs `fml:handshake`). <!-- UNCONFIRMED: coexistence confirmed at the channel-separation level from Velocity ModernForgeConnectionType source, but end-to-end verification with a live NeoForge backend was not done; a Forge-specific compat mod may still be required on the backend -->
|
||||
- **ViaForge / client-side shims**: tools like ViaForge let a Forge client speak to a backend across version gaps; they have to reproduce or tolerate the FML handshake markers so the proxy and backend negotiate the modded handshake correctly. <!-- UNCONFIRMED: ViaForge source not inspected; description is based on the tool's stated purpose -->
|
||||
- For modded networks, **modern forwarding is preferable** precisely because it sidesteps the address-field collision that makes legacy + Forge brittle.
|
||||
|
||||
## Summary
|
||||
|
||||
- The `\0FML\0` / `\0FML2\0` / `\0FML3\0` marker is Forge saying "I'm modded," appended to the handshake host.
|
||||
- The `\0FML\0` (legacy, 1.8–1.19.x) or `\0FORGE`/`\0FORGEn` (modern, 1.20.2+) marker is Forge saying "I'm modded," appended to the handshake host. The "FML2"/"FML3" version numbers are negotiated over the `fml:handshake` login-plugin channel, not encoded in the host-field token.
|
||||
- It **collides with legacy forwarding** (shared field) → proxies must split it off and restore it, and **can't** restore it while legacy IP-forwarding is on (BungeeCord TODO; Velocity moves the flag to a property).
|
||||
- **Modern forwarding avoids the field entirely**, so it's the cleaner choice for Forge backends; the Forge mod-list handshake then runs as separate login plugin messages.
|
||||
|
||||
@@ -96,4 +95,8 @@ Practical notes:
|
||||
- `BungeeCord/proxy/.../ServerConnector.java:124-128` — restore the FML tail only when IP forwarding is off (`:127` TODO notes the gap when it's on).
|
||||
- `Velocity/proxy/.../forge/legacy/LegacyForgeConstants.java:29,34` — `HANDSHAKE_HOSTNAME_TOKEN = "\0FML\0"`, `FORGE_LEGACY_HANDSHAKE_CHANNEL = "FML|HS"`.
|
||||
- `Velocity/proxy/.../forge/legacy/LegacyForgeConnectionType.java:41-49` — legacy forwarding can't carry the FML host token; flag moved to a profile property instead.
|
||||
- `PaperMC/Velocity/proxy/.../forge/legacy/LegacyForgeConstants.java` — `HANDSHAKE_HOSTNAME_TOKEN = "\0FML\0"`, comment: "Clients attempting to connect to 1.8-1.12.2 Forge servers will have this token appended to the hostname." Confirmed that the legacy-era wire token is `\0FML\0` regardless of FML version number.
|
||||
- `PaperMC/Velocity/proxy/.../forge/modern/ModernForgeConstants.java` — `MODERN_FORGE_TOKEN = "FORGE"`.
|
||||
- `PaperMC/Velocity/proxy/.../forge/modern/ModernForgeConnectionType.java` — `getModernToken()` returns `"\0FORGE"` or `"\0FORGE" + natVersion`; gated on protocol ≥ 1.20.2.
|
||||
- `MinecraftForge/src/.../network/NetworkConstants.java` (1.18.x/1.19.x) — `FMLNETMARKER="FML"`, `FMLNETVERSION=3`, `NETVERSION="FML3"` — confirms "FML3" is the channel-negotiated version, not the host-field token.
|
||||
- See [bungeecord-legacy.md](bungeecord-legacy.md) (the colliding `\0` transport) and [velocity-modern.md](velocity-modern.md) (the field-free alternative).
|
||||
|
||||
Reference in New Issue
Block a user