forceUpdateRegion crashed with "no profiling cycle is active" because
runModulesForRegion calls profiler.beginModule() which requires an active
cycle. Wrapped the call in startCycle/endCycle in a try/finally.
Regions showed tick=0 and no module data because SimulationScheduler's
priority queue was never populated for normal rolling updates — only
explicit queueRegion() calls worked. Fixed by auto-enqueueing all active
regions in onMinecraftServerTick() just before each simulation cycle fires.
Auto-enqueueing is placed there (not in runSimulationCycle()) so unit tests
that drive cycles directly are unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Track E — commands:
/lw region info — now shows all 7 module data classes (air/ground/water pollution,
soil fertility/moisture/contamination, succession stage, depletion levels, etc.)
/lw region info <x> <z> — inspect any region by block coordinates
/lw region force-update — runs full module pipeline on current region immediately
/lw stats — shows last cycle duration, per-module timings, budget overrun flag
Track F — weather feedback:
Each simulation tick, active overworld regions receive a moisture boost when it
rains (+0.3 waterAvailability, -0.15 droughtRisk) and a drought increase when
dry (+0.05 droughtRisk). The rain state is supplied by LivingWorldMod via a
BooleanSupplier set on ServerStartedEvent and cleared on stop.
400 tests, all passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NeoForgeWorldEffectExecutor translates WorldEffectRequests into actual Minecraft
block operations: GRASS_DEGRADES_TO_DIRT replaces grass with dirt, VEGETATION_SPREADS
spreads grass onto lit dirt, POLLUTION_VISUAL_INDICATOR spawns smoke particles.
SAPLING_GROWTH_SLOWED/BOOSTED are stubs pending mixin hooks.
Block writes are guarded by isLoaded() checks so no chunks are force-loaded.
Intensity scales the number of block candidates attempted per tick (max 8).
MinecraftServer is captured in LivingWorldMod on ServerStartedEvent and cleared
on stop; the executor receives it via Supplier to stay null-safe across restarts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Eight simulation modules (pollution, soil, water, vegetation, resource depletion,
recovery, ecosystem, world effects) form the full ecosystem pipeline. Each module
owns typed RegionData and writes summary metrics back to RegionMetrics.
Player block-break events are wired through BlockBreakInfo across the platform
boundary; the NeoForge adapter translates BreakEvent and routes it to the
bootstrap handler which records mining/logging/farming depletion on the
affected region.
Module state now survives server restarts: FileRegionPersistenceService accepts
per-module codecs (via PropertiesPersistenceWriter/Reader) that serialise every
RegionData instance alongside the region's core state. Bootstrap registers codecs
for all seven data-bearing modules at startup.
395 tests, all passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>