dynmap-neoforge/CHANGES.md

3.9 KiB

Changelog — Dynmap NeoForge 1.21.1 Port

All changes relative to the upstream neoforge-1.20.6 module.


[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() (lines ~248, ~259):
    • isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)canOcclude()
    • propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO)isAir()
    • isSolid()canOcclude()

Why

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.<init> 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() 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

[2026-03-07] — Runtime fixes + build improvements

Fixed — API changes (1.21.1)

  • DynmapPlugin: ServerTickEvent listener updated to ServerTickEvent.Post
    • 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
    • (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: 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

⚠️ 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 from neoforge-1.20.6neoforge-1.21.1 baseline:
    • net.minecraftforge.*net.neoforged.* (full package migration)
    • MinecraftForge.EVENT_BUSNeoForge.EVENT_BUS
    • Access transformer updated for 1.21.1 private field patterns

Format note

Entries are dated by session (not release), since this is a port-in-progress.