Skip to content

Commit ddcfbc9

Browse files
committed
docs: Add rule that serves as both a comprehensive reference and a practical playbook for anyone working on Connect Java platform injection issues.
1 parent b6b7219 commit ddcfbc9

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
alwaysApply: false
3+
description: Connect Java injection + Netty event-loop compatibility playbook across Velocity/Bungee/Spigot
4+
---
5+
6+
# Connect Java Injection and Netty Event-Loop Playbook
7+
8+
This rule captures our working patterns and pitfalls for platform injection (Velocity, Bungee, Spigot/Paper), Netty compatibility, and how we leverage Floodgate/Geyser learnings. Use this when touching injection code, LocalServerChannel/LocalChannel plumbing, or upgrading Netty/platforms.
9+
10+
## Overview
11+
12+
Minekube Connect is a global proxy network plugin forked from Floodgate that incorporates Geyser's logic. It allows Minecraft servers to be accessible worldwide through edge proxies using local channels and tunneling.
13+
14+
## Core Concepts
15+
16+
- Local server loopback is implemented with `LocalServerChannel`/`LocalChannel` wrappers:
17+
- [LocalServerChannelWrapper.java](mdc:core/src/main/java/com/minekube/connect/network/netty/LocalServerChannelWrapper.java)
18+
- [LocalChannelWrapper.java](mdc:core/src/main/java/com/minekube/connect/network/netty/LocalChannelWrapper.java)
19+
- Session orchestration: [LocalSession.java](mdc:core/src/main/java/com/minekube/connect/network/netty/LocalSession.java)
20+
- Injection entry points per platform:
21+
- Velocity: [VelocityInjector.java](mdc:velocity/src/main/java/com/minekube/connect/inject/velocity/VelocityInjector.java)
22+
- Bungee: [BungeeInjector.java](mdc:bungee/src/main/java/com/minekube/connect/inject/bungee/BungeeInjector.java)
23+
- Spigot/Paper: data injection/handshake tweaks in [SpigotDataHandler.java](mdc:spigot/src/main/java/com/minekube/connect/addon/data/SpigotDataHandler.java)
24+
25+
## Netty Compatibility
26+
27+
- LocalServerChannel is not compatible with native KQueue/Epoll handlers. Use LocalIoHandler-backed event loops.
28+
- Align Netty with platform when needed. Velocity uses Netty 4.2.x. Our repo tracks the version in [Versions.kt](mdc:build-logic/src/main/kotlin/Versions.kt). If you require `MultiThreadIoEventLoopGroup(LocalIoHandler.newFactory())`, ensure Netty is recent enough.
29+
30+
## Velocity (Working Pattern)
31+
32+
- Validate event loop type (KQueue/Epoll/NIO). Use LocalIoHandler-backed groups for LocalServerChannel.
33+
- Proven approach (inspired by Geyser):
34+
- Create `MultiThreadIoEventLoopGroup(LocalIoHandler.newFactory())` for LocalServerChannel bootstrap.
35+
- Delegate non-local channels to Velocity's native event loops when necessary (see Geyser's WatchedSingleThreadIoEventLoop pattern). Adjust to our Netty version constraints.
36+
- Keep injection into Velocity's channel initializers intact; do not replace core semantics.
37+
38+
## Bungee (Working Pattern)
39+
40+
- Symptom fixed: `IllegalStateException: channel not registered to an event loop` during upstream connect/close.
41+
- Root cause: `LocalSession` created its own `DefaultEventLoopGroup`, so its channels weren't registered with Bungee's event loops.
42+
- Fix (minimal and robust):
43+
1. In [BungeeInjector.java](mdc:bungee/src/main/java/com/minekube/connect/inject/bungee/BungeeInjector.java), build a wrapper worker group:
44+
- Base group: Bungee/Waterfall worker `MultiThreadIoEventLoopGroup`.
45+
- Use `SingleThreadIoEventLoop(finalWorkerGroup, wrapperFactory)` where `wrapperFactory` is an IoHandler that delegates:
46+
- Local channels → LocalIoHandler
47+
- Native channels → NIO handler
48+
2. Implement wrapper IoHandler: [ConnectIoHandlerWrapper.java](mdc:bungee/src/main/java/com/minekube/connect/inject/bungee/ConnectIoHandlerWrapper.java).
49+
3. Share the platform event loop group with `LocalSession`:
50+
- Add `LocalSession.setPlatformEventLoopGroup(...)` and call it from Bungee injector before establishing the local channel.
51+
- `LocalSession` now uses the platform group if set; otherwise falls back to the default.
52+
53+
This keeps LocalServerChannel compatible (LocalIoHandler) while ensuring all channels are managed by Bungee's event loops.
54+
55+
## Spigot/Paper (Handshake Mutation on Newer Versions/Java 21)
56+
57+
- Do not reflectively mutate final fields on modern Java/Paper (e.g., handshake hostname). Instead, construct a new handshake packet for 1.20.2+ using `HANDSHAKE_PACKET_CONSTRUCTOR` and existing fields in [ClassNames.java](mdc:spigot/src/main/java/com/minekube/connect/util/ClassNames.java).
58+
- Implementation lives in [SpigotDataHandler.java](mdc:spigot/src/main/java/com/minekube/connect/addon/data/SpigotDataHandler.java); mirrors Floodgate's approach for constructing new packets instead of bypassing final.
59+
60+
## Diagnostics and Playbook
61+
62+
1. Clone upstreams into `./tmp` to study internals:
63+
- Geyser: `tmp/Geyser` (Velocity/Bungee injectors and Netty helpers)
64+
- Floodgate: `tmp/Floodgate` (initializer wrapping and Spigot handshake strategies)
65+
- Velocity: `tmp/Velocity`
66+
- BungeeCord: `tmp/BungeeCord`
67+
2. Identify event loop types from logs (kqueue/epoll/nio). If LocalServerChannel present, ensure LocalIoHandler is used for that channel's loops.
68+
3. If you see:
69+
- `IoHandle ... not supported`: LocalServerChannel is being registered on a non-Local handler (fix with LocalIoHandler-backed event loop).
70+
- `channel not registered to an event loop`: your local channels are not on the platform's loop. Share platform ELG with `LocalSession.setPlatformEventLoopGroup(...)` (Bungee fix) or adopt a wrapper loop that delegates appropriately.
71+
- Phase errors (e.g., LoginSuccess in CONFIGURATION): often caused by event loop/channel mismatch or pipeline ordering; reassess Local vs native handler usage and initializer placement.
72+
73+
## Architectural Principles
74+
75+
- Maintain platform ownership of event loops. Connect should integrate with, not replace, a platform's loop model.
76+
- Only use LocalIoHandler for LocalServerChannel/LocalChannel compatibility; delegate everything else to the platform-native handlers.
77+
- Keep `LocalSession` platform-agnostic but allow platforms to inject their event loop group via a single optional hook.
78+
- Mirror Floodgate/Geyser patterns when possible; they've solved many injection edge cases.
79+
80+
## Changes to Keep Minimal
81+
82+
- Only add:
83+
- `LocalSession.setPlatformEventLoopGroup(...)` and selection in `connect()`.
84+
- Platform-specific wiring (Bungee) to set the platform ELG and wrapper IoHandler.
85+
- Avoid broad refactors; do not introduce separate, long-lived event loops per platform unless necessary.
86+
87+
## Release/Verification Checklist
88+
89+
- Build all modules: `./gradlew build`
90+
- Smoke tests:
91+
- Velocity: injects and accepts join through Connect; ensure no loop incompatibilities.
92+
- Bungee: no `channel not registered` or `IoHandle not supported`; join succeeds.
93+
- Spigot/Paper: no IllegalAccessException on handshake; new-packet path for 1.20.2+ works.
94+
95+
## Commit Guidance
96+
97+
- Title: "platform: fix LocalServerChannel/LocalSession compatibility via IoHandler delegation and platform ELG sharing"
98+
- Body:
99+
- Explain IoHandler wrapper delegation (Local vs native).
100+
- Note `LocalSession.setPlatformEventLoopGroup(...)` and platform usage (Bungee).
101+
- Reference files: [BungeeInjector.java](mdc:bungee/src/main/java/com/minekube/connect/inject/bungee/BungeeInjector.java), [ConnectIoHandlerWrapper.java](mdc:bungee/src/main/java/com/minekube/connect/inject/bungee/ConnectIoHandlerWrapper.java), [LocalSession.java](mdc:core/src/main/java/com/minekube/connect/network/netty/LocalSession.java).

0 commit comments

Comments
 (0)