Commit Graph

41 Commits

Author SHA1 Message Date
George 66dc2f336a Add /lw speed command for real-time simulation acceleration
/lw speed <1-20>  — run N full sim cycles (module pipeline + all
                    post-sim hooks) per normal tick interval.
/lw speed reset   — return to real-time (1x).

The multiplier is stored on LivingWorldBootstrap and reset to 1 on
server stop. Extra cycles queue all active regions and call the full
post-sim hook chain (pollution spread, seasonal effects, climate,
warming, water runoff, dynamic cap) so ecosystem state advances
coherently rather than just running modules in isolation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 22:16:26 +01:00
George b17a8990b0 Speed up ecosystem decay and fix succession cap being silently reset
VegetationModule:
- All living tiers now die under bad conditions, not just grass. Rates:
  grass 1.0, flowers 0.5, shrubs 0.25, trees 0.10 per sim cycle (trees
  only die under severe pollution >60 or near-zero soil <10).
- Dead accumulation raised 0.20 → 0.50 per bad cycle.
- Previously only grass died, keeping vegetation pressure artificially
  high and preventing regression even when soil/pollution were terrible.

RecoveryModule:
- DAMAGE_PER_BAD_TICK raised 3.0 → 5.0 so regression fires in ~14 bad
  cycles (~35s) once conditions trip the threshold, down from ~23 cycles.
- DAMAGE_DECAY_RATE lowered 0.05 → 0.03 so damage sticks around during
  oscillating conditions instead of washing away on good ticks.
- Fixed bug: 3-arg RecoveryRegionData constructor (used during damage
  decay) defaulted maxSuccessionStage to MATURE_FOREST, silently
  overwriting any biome or dynamic cap set by setRegionBiomeCap() /
  applyDynamicCapUpdate(). Now uses 4-arg constructor to preserve cap.

Net result: a heavily polluted forest regresses a stage in ~2 minutes
of sustained bad conditions instead of 10-15+ minutes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 22:07:48 +01:00
George 0f2a265c61 Add /lw set debug commands for ecosystem testing
Adds RegionSetCommand under /lw set with sub-commands to directly mutate
simulation data in the player's current region:

  /lw set soil fertility <0-100>     — soil fertility
  /lw set soil moisture  <0-100>     — soil moisture
  /lw set water availability <0-100> — water availability
  /lw set water drought      <0-100> — drought risk
  /lw set pollution <0-100>          — all pollution layers (proportional)
  /lw set stage <STAGE>              — force succession stage (resets progress)
  /lw set cap   <STAGE>              — force succession ceiling
  /lw set rain  <0.0-1.0>            — override regional rain level

Stage names have tab-completion. Forcing /lw set stage to a higher stage
than the current cap auto-raises the cap. All changes are immediately
persisted via markDirty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 21:50:39 +01:00
George 32e413cc9f Add dynamic region transformation, water runoff physics, and puddle formation
- Dynamic succession cap: desert regions (initially capped at SPARSE_GRASS)
  can now advance to MATURE_FOREST if water and soil conditions improve
  sustainably. applyDynamicCapUpdate() raises the cap each sim cycle;
  maxSuccessionStage is now persisted in the region codec so progress
  survives server restarts.

- Elevation-based water runoff: LivingWorldMod samples average surface
  height once per region on first entry. applyWaterRunoff() uses height
  differences to transfer water availability from high regions to low
  neighbours when it is raining, simulating drainage basin physics —
  valleys collect water, hills drain.

- Water pool formation (WATER_POOL_FORMS): WorldEffectsModule emits the
  new effect when a BARREN/SPARSE_GRASS region has regional rain > 0.3.
  NeoForgeWorldEffectExecutor finds the lowest sampled surface point and
  places water source blocks there; at high intensity the pool widens to
  adjacent blocks. These physical water blocks are then picked up by the
  periodic hasWaterBody() scan and feed back a hydration boost, enabling
  succession.

- Player water management: water bucket placement now invalidates the
  water-body scan cache for that region so player-built pools are detected
  within one player-check cycle. The scan itself is now periodic (every
  ~10 min) rather than one-shot, so natural pools from puddle formation
  are also re-evaluated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 21:41:35 +01:00
