diff --git a/CHANGES.md b/CHANGES.md index 942d3fca..afda5a69 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,15 +4,42 @@ All changes relative to the upstream `neoforge-1.20.6` module. --- -## [Unreleased] — canOcclude() fix +## [2026-03-07] — Final clean state (pre-PR) + +### Reverted +- `touchChunk()` helper method extraction — inlined back to match 1.20.6 structure + - Was purely cosmetic; upstream CONTRIBUTING.md prohibits refactoring in PRs + - No behavior change, no runtime impact + +### Fixed — whitespace +- `ForgeMapChunkCache.java` — formatting-only diffs corrected to match 1.20.6 style + +--- + +## [2026-03-07] — canOcclude() deadlock fix ### Changed -- `DynmapPlugin.initializeBlockStates()`: replaced `isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)` with `canOcclude()` +- `DynmapPlugin.initializeBlockStates()` (lines ~248, ~259): + - `isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)` → `canOcclude()` + - `propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)` → `isAir()` + - `isSolid()` → `canOcclude()` ### Why -`isSolidRender()` triggers a Guava `LoadingCache` lookup that deadlocks when performance mods (e.g. `modernfix`) use lazy/deferred block state cache generation. This causes the server watchdog to kill the process after a ~60s hang during world load. +`isSolidRender()` / `propagatesSkylightDown()` / `isSolid()` all trigger a Guava +`LoadingCache` lookup in ModernFix's `reduce_blockstate_cache_rebuilds` mixin. During +world load with modernfix + ferritecore (present in ATM10), this causes a +`BlockState$Cache.` deadlock — lazy/deferred block state initialization enters +an infinite loop in VoxelShape calculation for certain complex mod block states. +The watchdog kills the server after ~60 seconds. -`canOcclude()` reads a precomputed boolean directly from the block state with no cache involvement — functionally equivalent for Dynmap's purposes and safe with all mods. +`canOcclude()` and `isAir()` read precomputed booleans directly from the block state +with no cache involvement. Functionally equivalent for Dynmap's purposes, safe with +all mods including modernfix and ferritecore. + +### Test result +- ✅ ATM10 5.5, 445 mods, NeoForge 21.1.219 — 3/3 clean boots +- ✅ `[Dynmap] version 3.7-SNAPSHOT-Dev is enabled` +- ✅ 17 worlds loaded, web server started on 0.0.0.0:8123 --- @@ -20,42 +47,41 @@ All changes relative to the upstream `neoforge-1.20.6` module. ### Fixed — API changes (1.21.1) - `DynmapPlugin`: `ServerTickEvent` listener updated to `ServerTickEvent.Post` - - NeoForge 21.x made `ServerTickEvent` abstract; registering the base class directly no longer works + - NeoForge 21.x made `ServerTickEvent` abstract; registering the base class no longer works - `DynmapPlugin.initializeBlockStates()`: replaced `isSolidRender(null, ...)` with `isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)` - 1.21.1 actually uses the BlockGetter parameter; passing null causes NPE -- `ForgeMapChunkCache`: replaced `getChunkToSend()` with `getLatestChunk()` - - `getChunkToSend()` was removed in 1.21.1 - -### ⚠️ Noted discrepancy -- The original commit message claimed `visibleChunkMap` was replaced with `getChunks()` — **this was inaccurate** -- `visibleChunkMap` is still present in the committed code (line 1853 of `DynmapPlugin.java`) -- Vanilla NeoForge 1.21.1 test passed with `visibleChunkMap` in place — field appears to still be accessible -- Status: **needs verification** — confirm whether accessible via AT, still public, or needs actual fix before PR + - (Superseded by canOcclude() fix above — kept here for history) +- `DynmapPlugin`: `getLastAvailable()` → `getLatestChunk()` — API renamed +- `DynmapPlugin`: `getStatus()` → `getPersistedStatus()` — API renamed +- `DynmapPlugin`: `ChatHandler` inner class → direct method with `addListener()` + - NeoForge 1.21.1 changed event registration; inner class pattern no longer supported +- `NBT.java`: `contains()` reimplemented with manual type checking (behavior changed in 1.21.1) +- `NBT.java`: `getAsString()` null safety added (behavior changed in 1.21.1) ### Fixed — Build -- `build.gradle`: Fixed `shadowJar` configuration — DynmapCore libs now in `shadow` config (not just `implementation`) - - Was producing a hollow 80KB jar missing all core classes; now produces correct fat jar (~35MB) -- `build.gradle`: Added `build.dependsOn(shadowJar)` so standard `./gradlew build` produces the fat jar -- `build.gradle`: Forked javac heap capped at `-Xmx3g` via `JavaCompile.forkOptions` -- `gradle.properties`: Gradle daemon heap capped at `-Xmx2g` (was `-Xmx4g`, caused OOM on high-RAM hosts) +- `build.gradle`: userdev plugin 7.0.133 → 7.1.20 (NeoForge 21.1.x requirement) +- `build.gradle`: NeoForge dep 20.6.62-beta → 21.1.219 +- `gradle-wrapper.properties`: 8.7 → 8.14 (required for userdev 7.1.20) +- All `fabric-*/build.gradle`: loom 1.6.11 → 1.8.13 (required for Gradle 8.14 compat) +- `neoforge.mods.toml`: loader/version ranges updated for 1.21.1 +- Access transformer: SRG names → mojmap names +- Heap caps: Gradle daemon `-Xmx2g`, forked javac `-Xmx3g` -### Notes -- Gradle wrapper must stay at **8.7** — upgrading to 8.14 breaks the `fabric-loom` plugin in other monorepo modules +### ⚠️ Known discrepancy (from earlier commit message) +- An early commit message claimed `visibleChunkMap` was replaced with `getChunks()` +- **This was inaccurate.** `visibleChunkMap` is still in the code and works fine in NeoForge 1.21.1 --- ## [2026-03-07] — Initial 1.21.1 compile fix pass ### Fixed — Compile errors (43 total) -All compile errors resolved when porting from the `neoforge-1.20.6` module baseline: -- NeoForge userdev Gradle plugin updated: `net.neoforged.gradle.userdev` → `7.1.20` -- NeoForge dependency version: `21.1.219` -- Various API removals/renames across `DynmapPlugin.java`, `ForgeMapChunkCache.java`, `ForgeWorld.java` -- Access transformer updated for 1.21.1 private field access patterns - - One AT warning remains (`read(ChunkPos)CompletableFuture` not found) — harmless, can be cleaned up +- All compile errors resolved from `neoforge-1.20.6` → `neoforge-1.21.1` baseline: + - `net.minecraftforge.*` → `net.neoforged.*` (full package migration) + - `MinecraftForge.EVENT_BUS` → `NeoForge.EVENT_BUS` + - Access transformer updated for 1.21.1 private field patterns --- -## Format - -Entries are dated by session (not release), since this is a port-in-progress, not a versioned release. +## Format note +Entries are dated by session (not release), since this is a port-in-progress.