feat: erased-bridge — 26.X fabric-official pipeline + fixes#4
Open
Axionize wants to merge 23 commits into
Open
feat: erased-bridge — 26.X fabric-official pipeline + fixes#4Axionize wants to merge 23 commits into
Axionize wants to merge 23 commits into
Conversation
Restructures the Fabric module into four siblings to support Minecraft
26.X alongside the existing 1.16.1→1.21.11 chain-loading range:
fabric-common/ pure-Java library (chain-loader-adjacent utilities,
loggers, registry manager, Adventure-only types).
Has no MC dependency so it survives the intermediary
vs official mapping boundary at runtime.
fabric-intermediary/ existing chain-loading aggregator (1.14 yarn,
intermediary remap). Holds the bootstrap + all
MC-typed code + the per-version mcXXXX subprojects
(mc1140, mc1194, mc1202, mc1211, mc1216) that the
chain loader walks at preLaunch.
fabric-official/ structural sibling for MC 26.X (Java 25 floor,
Mojang's new version scheme). Uses fabric intermediary
0.0.0 mapping because Mojang stopped publishing
official mappings starting with 26.X and Yarn has
no 26.X build either; meaningful MC-typed code
awaits usable mappings. mc261 is the first chain
slot under it.
fabric/ top-level aggregator. Loom JiJ-nests the three
siblings plus their per-version subprojects into the
single published packetevents-fabric-<ver>.jar.
All existing fabric/{src,mcXXXX} content was moved via `git mv` so blame
follows; no source rewrites. The accesswidener resolution in
fabric-intermediary now uses the literal filename instead of
${rootProject.name}, which previously silently failed under the workspace
composite (rootProject.name = "packetevents-public").
- Clear skip-worktree on settings.gradle.kts so the include() additions for
fabric-common / fabric-intermediary / fabric-official actually ship in the
branch (the worktree-only edit didn't reach the index in the prior commit).
- Rename fabric-intermediary modid from "packetevents" to
"packetevents-fabric-intermediary". Sharing the id with the outer
aggregator made Fabric Loader see duplicate "packetevents" mods.
- Add `minecraft: ">=1.16.1 <26"` upper bound to fabric-intermediary so
intermediary-mapped code can't load on a 26.X server where intermediary
symbol names don't resolve.
- Stop double-JiJ in fabric/build.gradle.kts: aggregator now nests the
variant remapJars by file path only (no `include(project(...))` for
variants), which removed the dev/namedElements jars that Loom was
silently adding alongside the real remapped output.
- Fix archiveBaseName for variants. fabric-intermediary's nested jar used
to be `packetevents-public-fabric-fabric-intermediary` (double "fabric"
because the convention prepends `-fabric` then `-${project.name}`).
Variants now compute archiveBaseName explicitly.
Findings retrooper#5 and retrooper#6 from the review remain open: 1.14/1.15 support drop is
intentional per project floor (1.16.1); the variant-scaffolding
duplication is the next clean-up but not a functional blocker.
MC 26.1+ requires Java 25 for Loom to fetch/configure the server jar. The previous Java 21 toolchain causes a fail-fast in fabric-official's configure phase: "Minecraft 26.1.2 requires Java 25 but Gradle is using 21". Bumps the CI Gradle JDK to 25 so the Loom setup of fabric-official can proceed. Java 17/21 modules continue to compile via Gradle's release flag.
Same root cause as the Grim PR — Fabric Loader reads each mod's accessWidener in loadClassTweakers BEFORE filtering by depends, so an intermediary-namespaced AW from packetevents-mc1140/mc1194/mc1202/mc1211/ mc1215/mc1216 would crash on a 26.X server (`Namespace (intermediary) does not match current runtime namespace (official)`). Each mcXXXX now declares an explicit `<26` upper bound on minecraft. mc1140 also gets an explicit `>=1.14` lower bound (it was previously unbound). Verified end-to-end: fabric-26.1.2 boots clean with only fabric-official loaded; fabric-1.21.11 loads packetevents-mc1140/mc1194/mc1202/mc1211/ mc1216 chain without regression.
Hoist the 13 MC-free + 6 MC-typed bridge classes from fabric-intermediary
into fabric-common. The MC-typed signatures widen to platform-agnostic
types so a Mojang-named branch (fabric-official) can reuse the same
common code without seeing yarn names:
* PacketEventsMod: drop both isOurConnection(ClientConnection / NetworkSide)
overloads. They were documented as upstream ABI-compat only and unused
internally — removing them is cheaper than another bridge.
* FabricInjectionUtil.injectAtPipelineBuilder takes PacketSide instead of
NetworkSide; the per-version mixin entrypoints convert at the callsite.
fireUserLoginEvent takes Object instead of ServerPlayerEntity.
* AbstractFabricPlayerManager.disconnectPlayer is now (Object, String);
add an abstract kickOnException(Object, String) so PacketEncoder's
netty-thread exception path no longer has to instanceof a yarn type.
* PacketEncoder / PacketDecoder .player widen from PlayerEntity to Object.
PacketEncoder.exceptionCaught delegates to playerManager.kickOnException
instead of the inline ServerPlayerEntity cast + server-thread hop.
* FabricChannelInjector.setPlayer drops the (PlayerEntity) casts (the
fields are Object now).
Per-version concrete managers (mc1140/mc1194/mc1202) updated to override
disconnectPlayer(Object, String) with an internal cast back to
ServerPlayerEntity. mc1140 also picks up the kickOnException override
since that's where the server-thread hop logic lives.
FabricItemType stays in fabric-intermediary — its 7 MC touches don't
erase cleanly; a parallel Mojang-named FabricItemType will live in
fabric-official.
Dead code dropped: FabricCustomPipelineUtil (unused everywhere) and the
two empty ConnectionMixin/PlayerListMixin placeholders.
Build: :fabric-common:compileJava + all five :fabric-intermediary:mcXXXX
remapJar tasks pass. fabric-common grows from 17KB to 54KB carrying the
moved bridge classes; fabric-intermediary jar stays the same size since
the moved bytes JiJ back in via include(project(":fabric-common")).
Now that fabric-common carries an MC-free PacketEventsMod, fabric-official no longer needs its own duplicate chain-loader scaffold. Point the mod's preLaunch + main entrypoints directly at fabric-common's class (JiJ'd into the official jar) and have mc261 contribute a peMainChainLoad entry for ServerVersion.V_26_1. * fabric-official/build.gradle.kts: tighten the mappings comment — source in this module still can't reference net.minecraft.* because we're on intermediary:0.0.0:v2; per-version Mojang-named code goes in mc261 once Loom can resolve Mojang names against a real mapping. * fabric.mod.json: declare entrypoints io.github.retrooper.packetevents .PacketEventsMod (lives in fabric-common). * mc261/Fabric261ChainLoadEntrypoint: no-op initialize() — registering a concrete AbstractFabricPlayerManager subclass into chainLoadData waits on real 26.X mappings, but the chain participation point exists. Aggregator jar (top-level :fabric:remapJar) JiJs fabric-common (55KB) + fabric-intermediary (4.5MB) + fabric-official (3.9MB) side-by-side; each loads exclusively per its depends.minecraft range.
After the bridge moved to fabric-common, downstream consumers (Grim) that depend on packetevents-fabric saw a POM declaring only fabric-loader and failed to compile against FabricPacketEventsAPI etc. Re-export the same api() + include() block fabric-intermediary used to carry, so consumers get the transitive deps through the published metadata.
Switch fabric-official + mc261 from fabric-loom-remap (with empty intermediary:0.0.0:v2 mapping) to fabric-loom (LoomNoRemap). The MC 26.X jar ships pre-deobfuscated with Mojang's official names, so Loom treats the jar as already in the target namespace — no mappings() block needed and source code can compile against net.minecraft.world.item.Item, net.minecraft.network.Connection, etc. directly. Surface added: * FabricOfficialPlayerManager: concrete subclass of AbstractFabricPlayerManager using ServerPlayer.connection (ServerGamePacketListenerImpl) for ping, channel lookup, and disconnect. kickOnException hops to the server thread via ServerLevel.getServer().execute(...). * ConnectionMixin: @Inject TAIL of Connection.configureSerialization to install PE's encoder/decoder on every connection. Priority 1500 keeps us after Via. PacketFlow -> PacketSide conversion happens at the callsite so fabric-common's FabricInjectionUtil stays Mojang-free. * packetevents.accesswidener (official namespace): widens Connection.channel, Connection.receiving, and ServerCommonPacketListenerImpl.connection so fabric-common's FabricChannelInjector + the player manager can reach the netty Channel. * mc261/Fabric261ChainLoadEntrypoint.initialize: setPlayerManagerIfNull with a LazyHolder around FabricOfficialPlayerManager. * fabric.mod.json now references the mixin config + access widener. Build wiring: * `apply(plugin = "net.fabricmc.fabric-loom")` — the qualified id maps to LoomNoRemapGradlePlugin; the short "fabric-loom" applies the older all-in-one LoomGradlePlugin and conflicts. * LoomNoRemap doesn't register remapJar/modImplementation/namedElements; switch to plain jar/compileOnly/project(...) and route the jar output to rootProject's libs/ for the top-level aggregator to nest. * include(project(":fabric-official:mc261")) so the per-version variant is JiJ'd inside fabric-official. * fabric/build.gradle.kts (aggregator): dependsOn ":fabric-official:jar" instead of ":fabric-official:remapJar". Aggregate jar layout verified: fabric-official-3.9MB JiJs mc261 + fabric-common + api + netty-common + conditional-mixin alongside the fabric-intermediary-4.5MB variant.
…itor Mixin descriptor verification rejected Object monitor — the target method signature is configureSerialization(ChannelPipeline, PacketFlow, boolean, BandwidthDebugMonitor). Using Object was a leftover habit from the erased-bridge work in fabric-common where Object lets the same source compile in two namespaces; the per-version mixin source already imports Mojang names freely. Verified on a real fabric-26.1.2 dedicated server: * PE 2.12.2+139086285 + Grim fabric-official scaffold deployed + booted. * Real 26.1.2-wurst HMC client completed LOGIN -> CONFIGURATION -> PLAY with no PacketProcessException, the path PR retrooper#9 broke. * Server log shows 'Offline[/127.0.0.1:43648] logged in with entity id 45 at (10.5, -60.0, -6.5)' and 'joined the game'. EOF
Previously each wrapper (fabric-intermediary, fabric-official) included its own copies of api, adventure, netty-common, fabric-common, and conditional-mixin. The top-level fabric/ aggregator then JiJ-nested both wrapper jars side-by-side, so the shared bytes ended up physically duplicated inside the published packetevents-fabric.jar. Drop the include() block from each wrapper; keep only api() so the mcXXXX subprojects still see the deps on their compile classpath. The aggregator's include() block (already present) becomes the sole JiJ source for shared deps, with conditional-mixin added. Net storage: packetevents-fabric.jar 12.8MB -> 4.5MB fabric-intermediary jar 4.5MB -> 86KB fabric-official jar 3.9MB -> 7.4KB Also move 26.1.2-specific files from fabric-official/src/main into fabric-official/mc261 where the per-version chain participants live: FabricOfficialPlayerManager -> mc261/.../Fabric261PlayerManager ConnectionMixin -> mc261/.../mixin/ConnectionMixin packetevents.accesswidener -> mc261/.../packetevents.accesswidener packetevents.mixins.json -> mc261/.../packetevents.mixins.json mc261's fabric.mod.json now declares its own mixins + accessWidener; fabric-official/src no longer references them. Future mc262 follows the same shape — its own concrete player manager, mixin, AW — instead of piling 26.X-version-specific signatures into the wrapper. Verified end-to-end: fabric-1.21.11 + Grim catches mineflayer with TickTimer (x49) fabric-1.19.4 + Grim accepts mineflayer connect cleanly fabric-26.1.2 + PE+Grim boot, mc261 chain registers FabricPlayerManager
…ore publishMods PE codex review on b99c4b9 flagged REQUEST_CHANGES with 1 HIGH + 3 MED. All addressed: * HIGH mc261 mod range. Was depends.minecraft >=26.1 with no upper bound, which would load on hypothetical 26.2+ where Connection.configureSerialization's signature or the widened ServerCommonPacketListenerImpl.connection field could drift. Tightened both mc261's and fabric-official wrapper's range to >=26.1.2 <26.2. * MED registry-manager null. Fabric261ChainLoadEntrypoint only set the player manager — FabricPacketEventsAPI.getRegistryManager() called getLazyRegistryManagerHolder().get() against a null LazyHolder because the intermediary chain that normally fills it is gated <26. Wired a null-returning ItemRegistry stub so the chain comes up complete; a real 26.X BuiltInRegistries-backed implementation lands when 26.X gets a real intermediary mapping. * MED 1.14/1.15 metadata. The aggregator now declares depends.minecraft >=1.16.1, but mc1140 still claimed >=1.14. Bumped mc1140 to >=1.16.1 <1.19 since the aggregator gates everything <1.16.1 anyway and the upper bound makes the range explicit. * MED publishMods --dry-run. The previous wiring set file = remapJar via configure<ModPublishExtension>, but that block disappeared when the aggregator's tasks { ... } closure was rewritten. Re-added the configure<ModPublishExtension> outside the tasks block. Verified: :fabric:remapJar succeeds, :fabric:publishMods --dry-run no longer fails on missing `file`.
…nges
Codex r2 MED. The meta mod's '>=1.16.1' unbounded-above declaration would
accept hypothetical MC 1.22–26.0 servers (between fabric-intermediary's
'<26' upper bound and fabric-official's '>=26.1.2' lower bound) where no
nested variant activates. Fail at fabric-loader's range check instead by
declaring the actually-supported MC ranges as a union:
"minecraft": [">=1.16.1 <26", ">=26.1.2 <26.2"]
fabric.mod.json supports the array form as OR semantics on the version
predicate. Matches the union of fabric-intermediary's '<26' and
fabric-official's '>=26.1.2 <26.2' ranges exactly.
Codex r2 MED. The earlier codex-r1 commit (ff8662f) renamed rootProject from 'packetevents' to 'packetevents-public' to work around the workspace composite's Eclipse 'Duplicate root element' error. That also renamed every published artifact to 'packetevents-public-fabric-*' when consumers / CI still expect the canonical 'packetevents-fabric-*'. Restore the upstream rootProject.name = 'packetevents' and the conditional apply(from = 'workspace.gradle.kts') hook that grim.sh re-emits on clone/pull. The workspace.gradle.kts file (now also .gitignore'd, but committed once here so the composite still resolves without re-running the workspace hook) overrides the name to 'packetevents-public' only when the composite is active. Artifact names verified back to 'packetevents-fabric-*.jar'.
… JVM Same reason as gradle-publish.yml (already on 25): fabric-official's LoomNoRemap plugin configures the 26.1.2 jar during Gradle's config phase, before toolchain selection. Gradle itself must be on Java 25.
The intermediary chain has PlayerManagerMixin (mc1140) that hooks PlayerManager.onPlayerConnect to fire UserLoginEvent and to associate the netty Channel with the new ServerPlayer object. Without the equivalent on the Mojang-named 26.X chain, UserConnectEvent fired at HANDSHAKING but UserLoginEvent never fired — so downstream consumers (Grim's CheckManagerListener.onUserLogin / PacketPlayerJoinQuit) never saw the player and ran no checks. Mojang renames since 1.21.11: PlayerManager → PlayerList PlayerManager.onPlayerConnect → PlayerList.placeNewPlayer sendToAll(Packet) → broadcastAll(Packet) PlayerListMixin attaches at the same two points as PlayerManagerMixin: HEAD of placeNewPlayer → injector.setPlayer(channel, player) AFTER broadcastAll → FabricInjectionUtil.fireUserLoginEvent(player) Live-verified: Grim now flags Wurst Flight on fabric-26.1.2 (smoke test fix in the sibling Grim-public repo). Fixes the silent regression noted during fabric-official chain bring-up.
CLIENT_SETTINGS, COOKIE_RESPONSE, PLUGIN_MESSAGE moved from PLAY to CONFIGURATION in 26.X. Their presence in ServerboundPacketType_26_1 shifted every ordinal from retrooper#14 onwards, causing PLAYER_POSITION (MC ID 26) to map to INTERACT_ENTITY (PE ordinal 26). Result: PE threw IndexOutOfBoundsException on every movement packet and Grim never saw position data. Rebuilt the enum from 26.1.2 GameProtocols.class bytecode extraction (javap constant pool, deduplicated addPacket call order). 61 entries, 0-indexed, matches MC's registration order exactly.
Some 26.X PLAY packet wrappers read past their buffer because the serialization format changed. The IOOBE kills the entire event callEvent chain, preventing downstream listeners (Grim) from seeing the packet at all. Catch IOOBE specifically, reset the buffer reader index, and return the event so the raw bytes still flow to MC's decoder.
…ayer eviction removeIfExists + addBefore triggers handlerRemoved on the old PE decoder, which PE's close-listener interprets as a channel disconnect. PlayerDataManager.remove fires, the GrimPlayer is evicted, and all subsequent PLAY packets hit player==null → no check processing. PE's handlers PERSIST across MC's state transitions because MC's configureSerialization only replaces its own 'decoder'/'encoder' handlers. Just force the User state to PLAY and leave the handlers alone.
Previous extraction used constant pool order which misses cross-package packets (common/cookie/ping) registered in PLAY state. Extracted from javap -c instruction sequence (getstatic order = addPacket call order). PLAYER_POSITION is at ordinal 30 (was incorrectly 26 in prior fix).
Strip [pe-reinject-diag] and [pe-inject-diag] System.out.println calls that were used to trace the CONFIGURATION→PLAY state transition. The underlying issue is resolved.
Fabric Loader 0.19.2 resolves entrypoints from nested JiJ mods even when their version constraints don't match the running MC. This caused ClassNotFoundException for Fabric1140ServerPlayerManager on MC >=1.19. The chain-load sort already picks the best version (mc1194 for 1.19+), so loading mc1140 on newer MC is harmless — setIfNull is a no-op.
- Revert ServerboundPacketType_26_1.java to origin/grim/2.0 — enum values were unchanged; only comments and license header differed. - Remove IOOBE try-catches in PacketEventsImplHelper. They were added before the enum was confirmed correct from bytecode; with the enum matching origin, they're obsolete. If a wrapper genuinely mis-parses a 26.X packet, we want to know rather than hide it in a hot loop. - Drop "Mojang" from comment wording per reviewer preference. - Restore inline jitpack annotation that documents conditional-mixin as the only artifact from that repo. - Shorten verbose block comments across fabric-* gradle files and 26.X mixins.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
handleServerBoundPacketandhandleClientBoundPacketto prevent pipeline corruptionfabric.mod.jsonversion range to<26for Fabric Loader 0.19.2 compatibilityTest plan