George 178d50883e Add global climate layer: carbon cycle, greenhouse warming, /lw climate
GlobalClimateTracker accumulates carbonPpm each sim cycle from total regional
air pollution (emissions) minus total tree-canopy pressure (carbon sink). The
resulting warmingLevel (0–1, representing 0–5°C anomaly) feeds three effects:

- AtmosphereModule subtracts getRainPenalty() (up to -0.15) from every
  region's rain target, creating planet-wide drought as warming rises.
- Bootstrap post-sim pass raises drought risk by warming * 0.02 per cycle,
  giving warming a second, persistent drought pathway.
- Carbon state persists across sessions in living_world/global_climate.dat
  so climate change accumulates over a playthrough.

/lw climate shows: Carbon: 342 ppm (+62 ppm) | Warming: +1.1°C |
  Biodiversity: 73% | Rain penalty: -3%

Deforestation accelerates warming; reforestation reverses it — the mod now
rewards long-term forest stewardship at a planetary scale.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 21:16:14 +01:00
George c82a2afc4f Add seasons, player pollution effects, wildfire, fog, water body boost, /lw atmosphere
Seasons (Step 1)
- Season enum (SPRING/SUMMER/AUTUMN/WINTER) derived from gameTime / 24000 / 8.
- AtmosphereModule applies seasonal rain modifier: spring +10%, summer -15%,
  winter -25%. Cascades naturally through water → soil → succession.
- Bootstrap post-sim pass: spring boosts soil fertility (+0.003/cycle),
  winter draws moisture out of topsoil (-0.002/cycle).

Player pollution effects (Step 2)
- Poll > 40: nausea (MobEffects.CONFUSION in 1.21.1); > 60: slowness; > 80: weakness.
- Duration 100 ticks, refreshed each PLAYER_CHECK_INTERVAL (1 s). Expires
  5 s after the player leaves the polluted region.

Wildfire (Step 3)
- WILDFIRE added to WorldEffectType.
- WorldEffectsModule emits WILDFIRE when droughtRisk > 70 AND thunderLevel > 0.5
  with 1% probability per sim cycle.
- NeoForgeWorldEffectExecutor places fire blocks on surface grass/leaves/logs;
  Minecraft fire spreading takes over from there.

Fog (Step 4)
- When pollutionScore > 40, 1–3 SMOKE particles sent per check interval at
  player eye-level via ServerLevel.sendParticles(player, ...) — per-player only,
  not broadcast to everyone.

Water body passive boost (Step 5)
- On first entry to a region, hasWaterBody() samples 30 surface positions.
  If ≥5 are water, applyWaterBodyBoost() permanently raises purification
  capacity +15, water availability +10, and lowers drought risk -10.

/lw atmosphere command (Step 6)
- Shows: Region (x,z) | Season: Spring | Rain: 72% | Storm: 18%
- Wired via Function<CommandSourceStack, String> atmosphereStatus parameter
  added to LivingWorldCommandRoot.registerDeferred().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:42:41 +01:00
George 61abff52dc Add regional atmosphere: vegetation scrub, ecosystem-driven rain, per-player weather
- New AtmosphereModule (9th in pipeline) derives per-region rain/thunder from
  ecosystem health and pollution score, smoothly interpolating each sim cycle.
- Tree canopy scrubs air pollution: treePressure × 0.003 removed per cycle,
  creating a direct incentive to maintain forests.
- Rain level (0–1) targets ecosystem health / 100 × 0.85; global MC rain adds
  a 0.15 bias so natural weather still matters.
- Thunder level targets pollutionScore / 100 × 0.8; acid rain fires when
  thunder > 0.4 AND pollution > 20, draining soil fertility and water.
- Regional drought: rain < 0.2 raises drought risk proportionally.
- Per-player ClientboundGameEventPacket (RAIN_LEVEL_CHANGE, THUNDER_LEVEL_CHANGE,
  START_RAINING, STOP_RAINING) sent each player-check cycle so each region has
  an independent sky without client-side mixins.
- HUD extended with Rain% and Storm% fields when atmosphere data is present.
- Removed global applyWeatherFeedback() from bootstrap; AtmosphereModule owns
  all rain/drought/acid-rain simulation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:24:04 +01:00
