Phase 10: implement neoforge-26_1 leaf (WS, deltas, chat, link, reconciliation, player tracking)
Ports the full feature set proven by the two legacy leaves to modern, post-Flattening NeoForge (loader assumption confirmed: NeoForge 26.1.2.94 is real and published). Neoforge261ChunkAdapter reads BlockState via LevelChunk/LevelChunkSection instead of raw id+meta, carrying the full packed state id in DeltaEvent#blockStateId (a lossless int, unlike the pre-Flattening 16-bit encoding) while documenting a known truncation caveat for SectionData's char[]-based 3D backfill on very large modded registries. MCMapperMod uses constructor-injected event buses (IEventBus/ModContainer) and NeoForge.EVENT_BUS instead of @Mod.EventHandler methods, ModConfigSpec instead of legacy Configuration, and LinkCommand is a Brigadier registration (no CommandBase in this era) fired from RegisterCommandsEvent. Tracks its own loaded-chunk set via ChunkEvent.Load/Unload rather than querying chunk provider internals (no stable public API for that in modern MC). Gets its own standalone Gradle wrapper + settings.gradle (Foojay toolchain resolver) since ModDevGradle needs Gradle 8+ and a Java 25 toolchain (MC itself now requires Java 25), incompatible with the legacy leaves' Gradle-7/JDK-8 pin in one invocation. Verified against real NeoForge 26.1.2.94 + decompiled MC 26.1.2 source via ./gradlew build from inside neoforge-26_1/ (two real API mismatches caught and fixed by the compiler: ChunkPos is now a record — x()/z() methods, not fields — and ResourceLocation was renamed to Identifier, ResourceKey#identifier() not #location()).
This commit is contained in:
@@ -18,8 +18,12 @@ in Claude Code's plan mode.
|
||||
`common` interfaces as `forge-1_12_2`. Builds with legacy ForgeGradle 1.2, same fork family, one
|
||||
Forge-tooling generation further back — pre-block-state (raw `Block` + metadata int, no
|
||||
`IBlockState`) and pre-FML-repackage (`cpw.mods.fml.*`, not `net.minecraftforge.fml.*`).
|
||||
- `neoforge-26_1/` — MC 26.1.2 (NeoForge, assumed). Lowest MVP priority. Structurally scaffolded,
|
||||
not yet wired into the default build (see `settings.gradle`).
|
||||
- `neoforge-26_1/` — MC 26.1.2 (Phase 10; loader confirmed NeoForge). Lowest MVP priority, fully
|
||||
wired against the same `common` interfaces as the two legacy leaves. Post-Flattening, mixin-era
|
||||
API: block reads are `BlockState`, not raw id+meta; events/commands/config live under
|
||||
`net.neoforged.*` with constructor-injected event buses instead of `@Mod.EventHandler` methods
|
||||
and Brigadier commands instead of `CommandBase`. Builds standalone via ModDevGradle — see
|
||||
"Building" below, not part of the root multi-project build (see `settings.gradle`).
|
||||
|
||||
## Version targets and priority
|
||||
|
||||
@@ -40,12 +44,28 @@ Both legacy leaves share one root build, on Gradle 7.6 / JDK 8 (pinned via
|
||||
```
|
||||
|
||||
The first build downloads Minecraft/Forge artifacts and MCP mappings from Forge's Maven and can
|
||||
take a while / needs network access. `neoforge-26_1` is not yet buildable from the root — it
|
||||
needs Gradle 8+ and JDK 17+ (ModDevGradle), incompatible with the legacy leaves' toolchain
|
||||
within one Gradle invocation; see `settings.gradle`'s comment for the workaround until Phase 10
|
||||
gives it a proper isolated build.
|
||||
take a while / needs network access.
|
||||
|
||||
## Configuration (forge-1_12_2 and forge-1_7_10)
|
||||
`neoforge-26_1` is **not** part of the root build — it needs Gradle 8+ and a Java 25 toolchain
|
||||
(Minecraft itself now requires Java 25 as of the 26.x cycle), incompatible with the legacy
|
||||
leaves' Gradle-7/JDK-8 pin within one Gradle invocation. It has its own wrapper; build it from
|
||||
inside its own directory:
|
||||
|
||||
```
|
||||
cd neoforge-26_1
|
||||
./gradlew build
|
||||
```
|
||||
|
||||
The Gradle *daemon* can run on any modern JDK on `PATH`/`JAVA_HOME` (or pinned via
|
||||
`org.gradle.java.home` in a `$GRADLE_USER_HOME/gradle.properties`, same mechanism as the legacy
|
||||
leaves' JDK 8 pin — see `settings.gradle`'s comment) — it does not need to already be JDK 25
|
||||
itself. `settings.gradle` applies the Foojay toolchain resolver so Gradle auto-provisions an
|
||||
actual JDK 25 (into its own `GRADLE_USER_HOME` cache, not a system-wide install) for the
|
||||
compile/run tasks. The first build also downloads and decompiles/patches Minecraft itself via
|
||||
NeoForge's NeoForm pipeline (the modern equivalent of the legacy leaves' MCP step) — expect it to
|
||||
take several minutes and a real chunk of disk/network the first time; subsequent builds are fast.
|
||||
|
||||
## Configuration (all three leaves)
|
||||
|
||||
On first server start the leaf writes `config/mcmapper.cfg` with defaults. Set:
|
||||
|
||||
@@ -59,15 +79,22 @@ overworld chunks, and streams event-driven column deltas (block place/break) in
|
||||
`deltaFlushIntervalTicks` (default 20 = 1s). A periodic reconciliation sweep (Phase 7) also
|
||||
walks a bounded number of currently-loaded chunks per tick (`reconciliationChunksPerSweep`,
|
||||
default 4) and re-sends any that drifted from what the backend last acknowledged, to catch
|
||||
mutations event hooks miss (world-gen, other mods, `/fill`). Only the overworld is tracked —
|
||||
other dimensions and `neoforge-26_1` land in a later phase. The WS client and JSON encoding are
|
||||
hand-rolled (no third-party dependency) — see
|
||||
mutations event hooks miss (world-gen, other mods, `/fill`). Only the overworld is tracked. The
|
||||
WS client and JSON encoding are hand-rolled (no third-party dependency) — see
|
||||
`common/src/main/java/.../ws/SimpleWebSocketClient.java` and `.../json/MiniJson.java` for why.
|
||||
`forge-1_7_10` implements the identical config/flush/reconciliation/player-tracking behavior
|
||||
against 1.7.10's own API generation (see `Forge1710ChunkAdapter`'s javadoc for what differs) — it
|
||||
has no `MultiPlaceEvent` hook (that class doesn't reliably exist at this Forge version), so
|
||||
multi-block placements like doors/beds are only caught by the reconciliation sweep rather than
|
||||
immediately, unlike `forge-1_12_2`.
|
||||
|
||||
`forge-1_7_10` and `neoforge-26_1` implement the identical config/flush/reconciliation/
|
||||
player-tracking behavior against their own API generation (see `Forge1710ChunkAdapter`'s and
|
||||
`Neoforge261ChunkAdapter`'s javadocs for what differs). Neither has a `MultiPlaceEvent`-equivalent
|
||||
hook wired (1.7.10: that class doesn't reliably exist at this Forge version; 26.1.2: skipped for
|
||||
symmetry, no strong need identified), so multi-block placements like doors/beds are only caught
|
||||
by the reconciliation sweep rather than immediately, unlike `forge-1_12_2`. `neoforge-26_1` writes
|
||||
its config to `config/mcmapper-server.toml` (NeoForge's `ModConfigSpec`/TOML format, not the
|
||||
legacy leaves' `.cfg`), and — being post-Flattening — carries the full registry-wide packed
|
||||
`BlockState` id as `DeltaEvent#blockStateId` (an `int`, so this is lossless for the 2D column
|
||||
pipeline); 3D section backfill (`SectionData#blocks`, a `char[]` for wire-size reasons inherited
|
||||
from the pre-Flattening leaves) truncates to the low 16 bits, a known, documented collision risk
|
||||
for very large modded registries — see `Neoforge261ChunkAdapter`'s javadoc.
|
||||
|
||||
### Player position tracking (Phase 7b)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user