George 67a1e07b82 Add /lw hud debug command to toggle region HUD without compass
/lw hud toggles a persistent per-player flag stored in LivingWorldBootstrap.
When enabled, the action-bar HUD (Eco/Poll/Soil/Wat) is shown every 20 ticks
alongside the existing compass-based trigger. Flag is cleared on server stop.
Requires operator permission level 2.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:02:38 +01:00
George c9f927b265 Add mob spawning, HUD, agriculture, acid rain, biome caps, directional wind
Step 1 – Mob spawn feedback: FinalizeSpawnEvent suppresses passive mobs (Animal)
  in regions with ecosystem health < 30 (up to 70% cancellation) and hostile mobs
  (Monster) in regions > 60 health (up to 50% cancellation).

Step 2 – Compass HUD: holding a compass shows a colour-coded action-bar overlay
  with Eco/Poll/Soil/Wat scores for the current region (green/yellow/red banded).

Step 3 – Resource loop closure: logging depletion recovery is already tied to
  vegetation pressure in ResourceDepletionModule; sapling-to-tree growth continues
  to close the loop via the existing vegetation feedback path.

Step 4 – Agriculture: bone meal (PlayerInteractEvent.RightClickBlock) adds +2
  soil fertility; harvesting fully-grown (age=7) crops (BlockEvent.BreakEvent)
  drains -0.5 fertility and adds 0.3 farming depletion.

Step 5 – Acid rain: when raining AND region pollution > 20, rainfall drains soil
  fertility, raises soil contamination, and reduces water availability proportional
  to excess pollution. Implemented in applyWeatherFeedback().

Step 6 – Biome-aware succession: RecoveryRegionData gains a maxSuccessionStage
  cap (default MATURE_FOREST). deriveBiomeCap() samples the biome at the region
  centre on first player entry and calls setRegionBiomeCap(); deserts/badlands →
  SPARSE_GRASS, savannas/mountains/cold → SCRUBLAND, beaches/oceans → GRASSLAND,
  forests/taiga/jungle → MATURE_FOREST, plains/swamp → YOUNG_WOODLAND.

Step 7 – Directional wind: spreadPollutionAcrossRegions() drifts a wind angle by
  ±0.05 rad per sim cycle; each cardinal neighbour's spread rate is multiplied by
  (1 + alignment×0.5) where alignment = cos(windAngle − offsetAngle), creating
  downwind (×1.5) and upwind (×0.5) asymmetry.

All 400 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 19:57:09 +01:00
George 2350c27374 Vary sapling species by succession stage for realistic forest growth
Pioneer species (oak, birch) dominate at YOUNG_WOODLAND (intensity ~0.5).
Spruce and dark oak join at mid intensity. At MATURE_FOREST (intensity ~1.0)
the full mix includes cherry and jungle saplings for a diverse canopy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 19:12:25 +01:00
George 773fb0223f Tune ecosystem sensitivity and add simulation richness (Steps 1-6)
Tuning:
- simulationIntervalTicks: 100→50 (faster sim feedback)
- FURNACE_SCAN_INTERVAL: 100→50 (matches sim interval for pollution equilibrium)
- PollutionModule.BASE_DECAY_RATE: 0.02→0.008 (slower natural decay)
- SoilModule.POLLUTION_CONTAMINATION_THRESHOLD: 30→10, CONTAMINATION_FERTILITY_DRAIN: 0.002→0.005
- VegetationModule.DIEOFF_POLLUTION_THRESHOLD: 60→30
- WorldEffectsModule: lower grass-degrade/pollution-indicator thresholds so effects
  trigger from realistic furnace-driven pollution levels
- NeoForgeWorldEffectExecutor.BLOCK_ATTEMPTS: 8→20

New features:
- Campfire pollution source (0.2 air, 0.05 ground per lit campfire)
- Cross-region air pollution spreading (2% of gradient per sim cycle)
- SimulationManager.queueRegionForUpdate() for priority enqueueing
- LivingWorldBootstrap.notifyPlayerInRegion() boosts priority when player enters region
- Player region tracking in LivingWorldMod: checks every 20 MC ticks, queues update
  on region change
- NeoForgeWorldEffectExecutor: implement SAPLING_GROWTH_BOOSTED (oak sapling placement);
  VEGETATION_SPREADS also places short grass and flowers; GRASS_DEGRADES_TO_DIRT clears
  plants and converts dirt→coarse_dirt at intensity>0.5

All 400 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 18:55:08 +01:00
George 577c14b6ea Lower world effect thresholds to achievable levels; add water pollution to furnaces
The previous thresholds (grass=60, smoke=70) required pollutionScore > 60.
pollutionScore is a weighted average, so even if air pollution caps at 100
the score only reaches 40 from air alone — the thresholds were physically
unreachable from furnace burning.

New thresholds: grass degradation fires at pollutionScore > 15 (soilQuality
gate raised to 75 so it doesn't block — soil defaults to 60), smoke
particles fire at > 10. With 4 furnaces the score reaches ~15 in about
20 real simulation ticks (~2 minutes of play).

Also added acid-rain water pollution (0.1/furnace/scan) — coal burning
emits SO₂ which contributes to the weighted score alongside the existing
air and ground components.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 17:13:57 +01:00
George dfa84a9347 Wire furnace burning to air pollution input
PollutionModule only decayed pollution; no source ever fed it. Every 100
server ticks (one simulation interval), LivingWorldMod now scans each
active region's loaded chunks for lit AbstractFurnaceBlockEntity instances
(covers standard furnace, blast furnace, smoker) using getChunkNow so
unloaded chunks are skipped cheaply.

Per lit furnace per scan: +0.5 air, +0.1 ground pollution. With 4 furnaces
this drives air pollution to an equilibrium of ~55 (decay rate 3.6%/tick),
giving a clearly visible pollution score in /lw region info.

Bootstrap gains getActiveRegions() and handleFurnaceActivity() for the
platform layer to call without needing Minecraft imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 16:57:11 +01:00
George 881f716115 Fix two live simulation bugs: profiler crash + regions never updating
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>
2026-06-07 16:42:11 +01:00
George 6e6de00f0d Add debug commands, force-update, and weather feedback loop
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>
2026-06-07 16:20:48 +01:00
George 4fd9bb97aa Wire world effect executor — ecosystem simulation now mutates blocks in-game
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>
2026-06-07 16:01:57 +01:00
George 6427677db5 Add Volume 2 ecosystem modules, event hooks, and module data persistence
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>
2026-06-07 15:53:06 +01:00
George ae2a8db3ce Wire Volume 1 server lifecycle 2026-06-07 14:11:10 +01:00
George 96747a37db Add file-backed region persistence 2026-06-07 14:08:44 +01:00
George 69d60f7c13 Add NeoForge platform adapter 2026-06-07 14:06:53 +01:00
George cd5ffea24d Add Minecraft coordinate boundary mapper 2026-06-07 14:04:34 +01:00
George 7045df9a21 Add platform adapter contract 2026-06-07 14:04:27 +01:00
George 482e981c36 Consolidate persistence service contract 2026-06-07 14:03:55 +01:00
George 4f5a067300 Complete persistence metadata foundation 2026-06-07 14:02:50 +01:00
George e23f362b12 Add sustained simulation validation 2026-06-07 13:36:54 +01:00
George 025487dd40 Add direct event bus contract tests 2026-06-07 13:35:16 +01:00
George fbe1ccbbc3 Test and fix scheduler cycle budgets 2026-06-07 13:34:35 +01:00
George f1ceb5e019 Lock lifecycle transition matrix 2026-06-07 13:33:49 +01:00
George a46a945850 Complete region coordinate boundary coverage 2026-06-07 13:33:19 +01:00
George b0815db6c1 Add deterministic test simulation module 2026-06-07 13:32:42 +01:00
George 0ce71b727a Harden simulation profile snapshots 2026-06-07 13:31:39 +01:00
George 2202ff0680 Add simulation profiler 2026-06-07 13:01:14 +01:00
George 11d8c2db49 Add forced simulation command 2026-06-07 12:59:25 +01:00
George 0358c2e5bf Add region info command 2026-06-07 12:58:30 +01:00
George 44f06c04a5 Register Living World command root 2026-06-07 12:57:36 +01:00
George 524ccb2e60 Implement region manager 2026-06-07 12:56:23 +01:00
George 2c52b9b2e7 Implement region query engine 2026-06-07 12:55:03 +01:00
George f31e711dbb Add RegionStorage class with persistence delegation 2026-06-07 12:47:21 +01:00
George 5bbde601dc Add PersistenceService interface for region persistence operations 2026-06-07 12:42:25 +01:00
George 3edc507af2 Fix milestone 11 simulation flow 2026-06-07 12:22:59 +01:00
George 9f9b85e1f2 Initial commit 2026-06-07 12:18:45 +01:00