commit 9f9b85e1f2afe7fd7683d4b11dae577b9635c961
Author: George
Date: Sun Jun 7 12:18:45 2026 +0100
Initial commit
diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..97652dc
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gradle/9.5.1/checksums/checksums.lock b/.gradle/9.5.1/checksums/checksums.lock
new file mode 100644
index 0000000..6c1e89f
Binary files /dev/null and b/.gradle/9.5.1/checksums/checksums.lock differ
diff --git a/.gradle/9.5.1/checksums/md5-checksums.bin b/.gradle/9.5.1/checksums/md5-checksums.bin
new file mode 100644
index 0000000..72a6cdc
Binary files /dev/null and b/.gradle/9.5.1/checksums/md5-checksums.bin differ
diff --git a/.gradle/9.5.1/checksums/sha1-checksums.bin b/.gradle/9.5.1/checksums/sha1-checksums.bin
new file mode 100644
index 0000000..c242146
Binary files /dev/null and b/.gradle/9.5.1/checksums/sha1-checksums.bin differ
diff --git a/.gradle/9.5.1/executionHistory/executionHistory.bin b/.gradle/9.5.1/executionHistory/executionHistory.bin
new file mode 100644
index 0000000..af3dd4a
Binary files /dev/null and b/.gradle/9.5.1/executionHistory/executionHistory.bin differ
diff --git a/.gradle/9.5.1/executionHistory/executionHistory.lock b/.gradle/9.5.1/executionHistory/executionHistory.lock
new file mode 100644
index 0000000..0788ddb
Binary files /dev/null and b/.gradle/9.5.1/executionHistory/executionHistory.lock differ
diff --git a/.gradle/9.5.1/fileChanges/last-build.bin b/.gradle/9.5.1/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/.gradle/9.5.1/fileChanges/last-build.bin differ
diff --git a/.gradle/9.5.1/fileHashes/fileHashes.bin b/.gradle/9.5.1/fileHashes/fileHashes.bin
new file mode 100644
index 0000000..985fc6d
Binary files /dev/null and b/.gradle/9.5.1/fileHashes/fileHashes.bin differ
diff --git a/.gradle/9.5.1/fileHashes/fileHashes.lock b/.gradle/9.5.1/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..999c0af
Binary files /dev/null and b/.gradle/9.5.1/fileHashes/fileHashes.lock differ
diff --git a/.gradle/9.5.1/fileHashes/resourceHashesCache.bin b/.gradle/9.5.1/fileHashes/resourceHashesCache.bin
new file mode 100644
index 0000000..88b6bec
Binary files /dev/null and b/.gradle/9.5.1/fileHashes/resourceHashesCache.bin differ
diff --git a/.gradle/9.5.1/gc.properties b/.gradle/9.5.1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..8ec8afc
Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..69cad0a
--- /dev/null
+++ b/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Sat Jun 06 20:22:47 BST 2026
+gradle.version=9.5.1
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
new file mode 100644
index 0000000..51df46f
Binary files /dev/null and b/.gradle/buildOutputCleanup/outputFiles.bin differ
diff --git a/.gradle/file-system.probe b/.gradle/file-system.probe
new file mode 100644
index 0000000..fb01239
Binary files /dev/null and b/.gradle/file-system.probe differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/Docs/Living World Mod - Studio Development Plan.md b/Docs/Living World Mod - Studio Development Plan.md
new file mode 100644
index 0000000..4831325
--- /dev/null
+++ b/Docs/Living World Mod - Studio Development Plan.md
@@ -0,0 +1,4815 @@
+Living World Mod — Studio Development Plan
+Volume 1: Core Architecture & Simulation Engine
+
+Document status: Working draft
+Purpose: Build the real technical foundation for an Eco-style living Minecraft world mod.
+
+1\. What This Project Is
+
+This mod is not a normal content mod. It is a simulation layer that sits above Minecraft and gives the world memory, momentum, and consequences. The goal is to make the server feel alive even when players are not actively touching every part of it.
+
+Minecraft normally changes because a player loads an area, a random tick fires, an entity AI runs, or a vanilla system updates. This project adds a higher-level world simulation that tracks regions, ecology, settlements, factions, trade, roads, climate, resources, danger, and historical events.
+
+The first volume exists to define the engine layer. No ecology, settlements, factions, wars, roads, or economy systems should be built until this foundation is working.
+
+2\. Non-Negotiable Design Rules
+
+Rule 1: The world must continue without players nearby.
+
+The mod must not depend on loaded chunks for its main simulation. Loaded chunks are only used when the simulation needs to visibly apply changes to terrain, structures, roads, or entities. Most world evolution must happen in abstract region data.
+
+Rule 2: Simulate regions, not chunks.
+
+Chunks are too small and too numerous. The simulation uses regions as its main unit of world state. A region starts as 8 by 8 chunks, equal to 128 by 128 blocks. This size is large enough to reduce processing cost and small enough to let different parts of the world evolve differently.
+
+Rule 3: Everything must be modular.
+
+Ecology, settlements, factions, roads, economy, climate, wildlife, history, and events must be separate modules. A module can depend on the core API, services, region data, and events. A module must not directly depend on another gameplay module.
+
+Rule 4: Save data must be versioned from day one.
+
+Every saved object must include a schema version. No system is allowed to save unversioned data. Migrations must be part of the architecture before the first playable release.
+
+Rule 5: Debugging tools are not optional.
+
+A simulation this large is impossible to balance by guesswork. The mod must include commands to inspect regions, force ticks, simulate time, show history, dump save data, and profile module cost.
+
+3\. Target Mod Loader and Version Strategy
+
+Primary target: NeoForge or Forge for modern Minecraft.
+
+The project should avoid hard-coding version-specific logic into simulation classes. Minecraft-facing adapters should live in dedicated packages so the simulation core can survive porting between Minecraft versions.
+
+Recommended approach:
+
+\- Core simulation code should be plain Java where possible.
+\- Minecraft integration should be isolated.
+\- Save schemas should avoid depending directly on Minecraft runtime classes.
+\- BlockPos, ResourceLocation, Level, ServerLevel, and entity classes should be converted into internal data objects at the boundary.
+
+4\. High-Level Package Structure
+
+com.livingworld
+
+api
+Public interfaces and data contracts that other modules or addons may use.
+
+bootstrap
+Startup code. Owns system creation order. No gameplay module should self-bootstrap.
+
+config
+Configuration files and validation.
+
+core
+Engine-level systems such as lifecycle, service registry, simulation control, and global state.
+
+data
+Save data, serialization, migration, schema validation, and export tooling.
+
+events
+Living World event bus and event definitions.
+
+regions
+Region identity, region state, region manager, region cache, and region query logic.
+
+modules
+Gameplay simulation modules. Each module lives in its own subpackage.
+
+commands
+Server commands for inspection and control.
+
+debug
+Profiling, dumps, overlays, diagnostics, and test helpers.
+
+networking
+Packets and client synchronization.
+
+testing
+Game tests, simulation tests, mock services, and long-run validation tools.
+
+5\. Core Startup Sequence
+
+Startup order must be deterministic. The bootstrap system owns all major system creation.
+
+Startup flow:
+
+1\. Minecraft loads the mod entrypoint.
+2\. LivingWorldMod creates the bootstrap context.
+3\. Config files are loaded.
+4\. Config values are validated.
+5\. Core services are created.
+6\. The Living World event bus is created.
+7\. Data migrations are registered.
+8\. Saved data services are prepared.
+9\. Module registry is created.
+10\. Built-in modules are registered.
+11\. Commands are registered.
+12\. Networking packets are registered.
+13\. Server-start hooks wait for world access.
+14\. On server start, world save data is loaded.
+15\. Simulation manager starts ticking.
+
+The main mod entrypoint should not contain gameplay logic. Its job is to call bootstrap and register Minecraft-facing hooks.
+
+6\. Core Services
+
+The project uses a service layer so modules do not need to know how everything is implemented.
+
+Required services:
+
+SimulationService
+Owns simulation ticking, update queues, module update order, and performance budgets.
+
+RegionService
+Provides region lookup, region creation, coordinate conversion, region queries, and active region iteration.
+
+PersistenceService
+Owns save/load requests, dirty tracking, schema versioning, migration calls, and disk writes.
+
+EventService
+Owns Living World event publishing and subscription.
+
+ModuleService
+Owns module registry, lifecycle calls, module enable/disable state, and module dependency validation.
+
+TimeService
+Owns Living World calendar time, conversion between Minecraft ticks and simulation time, and time acceleration.
+
+DebugService
+Owns diagnostics, profiling, debug dumps, and command helper output.
+
+ConfigService
+Owns validated configuration access.
+
+HistoryService
+Owns historical record creation and lookup.
+
+7\. Service Access Rules
+
+Modules may request services through a controlled service locator or dependency injection during initialization.
+
+Allowed:
+
+\- EcologyModule receives RegionService, EventService, ConfigService, and DebugService.
+\- SettlementModule receives RegionService, EventService, TimeService, and HistoryService.
+
+Not allowed:
+
+\- EcologyModule directly creates SettlementModule.
+\- RoadModule directly reads private settlement internals.
+\- FactionModule writes directly to region save files.
+
+All cross-system communication must happen through services, public data contracts, or events.
+
+8\. Region Architecture
+
+A region is the main unit of simulation. It is not a chunk and it is not a biome. It is an abstract simulation cell covering multiple chunks.
+
+Default region size:
+
+\- Width: 8 chunks
+\- Depth: 8 chunks
+\- Block footprint: 128 by 128 blocks
+
+A region stores simulation state even when no chunk in that area is loaded.
+
+Region identity:
+
+RegionCoordinate
+\- regionX
+\- regionZ
+\- dimensionId
+
+Dimension must be included from the beginning. Even if v1 only simulates the Overworld, the architecture must not assume a single dimension forever.
+
+9\. RegionCoordinate Design
+
+Class name:
+RegionCoordinate
+
+Type:
+Immutable value object.
+
+Fields:
+\- String dimensionId
+\- int x
+\- int z
+
+Required methods:
+\- equals
+\- hashCode
+\- toString
+\- fromBlockPosition
+\- fromChunkPosition
+\- toMinimumChunkX
+\- toMinimumChunkZ
+\- toCenterBlockX
+\- toCenterBlockZ
+
+Rules:
+
+\- RegionCoordinate must be immutable.
+\- It must be safe as a HashMap key.
+\- It must never store a direct Level or ServerLevel reference.
+\- Dimension identity must be saved as a stable string or resource key value.
+
+10\. Region Object Design
+
+Class name:
+Region
+
+Purpose:
+Stores all simulation state for one region.
+
+Core fields:
+\- UUID id
+\- RegionCoordinate coordinate
+\- RegionLifecycleState lifecycleState
+\- long createdAtSimulationTick
+\- long lastUpdatedSimulationTick
+\- boolean dirty
+\- RegionFlags flags
+\- RegionMetrics metrics
+\- RegionModuleData moduleData
+
+RegionMetrics fields:
+\- double ecologyScore
+\- double pollutionScore
+\- double prosperityScore
+\- double dangerScore
+\- double stabilityScore
+\- double developmentScore
+\- double resourcePressureScore
+
+RegionModuleData:
+A container mapping module IDs to module-specific region data.
+
+Example:
+\- ecology \-\> EcologyRegionData
+\- climate \-\> ClimateRegionData
+\- settlements \-\> SettlementRegionData
+\- roads \-\> RoadRegionData
+
+The core Region class must not contain every future field directly. It should contain common metrics plus a structured module data map.
+
+11\. Region Lifecycle
+
+Every region exists in exactly one lifecycle state.
+
+States:
+
+UNLOADED
+Region is not currently in memory.
+
+LOADING
+Region data is being loaded or created.
+
+ACTIVE
+Region is available for simulation.
+
+DIRTY
+Region has changed and must be saved.
+
+SAVING
+Persistence service is writing region data.
+
+FAILED
+Region failed to load, save, or validate.
+
+UNLOADING
+Region is being removed from memory after save.
+
+Rules:
+
+\- A region cannot move from UNLOADED directly to DIRTY.
+\- A region cannot be saved unless it is DIRTY or explicitly force-saved.
+\- A failed region must not be simulated until recovery succeeds.
+\- Region transitions must be logged when debug mode is enabled.
+
+12\. RegionManager Responsibilities
+
+Class name:
+RegionManager
+
+Responsibilities:
+
+\- Convert block and chunk positions to region coordinates.
+\- Return active regions.
+\- Create missing regions.
+\- Load regions from persistence.
+\- Mark regions dirty.
+\- Queue regions for saving.
+\- Unload low-priority regions from memory.
+\- Provide region query APIs.
+\- Protect against duplicate region instances.
+
+Internal fields:
+
+\- Map\ activeRegions
+\- RegionFactory regionFactory
+\- RegionStorage regionStorage
+\- RegionCache regionCache
+\- RegionQueryEngine queryEngine
+\- RegionLifecycleController lifecycleController
+\- DebugService debugService
+
+Threading rule:
+For v1, RegionManager is main-thread owned. Async save preparation may be added later, but direct mutation of active region objects must happen on the server thread until a safe threading model exists.
+
+13\. RegionFactory
+
+Class name:
+RegionFactory
+
+Purpose:
+Creates new region objects with default values.
+
+Responsibilities:
+
+\- Assign UUIDs.
+\- Assign coordinate.
+\- Initialize lifecycle state.
+\- Initialize common metrics.
+\- Ask each enabled module to create default module data.
+\- Validate the finished region.
+
+Method:
+createNewRegion(RegionCoordinate coordinate)
+
+Creation rules:
+
+\- New regions start with lifecycle state ACTIVE.
+\- New regions are marked dirty immediately so they are saved.
+\- Module default data must be deterministic based on world seed and region coordinate where randomness is needed.
+
+14\. RegionStorage
+
+Class name:
+RegionStorage
+
+Purpose:
+Bridge between RegionManager and PersistenceService.
+
+Responsibilities:
+
+\- Load serialized region data.
+\- Save serialized region data.
+\- Validate schema version.
+\- Trigger migration if needed.
+\- Return load failures in a structured way.
+
+RegionStorage must not contain simulation logic.
+
+15\. RegionCache
+
+Class name:
+RegionCache
+
+Purpose:
+Reduce memory pressure while keeping important regions available.
+
+Cache policy v1:
+
+\- Always keep regions near online players.
+\- Always keep regions containing settlements.
+\- Always keep regions containing active events.
+\- Unload quiet regions after a configurable idle time.
+
+Cache metrics:
+
+\- active region count
+\- dirty region count
+\- failed region count
+\- memory estimate
+\- average load time
+\- average save time
+
+16\. Region Query Engine
+
+Class name:
+RegionQueryEngine
+
+Purpose:
+Provide safe ways to search regions.
+
+Required queries:
+
+\- getRegionAtBlockPos
+\- getRegionAtChunkPos
+\- getNeighbourRegions
+\- getRegionsInRadius
+\- getRegionsWithSettlement
+\- getRegionsAbovePollution
+\- getRegionsBelowEcology
+\- getRegionsByPriority
+\- getRegionsWithActiveEvent
+
+Rules:
+
+\- Queries must avoid loading chunks.
+\- Queries may load region data if explicitly requested.
+\- Expensive queries must have limits.
+\- Debug commands must use query APIs rather than scanning internal maps directly.
+
+17\. Simulation Scheduler
+
+Class name:
+SimulationScheduler
+
+Purpose:
+Controls when regions update and how much work happens per cycle.
+
+Minecraft runs at 20 ticks per second. The Living World simulation must not run heavy logic every tick.
+
+Default timing:
+
+\- Simulation interval: every 100 Minecraft ticks
+\- Equivalent: every 5 seconds
+\- Configurable: yes
+
+Scheduler fields:
+
+\- long minecraftTickCounter
+\- long simulationTickCounter
+\- int maxRegionsPerCycle
+\- int maxMillisecondsPerCycle
+\- Queue\ updateQueue
+\- SimulationProfiler profiler
+\- RegionPriorityCalculator priorityCalculator
+
+18\. Region Update Job
+
+Class name:
+RegionUpdateJob
+
+Fields:
+
+\- RegionCoordinate coordinate
+\- int priority
+\- long queuedAtSimulationTick
+\- Set\ requestedModules
+\- UpdateReason reason
+
+UpdateReason examples:
+
+\- NORMAL\_ROLLING\_UPDATE
+\- PLAYER\_NEARBY
+\- SETTLEMENT\_PRESENT
+\- ACTIVE\_EVENT
+\- FORCED\_DEBUG\_COMMAND
+\- SAVE\_MIGRATION\_REQUIRED
+
+19\. Simulation Budgeting
+
+The scheduler must prevent lag spikes.
+
+Budget rules:
+
+\- Never update all regions in one cycle unless explicitly forced by debug command.
+\- Stop processing when max region count is reached.
+\- Stop processing when time budget is reached.
+\- Continue remaining jobs next cycle.
+\- Log budget overruns.
+
+Default budget:
+
+\- Max regions per cycle: 50
+\- Max time per cycle: 25 milliseconds
+\- Emergency stop: 40 milliseconds
+
+If a module exceeds its budget repeatedly, the profiler flags it.
+
+20\. Region Priority
+
+Not all regions deserve equal update frequency.
+
+Priority sources:
+
+\- Player nearby: very high
+\- Active settlement: high
+\- Active event: high
+\- Road or trade route: medium
+\- High pollution: medium
+\- High danger: medium
+\- Empty wilderness: low
+
+Priority formula v1:
+
+priority \= base \+ playerBonus \+ settlementBonus \+ eventBonus \+ roadBonus \+ dangerBonus \+ pollutionBonus \- idlePenalty
+
+Priority must be deterministic and inspectable through debug commands.
+
+21\. Simulation Manager
+
+Class name:
+SimulationManager
+
+Purpose:
+Main coordinator for the simulation.
+
+Responsibilities:
+
+\- Receive server tick callbacks.
+\- Ask SimulationScheduler whether a simulation cycle should run.
+\- Ask RegionManager for update candidates.
+\- Ask ModuleRegistry for enabled modules.
+\- Run module updates in the correct order.
+\- Publish events generated by modules.
+\- Mark changed regions dirty.
+\- Ask PersistenceService to process save queue.
+\- Send profiler data to DebugService.
+
+The SimulationManager should be boring and predictable. It should coordinate, not contain gameplay rules.
+
+22\. Module Interface
+
+Interface name:
+SimulationModule
+
+Required methods:
+
+\- String getModuleId()
+\- ModuleMetadata getMetadata()
+\- void initialize(ModuleContext context)
+\- void onServerStarted(ServerContext context)
+\- void createDefaultRegionData(Region region)
+\- ModuleUpdateResult updateRegion(RegionUpdateContext context)
+\- void onLivingWorldEvent(LivingWorldEvent event)
+\- void saveModuleData(PersistenceWriter writer)
+\- void loadModuleData(PersistenceReader reader)
+\- void shutdown()
+
+Rules:
+
+\- Modules must report whether they changed a region.
+\- Modules must not save files directly.
+\- Modules must not load Minecraft chunks for abstract simulation.
+\- Modules must validate their config during initialize.
+
+23\. Module Metadata
+
+Class name:
+ModuleMetadata
+
+Fields:
+
+\- moduleId
+\- displayName
+\- version
+\- description
+\- requiredCoreVersion
+\- dependencies
+\- optionalDependencies
+\- defaultEnabled
+\- serverOnly
+\- experimental
+
+Purpose:
+The ModuleRegistry uses metadata to validate load order and reject incompatible modules.
+
+24\. Module Context
+
+Class name:
+ModuleContext
+
+Purpose:
+Dependency container passed to modules at initialization.
+
+Contains:
+
+\- ConfigService
+\- RegionService
+\- EventService
+\- TimeService
+\- PersistenceService
+\- DebugService
+\- HistoryService
+\- RandomService
+
+Modules receive only the services they are allowed to use.
+
+25\. Module Update Result
+
+Class name:
+ModuleUpdateResult
+
+Fields:
+
+\- boolean changedRegion
+\- List\ generatedEvents
+\- List\ historyRecords
+\- int estimatedCost
+\- List\ warnings
+
+Purpose:
+Prevents modules from mutating global systems directly during update. They return results, and SimulationManager applies them in a controlled way.
+
+26\. Module Update Order
+
+Default order:
+
+1\. Climate
+2\. Ecology
+3\. Wildlife
+4\. Resources
+5\. Settlements
+6\. Economy
+7\. Roads
+8\. Factions
+9\. Events
+10\. History
+
+Reasoning:
+
+Climate affects ecology. Ecology affects wildlife and resources. Resources affect settlements. Settlements affect economy and roads. Economy affects factions. Events and history record the outcome.
+
+27\. Event Architecture
+
+There are three event layers.
+
+Layer 1: Minecraft events
+Examples: block break, block place, entity death, player login, world tick.
+
+Layer 2: Living World simulation events
+Examples: forest expanded, pollution increased, settlement founded, trade route opened.
+
+Layer 3: Historical events
+Examples: town founded, famine began, war declared, city abandoned.
+
+Minecraft events should be translated into Living World events at the boundary. Modules should mainly listen to Living World events, not raw Minecraft events.
+
+28\. Living World Event Bus
+
+Class name:
+LivingWorldEventBus
+
+Responsibilities:
+
+\- Register listeners.
+\- Publish events.
+\- Queue events safely during simulation updates.
+\- Prevent recursive event storms.
+\- Log event counts for debugging.
+\- Allow modules to subscribe by event type.
+
+Rules:
+
+\- Events are immutable.
+\- Events include timestamp and source module ID.
+\- Events may be cancellable only when explicitly designed as cancellable.
+\- Historical events are created from selected simulation events, not every minor event.
+
+29\. Persistence Service
+
+Class name:
+PersistenceService
+
+Responsibilities:
+
+\- Own all save and load operations.
+\- Track dirty regions.
+\- Track dirty global module data.
+\- Validate save schemas.
+\- Run migrations.
+\- Write save files.
+\- Recover from partial save failures.
+\- Provide debug export commands.
+
+Persistence rule:
+Modules never call file write APIs directly.
+
+30\. Save File Layout
+
+Recommended layout:
+
+world/livingworld/
+
+core.json
+regions/
+region\_overworld\_0\_0.json
+region\_overworld\_0\_1.json
+settlements.json
+factions.json
+events.json
+history.json
+migrations.log
+profiling/
+latest\_profile.json
+
+Early development may use JSON for readability. Later versions may switch to compressed NBT or SQLite if performance requires it. The persistence layer must hide this decision from modules.
+
+31\. Save Schema Versioning
+
+Every save file includes:
+
+\- schemaVersion
+\- modVersion
+\- createdAt
+\- updatedAt
+\- data
+
+Example:
+
+{
+ "schemaVersion": 1,
+ "modVersion": "0.1.0",
+ "data": {}
+}
+
+No unversioned save file is valid.
+
+32\. Migration System
+
+Class name:
+MigrationManager
+
+Responsibilities:
+
+\- Detect save schema version.
+\- Find migration path.
+\- Apply migrations in order.
+\- Validate migrated data.
+\- Backup old data before migration.
+\- Record migration in migrations.log.
+
+Example migration:
+
+V1 stores ecology as one number.
+V2 splits ecology into forestDensity, soilHealth, waterQuality, and biodiversity.
+
+The migration converts the old value into new fields using deterministic defaults.
+
+33\. Time Service
+
+Class name:
+TimeService
+
+Purpose:
+The Living World needs its own calendar.
+
+Fields:
+
+\- long simulationTick
+\- int day
+\- int month
+\- int year
+\- double timeScale
+
+Default mapping:
+
+\- 1 Minecraft day equals 1 Living World month.
+\- 12 Minecraft days equals 1 Living World year.
+
+The mapping must be configurable.
+
+34\. Debug Commands
+
+Command root:
+/lw
+
+Required commands:
+
+/lw region info
+Shows region coordinate, lifecycle state, metrics, module data summary, dirty state, and priority.
+
+/lw region dump
+Exports full region data to a debug file.
+
+/lw simulate 100
+Runs 100 simulation ticks as fast as budget allows.
+
+/lw simulate 1000 unsafe
+Runs forced simulation without normal delay. Requires operator permission.
+
+/lw modules list
+Shows loaded modules, enabled state, version, and update cost.
+
+/lw profile start
+Starts profiler capture.
+
+/lw profile stop
+Stops profiler capture and writes report.
+
+/lw history recent
+Shows recent historical records.
+
+/lw event trigger
+Triggers a test Living World event.
+
+35\. Profiling Framework
+
+Class name:
+SimulationProfiler
+
+Tracks:
+
+\- total simulation cycle time
+\- per-module update time
+\- per-region update time
+\- event count
+\- dirty region count
+\- save queue size
+\- memory estimate
+\- budget overruns
+
+Profiler output should be readable by humans and exportable as JSON.
+
+36\. Testing Requirements for Volume 1
+
+Minimum tests before Volume 2 begins:
+
+Test 1: Region coordinate conversion
+Given block positions across positive and negative coordinates, region coordinates must be correct.
+
+Test 2: Region creation
+Requesting a missing region creates one with valid default data.
+
+Test 3: Region persistence
+A region changed, saved, unloaded, and reloaded must keep identical data.
+
+Test 4: Scheduler budget
+Given 5000 regions, scheduler only processes the configured number per cycle.
+
+Test 5: Module lifecycle
+A fake module receives initialize, update, save, load, and shutdown calls in correct order.
+
+Test 6: Event bus
+Publishing a test event reaches the correct listeners once.
+
+Test 7: Migration
+A v1 save migrates to v2 without data loss.
+
+Test 8: Long run
+The simulation runs 100,000 ticks without crash, memory leak, or corrupted save data.
+
+37\. Definition of Done for Volume 1
+
+Volume 1 is complete when the following exist in code:
+
+\- Bootstrap system
+\- Config loading
+\- Core service registry
+\- RegionCoordinate
+\- Region
+\- RegionManager
+\- RegionFactory
+\- RegionStorage
+\- RegionCache
+\- RegionQueryEngine
+\- SimulationScheduler
+\- SimulationManager
+\- ModuleRegistry
+\- SimulationModule interface
+\- LivingWorldEventBus
+\- PersistenceService
+\- MigrationManager
+\- TimeService
+\- Debug commands
+\- SimulationProfiler
+\- Test module
+\- Persistence tests
+\- Scheduler tests
+\- Event tests
+\- Long-run simulation test
+
+Only after these are passing should Volume 2 systems be implemented.
+
+38\. Implementation Rule for AI Agents
+
+AI agents must not skip foundation tasks.
+
+Every implementation task must include:
+
+\- Purpose
+\- File path
+\- Class name
+\- Inputs
+\- Outputs
+\- Dependencies
+\- Exact method signatures
+\- Expected tests
+\- Definition of done
+
+Vague tasks are banned.
+
+Bad task:
+Build region manager.
+
+Good task:
+Create src/main/java/com/livingworld/regions/RegionCoordinate.java as an immutable record with dimensionId, x, and z fields. Add fromBlockPosition and fromChunkPosition factory methods. Add unit tests for positive and negative coordinates. Done when all tests pass and RegionCoordinate can be used as a HashMap key.
+
+End of current Volume 1 draft section.
+
+Next section to add: exact file-by-file implementation backlog for the Volume 1 foundation.
+
+39\. Volume 1 File-by-File Implementation Backlog
+
+This section turns the architecture into buildable work. The tasks below are intentionally small, explicit, and ordered. A developer or AI coding agent should complete them in sequence unless a task explicitly says it can be done later.
+
+Backlog rules:
+
+\- Do not create gameplay modules yet.
+\- Do not implement ecology, settlements, roads, factions, or economy yet.
+\- Do not start with mobs, structures, or terrain changes.
+\- Build the engine first.
+\- Each task must compile before moving on.
+\- Each task must either add tests or explain why tests are not yet possible.
+\- Every class should have a single clear responsibility.
+
+40\. Milestone 1 — Project Skeleton
+
+Goal:
+Create the base mod project and folder structure.
+
+Definition of done:
+The mod launches in a development environment, logs a startup message, and has empty packages prepared for the core architecture.
+
+Task 1.1 — Create base mod package
+
+Purpose:
+Establish the root Java package.
+
+File path:
+src/main/java/com/livingworld/LivingWorldMod.java
+
+Class name:
+LivingWorldMod
+
+Dependencies:
+Forge or NeoForge mod loader entrypoint.
+
+Implementation notes:
+This class should contain only mod entrypoint wiring. It must not contain simulation logic. It should create or call a bootstrap class.
+
+Required behaviour:
+\- Defines public static final String MOD\_ID \= "livingworld".
+\- Logs that Living World is loading.
+\- Registers mod lifecycle listeners.
+\- Delegates setup to LivingWorldBootstrap.
+
+Definition of done:
+The mod loads without crashing and the log shows a clear startup message.
+
+Task 1.2 — Create bootstrap package
+
+Purpose:
+Create startup ownership boundary.
+
+File path:
+src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java
+
+Class name:
+LivingWorldBootstrap
+
+Required methods:
+\- void initialize()
+\- void onCommonSetup()
+\- void onServerStarting()
+\- void onServerStarted()
+\- void onServerStopping()
+
+Implementation notes:
+For now, methods can log their lifecycle stage. Later tasks will fill them with service creation and startup ordering.
+
+Definition of done:
+All lifecycle methods exist and can be called from the mod entrypoint.
+
+Task 1.3 — Create package placeholders
+
+Purpose:
+Create the long-term source tree.
+
+Packages to create:
+\- com.livingworld.api
+\- com.livingworld.bootstrap
+\- com.livingworld.config
+\- com.livingworld.core
+\- com.livingworld.core.lifecycle
+\- com.livingworld.core.registry
+\- com.livingworld.core.services
+\- com.livingworld.core.simulation
+\- com.livingworld.data
+\- com.livingworld.data.saved
+\- com.livingworld.data.migration
+\- com.livingworld.data.serialization
+\- com.livingworld.events
+\- com.livingworld.regions
+\- com.livingworld.regions.cache
+\- com.livingworld.regions.query
+\- com.livingworld.commands
+\- com.livingworld.debug
+\- com.livingworld.networking
+\- com.livingworld.testing
+\- com.livingworld.modules
+
+Definition of done:
+The packages exist and the project still compiles.
+
+Task 1.4 — Create build constants
+
+Purpose:
+Centralize mod constants.
+
+File path:
+src/main/java/com/livingworld/core/LivingWorldConstants.java
+
+Class name:
+LivingWorldConstants
+
+Fields:
+\- MOD\_ID
+\- MOD\_NAME
+\- CURRENT\_CORE\_SCHEMA\_VERSION
+\- DEFAULT\_REGION\_SIZE\_CHUNKS
+\- DEFAULT\_SIMULATION\_INTERVAL\_TICKS
+
+Initial values:
+\- MOD\_ID \= "livingworld"
+\- MOD\_NAME \= "Living World"
+\- CURRENT\_CORE\_SCHEMA\_VERSION \= 1
+\- DEFAULT\_REGION\_SIZE\_CHUNKS \= 8
+\- DEFAULT\_SIMULATION\_INTERVAL\_TICKS \= 100
+
+Definition of done:
+LivingWorldMod uses LivingWorldConstants.MOD\_ID instead of duplicating the string.
+
+41\. Milestone 2 — Logging and Diagnostics Foundation
+
+Goal:
+Create consistent logging before more systems exist.
+
+Definition of done:
+Every core system can log through one shared logging helper.
+
+Task 2.1 — Create logger wrapper
+
+File path:
+src/main/java/com/livingworld/debug/LivingWorldLogger.java
+
+Class name:
+LivingWorldLogger
+
+Purpose:
+Provide a central logging wrapper so logs are consistently formatted.
+
+Required methods:
+\- info(String message)
+\- warn(String message)
+\- error(String message)
+\- error(String message, Throwable throwable)
+\- debug(String message)
+
+Rules:
+\- Debug logs should respect a future debug config flag.
+\- Do not print directly to System.out.
+
+Definition of done:
+Bootstrap uses LivingWorldLogger for all startup logs.
+
+Task 2.2 — Create diagnostic category enum
+
+File path:
+src/main/java/com/livingworld/debug/DiagnosticCategory.java
+
+Enum values:
+\- BOOTSTRAP
+\- CONFIG
+\- REGIONS
+\- SIMULATION
+\- PERSISTENCE
+\- EVENTS
+\- MODULES
+\- COMMANDS
+\- NETWORKING
+\- TESTING
+
+Purpose:
+Allow future logs and profiler entries to be grouped.
+
+Definition of done:
+Logger can optionally accept a DiagnosticCategory.
+
+42\. Milestone 3 — Configuration Foundation
+
+Goal:
+Create config objects and validation before systems depend on hard-coded values.
+
+Task 3.1 — Create simulation config model
+
+File path:
+src/main/java/com/livingworld/config/SimulationConfig.java
+
+Class name:
+SimulationConfig
+
+Fields:
+\- int regionSizeChunks
+\- int simulationIntervalTicks
+\- int maxRegionsPerCycle
+\- int maxMillisecondsPerCycle
+\- int emergencyStopMilliseconds
+\- boolean enableDebugCommands
+\- boolean enableProfiler
+
+Default values:
+\- regionSizeChunks \= 8
+\- simulationIntervalTicks \= 100
+\- maxRegionsPerCycle \= 50
+\- maxMillisecondsPerCycle \= 25
+\- emergencyStopMilliseconds \= 40
+\- enableDebugCommands \= true
+\- enableProfiler \= true
+
+Required methods:
+\- validate()
+
+Validation rules:
+\- regionSizeChunks must be at least 1\.
+\- simulationIntervalTicks must be at least 1\.
+\- maxRegionsPerCycle must be at least 1\.
+\- maxMillisecondsPerCycle must be at least 1\.
+\- emergencyStopMilliseconds must be greater than or equal to maxMillisecondsPerCycle.
+
+Definition of done:
+Invalid values throw a clear validation exception.
+
+Task 3.2 — Create config service interface
+
+File path:
+src/main/java/com/livingworld/core/services/ConfigService.java
+
+Interface name:
+ConfigService
+
+Required methods:
+\- SimulationConfig getSimulationConfig()
+\- void reload()
+\- void validate()
+
+Definition of done:
+Interface compiles and is referenced by ModuleContext later.
+
+Task 3.3 — Create default config service implementation
+
+File path:
+src/main/java/com/livingworld/config/DefaultConfigService.java
+
+Class name:
+DefaultConfigService
+
+Implements:
+ConfigService
+
+Purpose:
+Provide config values before full Forge/NeoForge config wiring is completed.
+
+Definition of done:
+Bootstrap can create DefaultConfigService, validate it, and log the active simulation interval.
+
+43\. Milestone 4 — Core Service Registry
+
+Goal:
+Make service access controlled and predictable.
+
+Task 4.1 — Create ServiceKey
+
+File path:
+src/main/java/com/livingworld/core/services/ServiceKey.java
+
+Class name:
+ServiceKey
+
+Type:
+Generic immutable value object.
+
+Fields:
+\- String id
+\- Class\ serviceType
+
+Rules:
+\- Must be immutable.
+\- Must validate non-empty ID.
+\- Must validate serviceType is not null.
+
+Definition of done:
+Can be used as a key for registered services.
+
+Task 4.2 — Create ServiceRegistry
+
+File path:
+src/main/java/com/livingworld/core/services/ServiceRegistry.java
+
+Class name:
+ServiceRegistry
+
+Responsibilities:
+\- Register services.
+\- Reject duplicate service IDs.
+\- Retrieve services by key.
+\- Check if service exists.
+\- Lock registry after bootstrap.
+
+Required methods:
+\- \ void register(ServiceKey\ key, T service)
+\- \ T get(ServiceKey\ key)
+\- \ Optional\ find(ServiceKey\ key)
+\- boolean isRegistered(ServiceKey\\> key)
+\- void lock()
+\- boolean isLocked()
+
+Definition of done:
+Duplicate registration fails. Getting a missing service fails with a clear error.
+
+Task 4.3 — Create CoreServices keys
+
+File path:
+src/main/java/com/livingworld/core/services/CoreServices.java
+
+Class name:
+CoreServices
+
+Purpose:
+Central list of built-in service keys.
+
+Keys to define:
+\- CONFIG
+\- REGIONS
+\- SIMULATION
+\- PERSISTENCE
+\- EVENTS
+\- MODULES
+\- TIME
+\- DEBUG
+\- HISTORY
+
+Definition of done:
+ServiceRegistry can register and retrieve ConfigService using CoreServices.CONFIG.
+
+44\. Milestone 5 — Region Identity
+
+Goal:
+Implement coordinate conversion correctly before any region storage exists.
+
+Task 5.1 — Create RegionCoordinate
+
+File path:
+src/main/java/com/livingworld/regions/RegionCoordinate.java
+
+Class name:
+RegionCoordinate
+
+Recommended type:
+Java record.
+
+Fields:
+\- String dimensionId
+\- int x
+\- int z
+
+Required factory methods:
+\- static RegionCoordinate fromChunk(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+\- static RegionCoordinate fromBlock(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+
+Required instance methods:
+\- int minChunkX(int regionSizeChunks)
+\- int minChunkZ(int regionSizeChunks)
+\- int maxChunkX(int regionSizeChunks)
+\- int maxChunkZ(int regionSizeChunks)
+\- int centerBlockX(int regionSizeChunks)
+\- int centerBlockZ(int regionSizeChunks)
+\- String stableId()
+
+Important rule:
+Use floor division, not normal truncating division, so negative coordinates work correctly.
+
+Test cases:
+\- block 0,0 maps to region 0,0.
+\- block 127,127 maps to region 0,0 when region size is 8 chunks.
+\- block 128,0 maps to region 1,0.
+\- block \-1,0 maps to region \-1,0.
+\- block \-128,0 maps to region \-1,0.
+\- block \-129,0 maps to region \-2,0.
+
+Definition of done:
+All coordinate tests pass and RegionCoordinate is safe as a map key.
+
+Task 5.2 — Create RegionLifecycleState
+
+File path:
+src/main/java/com/livingworld/regions/RegionLifecycleState.java
+
+Enum values:
+\- UNLOADED
+\- LOADING
+\- ACTIVE
+\- DIRTY
+\- SAVING
+\- FAILED
+\- UNLOADING
+
+Definition of done:
+Enum exists and is used by Region in the next milestone.
+
+Task 5.3 — Create RegionFlags
+
+File path:
+src/main/java/com/livingworld/regions/RegionFlags.java
+
+Class name:
+RegionFlags
+
+Fields:
+\- boolean hasPlayerActivity
+\- boolean hasSettlement
+\- boolean hasRoad
+\- boolean hasActiveEvent
+\- boolean forceLoadedBySimulation
+\- boolean corrupted
+
+Required methods:
+\- copy()
+\- clearTransientFlags()
+
+Definition of done:
+Flags can be created, copied, and reset.
+
+45\. Milestone 6 — Region Core Data
+
+Goal:
+Create the in-memory region object and common metrics.
+
+Task 6.1 — Create RegionMetrics
+
+File path:
+src/main/java/com/livingworld/regions/RegionMetrics.java
+
+Class name:
+RegionMetrics
+
+Fields:
+\- double ecologyScore
+\- double pollutionScore
+\- double prosperityScore
+\- double dangerScore
+\- double stabilityScore
+\- double developmentScore
+\- double resourcePressureScore
+
+Rules:
+\- Values should generally be clamped between 0 and 100\.
+\- Clamping should happen through setter methods or normalize().
+
+Required methods:
+\- normalize()
+\- copy()
+\- static RegionMetrics defaults()
+
+Definition of done:
+Default metrics create a neutral region and normalize clamps out-of-range values.
+
+Task 6.2 — Create RegionModuleData
+
+File path:
+src/main/java/com/livingworld/regions/RegionModuleData.java
+
+Class name:
+RegionModuleData
+
+Purpose:
+Store module-specific data without bloating the core Region class.
+
+Fields:
+\- Map\ moduleData
+
+Required methods:
+\- put(String moduleId, Object data)
+\- \ Optional\ get(String moduleId, Class\ type)
+\- boolean contains(String moduleId)
+\- Set\ moduleIds()
+\- RegionModuleData copyShallow()
+
+V1 note:
+Using Object is acceptable for the first architecture pass. Later, replace with a typed serialization contract.
+
+Definition of done:
+Can store and retrieve typed module data safely.
+
+Task 6.3 — Create Region
+
+File path:
+src/main/java/com/livingworld/regions/Region.java
+
+Class name:
+Region
+
+Fields:
+\- UUID id
+\- RegionCoordinate coordinate
+\- RegionLifecycleState lifecycleState
+\- long createdAtSimulationTick
+\- long lastUpdatedSimulationTick
+\- boolean dirty
+\- RegionFlags flags
+\- RegionMetrics metrics
+\- RegionModuleData moduleData
+
+Required methods:
+\- markDirty()
+\- clearDirty()
+\- isDirty()
+\- updateLastSimulatedTick(long tick)
+\- setLifecycleState(RegionLifecycleState state)
+\- validate()
+
+Validation rules:
+\- id must not be null.
+\- coordinate must not be null.
+\- lifecycleState must not be null.
+\- metrics must not be null.
+\- moduleData must not be null.
+
+Definition of done:
+Region can be constructed, validated, marked dirty, and updated.
+
+46\. Milestone 7 — Region Creation and Lifecycle Control
+
+Goal:
+Create safe lifecycle transitions and deterministic region creation.
+
+Task 7.1 — Create RegionLifecycleController
+
+File path:
+src/main/java/com/livingworld/regions/RegionLifecycleController.java
+
+Class name:
+RegionLifecycleController
+
+Purpose:
+Validate state transitions.
+
+Required methods:
+\- boolean canTransition(RegionLifecycleState from, RegionLifecycleState to)
+\- void transition(Region region, RegionLifecycleState target)
+
+Allowed transitions:
+\- UNLOADED to LOADING
+\- LOADING to ACTIVE
+\- LOADING to FAILED
+\- ACTIVE to DIRTY
+\- DIRTY to SAVING
+\- SAVING to ACTIVE
+\- SAVING to FAILED
+\- ACTIVE to UNLOADING
+\- UNLOADING to UNLOADED
+\- FAILED to LOADING
+
+Definition of done:
+Invalid transitions throw clear exceptions.
+
+Task 7.2 — Create RegionFactory
+
+File path:
+src/main/java/com/livingworld/regions/RegionFactory.java
+
+Class name:
+RegionFactory
+
+Dependencies:
+\- ModuleRegistry later, but initial version can accept no modules.
+
+Required methods:
+\- Region createNewRegion(RegionCoordinate coordinate, long simulationTick)
+
+Rules:
+\- New region receives random UUID.
+\- New region starts ACTIVE.
+\- New region has default metrics.
+\- New region is dirty immediately.
+\- New region validates before return.
+
+Definition of done:
+Factory creates valid regions that pass Region.validate().
+
+47\. Milestone 8 — Module Contracts
+
+Goal:
+Define module contracts before modules exist.
+
+Task 8.1 — Create SimulationModule interface
+
+File path:
+src/main/java/com/livingworld/modules/SimulationModule.java
+
+Interface name:
+SimulationModule
+
+Required methods:
+\- String getModuleId()
+\- ModuleMetadata getMetadata()
+\- void initialize(ModuleContext context)
+\- void onServerStarted(ServerContext context)
+\- void createDefaultRegionData(Region region)
+\- ModuleUpdateResult updateRegion(RegionUpdateContext context)
+\- void onLivingWorldEvent(LivingWorldEvent event)
+\- void saveModuleData(PersistenceWriter writer)
+\- void loadModuleData(PersistenceReader reader)
+\- void shutdown()
+
+Temporary placeholders:
+If ServerContext, LivingWorldEvent, PersistenceWriter, or PersistenceReader do not exist yet, create minimal placeholder interfaces in the appropriate packages.
+
+Definition of done:
+The interface compiles and can be implemented by a fake test module.
+
+Task 8.2 — Create ModuleMetadata
+
+File path:
+src/main/java/com/livingworld/modules/ModuleMetadata.java
+
+Recommended type:
+Record or immutable class.
+
+Fields:
+\- String moduleId
+\- String displayName
+\- String version
+\- String description
+\- String requiredCoreVersion
+\- List\ dependencies
+\- List\ optionalDependencies
+\- boolean defaultEnabled
+\- boolean serverOnly
+\- boolean experimental
+
+Definition of done:
+ModuleMetadata validates moduleId and displayName are present.
+
+Task 8.3 — Create ModuleContext
+
+File path:
+src/main/java/com/livingworld/modules/ModuleContext.java
+
+Class name:
+ModuleContext
+
+Fields:
+\- ServiceRegistry services
+
+Required methods:
+\- \ T getService(ServiceKey\ key)
+
+Definition of done:
+A module can request ConfigService through ModuleContext.
+
+Task 8.4 — Create ModuleUpdateResult
+
+File path:
+src/main/java/com/livingworld/modules/ModuleUpdateResult.java
+
+Fields:
+\- boolean changedRegion
+\- List\ generatedEvents
+\- List\ historyRecords
+\- int estimatedCost
+\- List\ warnings
+
+Required static constructors:
+\- noChange()
+\- changed()
+
+Definition of done:
+A fake module can return noChange or changed results.
+
+Task 8.5 — Create ModuleRegistry
+
+File path:
+src/main/java/com/livingworld/modules/ModuleRegistry.java
+
+Responsibilities:
+\- Register modules.
+\- Reject duplicate module IDs.
+\- Resolve module order.
+\- Return enabled modules.
+\- Initialize modules.
+\- Shutdown modules.
+
+Required methods:
+\- void register(SimulationModule module)
+\- List\ getAllModules()
+\- List\ getEnabledModules()
+\- Optional\ find(String moduleId)
+\- void initializeAll(ModuleContext context)
+\- void shutdownAll()
+
+Definition of done:
+A fake module can be registered, initialized, found, and shut down.
+
+48\. Milestone 9 — Event Foundation
+
+Goal:
+Create the Living World event layer.
+
+Task 9.1 — Create LivingWorldEvent
+
+File path:
+src/main/java/com/livingworld/events/LivingWorldEvent.java
+
+Class name:
+LivingWorldEvent
+
+Recommended type:
+Interface.
+
+Required methods:
+\- String eventType()
+\- long simulationTick()
+\- String sourceModuleId()
+
+Definition of done:
+Test events can implement this interface.
+
+Task 9.2 — Create BaseLivingWorldEvent
+
+File path:
+src/main/java/com/livingworld/events/BaseLivingWorldEvent.java
+
+Class name:
+BaseLivingWorldEvent
+
+Fields:
+\- String eventType
+\- long simulationTick
+\- String sourceModuleId
+
+Definition of done:
+Can be used for simple test events.
+
+Task 9.3 — Create LivingWorldEventListener
+
+File path:
+src/main/java/com/livingworld/events/LivingWorldEventListener.java
+
+Interface method:
+\- void onEvent(LivingWorldEvent event)
+
+Definition of done:
+Listener interface compiles.
+
+Task 9.4 — Create LivingWorldEventBus
+
+File path:
+src/main/java/com/livingworld/events/LivingWorldEventBus.java
+
+Responsibilities:
+\- Register listener by event type.
+\- Publish event.
+\- Queue event during active dispatch.
+\- Prevent endless recursive dispatch.
+
+Required methods:
+\- void register(String eventType, LivingWorldEventListener listener)
+\- void publish(LivingWorldEvent event)
+\- int getPublishedEventCount()
+\- int getListenerCount(String eventType)
+
+Definition of done:
+A published event reaches its listener once.
+
+49\. Milestone 10 — Time Service
+
+Goal:
+Create internal simulation time independent from Minecraft time.
+
+Task 10.1 — Create LivingWorldCalendar
+
+File path:
+src/main/java/com/livingworld/core/simulation/LivingWorldCalendar.java
+
+Fields:
+\- long simulationTick
+\- int day
+\- int month
+\- int year
+
+Required methods:
+\- advanceTicks(long ticks)
+\- copy()
+\- toDisplayString()
+
+Definition of done:
+Advancing ticks updates the calendar in a predictable way.
+
+Task 10.2 — Create TimeService interface
+
+File path:
+src/main/java/com/livingworld/core/services/TimeService.java
+
+Methods:
+\- long getSimulationTick()
+\- LivingWorldCalendar getCalendar()
+\- void advanceSimulationTick()
+\- void advanceSimulationTicks(long ticks)
+
+Definition of done:
+Interface exists and is used by DefaultTimeService.
+
+Task 10.3 — Create DefaultTimeService
+
+File path:
+src/main/java/com/livingworld/core/simulation/DefaultTimeService.java
+
+Implements:
+TimeService
+
+Definition of done:
+Simulation tick can advance and calendar state can be read.
+
+50\. Milestone 11 — Simulation Scheduler and Manager
+
+Goal:
+Create the heartbeat of the simulation.
+
+Task 11.1 — Create UpdateReason
+
+File path:
+src/main/java/com/livingworld/core/simulation/UpdateReason.java
+
+Enum values:
+\- NORMAL\_ROLLING\_UPDATE
+\- PLAYER\_NEARBY
+\- SETTLEMENT\_PRESENT
+\- ACTIVE\_EVENT
+\- FORCED\_DEBUG\_COMMAND
+\- SAVE\_MIGRATION\_REQUIRED
+
+Definition of done:
+Enum compiles and is used by RegionUpdateJob.
+
+Task 11.2 — Create RegionUpdateJob
+
+File path:
+src/main/java/com/livingworld/core/simulation/RegionUpdateJob.java
+
+Fields:
+\- RegionCoordinate coordinate
+\- int priority
+\- long queuedAtSimulationTick
+\- Set\ requestedModules
+\- UpdateReason reason
+
+Definition of done:
+Jobs can be sorted by descending priority.
+
+Task 11.3 — Create RegionPriorityCalculator
+
+File path:
+src/main/java/com/livingworld/core/simulation/RegionPriorityCalculator.java
+
+Method:
+\- int calculatePriority(Region region)
+
+Initial scoring:
+\- base \= 5
+\- player activity bonus \= 100
+\- settlement bonus \= 75
+\- active event bonus \= 75
+\- road bonus \= 50
+\- danger bonus \= dangerScore / 2
+\- pollution bonus \= pollutionScore / 2
+
+Definition of done:
+Priority score is deterministic and testable.
+
+Task 11.4 — Create SimulationScheduler
+
+File path:
+src/main/java/com/livingworld/core/simulation/SimulationScheduler.java
+
+Responsibilities:
+\- Track Minecraft tick count.
+\- Decide when simulation should run.
+\- Maintain update queue.
+\- Respect max region budget.
+\- Respect time budget.
+
+Required methods:
+\- void onMinecraftTick()
+\- boolean shouldRunSimulationCycle()
+\- void queueRegion(RegionUpdateJob job)
+\- List\ pollJobsForCycle()
+
+Definition of done:
+Given 500 queued jobs and maxRegionsPerCycle of 50, one cycle returns 50 jobs.
+
+Task 11.5 — Create SimulationManager
+
+File path:
+src/main/java/com/livingworld/core/simulation/SimulationManager.java
+
+Responsibilities:
+\- Receive tick calls.
+\- Ask scheduler whether to run.
+\- Get update jobs.
+\- Resolve regions.
+\- Run enabled modules.
+\- Publish generated events.
+\- Mark changed regions dirty.
+
+Definition of done:
+A fake module can update a fake region through SimulationManager.
+
+51\. Milestone 12 — Persistence Foundation
+
+Goal:
+Build save/load abstraction before data becomes complicated.
+
+Task 12.1 — Create PersistenceWriter
+
+File path:
+src/main/java/com/livingworld/data/serialization/PersistenceWriter.java
+
+Purpose:
+Abstraction for writing save data.
+
+Initial methods:
+\- void writeString(String key, String value)
+\- void writeInt(String key, int value)
+\- void writeLong(String key, long value)
+\- void writeDouble(String key, double value)
+\- void writeBoolean(String key, boolean value)
+
+Definition of done:
+Interface compiles.
+
+Task 12.2 — Create PersistenceReader
+
+File path:
+src/main/java/com/livingworld/data/serialization/PersistenceReader.java
+
+Purpose:
+Abstraction for reading save data.
+
+Initial methods:
+\- String readString(String key, String defaultValue)
+\- int readInt(String key, int defaultValue)
+\- long readLong(String key, long defaultValue)
+\- double readDouble(String key, double defaultValue)
+\- boolean readBoolean(String key, boolean defaultValue)
+
+Definition of done:
+Interface compiles.
+
+Task 12.3 — Create SaveMetadata
+
+File path:
+src/main/java/com/livingworld/data/saved/SaveMetadata.java
+
+Fields:
+\- int schemaVersion
+\- String modVersion
+\- long createdAt
+\- long updatedAt
+
+Definition of done:
+Save metadata validates schemaVersion is greater than zero.
+
+Task 12.4 — Create PersistenceService interface
+
+File path:
+src/main/java/com/livingworld/core/services/PersistenceService.java
+
+Methods:
+\- void markRegionDirty(Region region)
+\- void saveDirtyRegions()
+\- Optional\ loadRegion(RegionCoordinate coordinate)
+\- void saveRegion(Region region)
+\- void flushAll()
+
+Definition of done:
+Interface compiles and RegionStorage can depend on it.
+
+52\. Milestone 13 — Region Storage and Manager
+
+Goal:
+Connect region creation, lookup, cache, and storage.
+
+Task 13.1 — Create RegionStorage
+
+File path:
+src/main/java/com/livingworld/regions/RegionStorage.java
+
+Dependencies:
+\- PersistenceService
+
+Methods:
+\- Optional\ load(RegionCoordinate coordinate)
+\- void save(Region region)
+
+Definition of done:
+Can delegate load/save to PersistenceService.
+
+Task 13.2 — Create RegionCache
+
+File path:
+src/main/java/com/livingworld/regions/cache/RegionCache.java
+
+Fields:
+\- Map\ activeRegions
+
+Methods:
+\- Optional\ get(RegionCoordinate coordinate)
+\- void put(Region region)
+\- void remove(RegionCoordinate coordinate)
+\- Collection\ allActive()
+\- int size()
+
+Definition of done:
+Can store and retrieve regions by coordinate.
+
+Task 13.3 — Create RegionQueryEngine
+
+File path:
+src/main/java/com/livingworld/regions/query/RegionQueryEngine.java
+
+Methods:
+\- Optional\ getRegion(RegionCoordinate coordinate)
+\- List\ getRegionsInRadius(RegionCoordinate center, int radius)
+\- List\ getRegionsWithActiveEvent()
+\- List\ getRegionsWithSettlement()
+
+Definition of done:
+Queries operate on RegionCache without touching chunks.
+
+Task 13.4 — Create RegionManager
+
+File path:
+src/main/java/com/livingworld/regions/RegionManager.java
+
+Dependencies:
+\- RegionFactory
+\- RegionStorage
+\- RegionCache
+\- RegionQueryEngine
+\- RegionLifecycleController
+\- SimulationConfig
+
+Methods:
+\- Region getOrCreateRegion(RegionCoordinate coordinate)
+\- Optional\ findRegion(RegionCoordinate coordinate)
+\- Region getOrCreateRegionAtBlock(String dimensionId, int blockX, int blockZ)
+\- Collection\ getActiveRegions()
+\- void markDirty(Region region)
+\- void unloadRegion(RegionCoordinate coordinate)
+
+Definition of done:
+Requesting a region first checks cache, then storage, then factory.
+
+53\. Milestone 14 — Debug Commands
+
+Goal:
+Expose inspection tools early.
+
+Task 14.1 — Create LivingWorldCommandRoot
+
+File path:
+src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java
+
+Purpose:
+Register /lw command tree.
+
+Initial subcommands:
+\- /lw status
+\- /lw region info
+\- /lw modules list
+\- /lw simulate \
+
+Definition of done:
+Commands register and return placeholder output if systems are not fully connected.
+
+Task 14.2 — Create RegionInfoCommand
+
+File path:
+src/main/java/com/livingworld/commands/RegionInfoCommand.java
+
+Output:
+\- Region coordinate
+\- Lifecycle state
+\- Dirty state
+\- Metrics
+\- Flags
+\- Module IDs present
+
+Definition of done:
+Standing in a world and running /lw region info prints region state.
+
+Task 14.3 — Create SimulateCommand
+
+File path:
+src/main/java/com/livingworld/commands/SimulateCommand.java
+
+Purpose:
+Force simulation ticks for testing.
+
+Rules:
+\- Operator-only.
+\- Maximum safe default: 1000 ticks.
+\- Unsafe mode can bypass limit later.
+
+Definition of done:
+Command advances TimeService and runs SimulationManager for requested ticks.
+
+54\. Milestone 15 — Profiling
+
+Goal:
+Measure simulation cost before real systems are added.
+
+Task 15.1 — Create SimulationProfiler
+
+File path:
+src/main/java/com/livingworld/debug/SimulationProfiler.java
+
+Tracks:
+\- cycle start time
+\- cycle end time
+\- per-module timings
+\- per-region timings
+\- event count
+\- save count
+\- budget overruns
+
+Methods:
+\- beginCycle()
+\- endCycle()
+\- beginModule(String moduleId)
+\- endModule(String moduleId)
+\- recordEvent()
+\- recordSave()
+\- createSnapshot()
+
+Definition of done:
+Profiler can produce a snapshot after a simulation cycle.
+
+Task 15.2 — Create SimulationProfileSnapshot
+
+File path:
+src/main/java/com/livingworld/debug/SimulationProfileSnapshot.java
+
+Fields:
+\- long totalCycleNanos
+\- Map\ moduleTimings
+\- int eventsPublished
+\- int regionsUpdated
+\- int savesPerformed
+\- boolean budgetExceeded
+
+Definition of done:
+Snapshot can be printed in debug command output.
+
+55\. Milestone 16 — Test Module and Long Run Test
+
+Goal:
+Prove the engine can run before real gameplay systems exist.
+
+Task 16.1 — Create TestSimulationModule
+
+File path:
+src/main/java/com/livingworld/testing/TestSimulationModule.java
+
+Purpose:
+Fake module used to verify lifecycle and update flow.
+
+Behaviour:
+\- On initialize, record initialized \= true.
+\- On updateRegion, increment a counter in test module data.
+\- Every 10 updates, return changedRegion \= true.
+
+Definition of done:
+SimulationManager can run this module against test regions.
+
+Task 16.2 — Create RegionCoordinateTest
+
+File path:
+src/test/java/com/livingworld/regions/RegionCoordinateTest.java
+
+Must test:
+\- Positive coordinate conversion.
+\- Negative coordinate conversion.
+\- Stable ID generation.
+\- HashMap key usage.
+
+Definition of done:
+All tests pass.
+
+Task 16.3 — Create RegionLifecycleControllerTest
+
+File path:
+src/test/java/com/livingworld/regions/RegionLifecycleControllerTest.java
+
+Must test:
+\- Allowed transitions succeed.
+\- Invalid transitions fail.
+\- Failed regions can return to loading.
+
+Definition of done:
+All tests pass.
+
+Task 16.4 — Create SchedulerBudgetTest
+
+File path:
+src/test/java/com/livingworld/core/simulation/SchedulerBudgetTest.java
+
+Must test:
+\- 500 jobs with limit 50 returns 50\.
+\- Higher priority jobs are returned first.
+\- Jobs not processed remain queued.
+
+Definition of done:
+All tests pass.
+
+Task 16.5 — Create EventBusTest
+
+File path:
+src/test/java/com/livingworld/events/EventBusTest.java
+
+Must test:
+\- Listener receives event.
+\- Listener receives event once.
+\- Multiple listeners receive event.
+\- Unknown event type does not crash.
+
+Definition of done:
+All tests pass.
+
+Task 16.6 — Create LongRunSimulationTest
+
+File path:
+src/test/java/com/livingworld/testing/LongRunSimulationTest.java
+
+Purpose:
+Prove the foundation does not collapse under time.
+
+Test setup:
+\- Create 1000 fake regions.
+\- Register TestSimulationModule.
+\- Run 100,000 simulation ticks.
+\- Save dirty regions periodically.
+
+Pass conditions:
+\- No crash.
+\- No unhandled exception.
+\- No invalid lifecycle transition.
+\- Dirty region count does not grow forever.
+\- Profiler reports cycle data.
+
+Definition of done:
+Long-run test completes reliably.
+
+56\. Milestone 17 — Volume 1 Completion Gate
+
+Volume 1 cannot be considered complete until all items below are true:
+
+\- The mod launches.
+\- Bootstrap sequence logs all stages.
+\- Config service loads and validates defaults.
+\- Service registry registers all core services.
+\- RegionCoordinate handles negative coordinates correctly.
+\- Region objects validate their internal state.
+\- RegionFactory creates valid dirty regions.
+\- RegionLifecycleController rejects invalid transitions.
+\- ModuleRegistry can register and initialize a test module.
+\- LivingWorldEventBus publishes events once.
+\- TimeService advances simulation time.
+\- SimulationScheduler respects region budget.
+\- SimulationManager runs at least one module over at least one region.
+\- RegionManager can get, create, cache, mark dirty, and unload regions.
+\- Debug commands exist.
+\- Profiler creates snapshots.
+\- Unit tests pass.
+\- Long-run simulation test passes.
+
+Only then should development move into Volume 2: Ecology, Climate, Wildlife, and Environmental Change.
+
+57\. Next Volume 1 Expansion
+
+The next expansion should add implementation-level pseudocode for the most important classes:
+
+\- RegionCoordinate
+\- Region
+\- RegionManager
+\- SimulationScheduler
+\- SimulationManager
+\- ModuleRegistry
+\- LivingWorldEventBus
+\- PersistenceService
+
+That section should include method bodies in pseudocode, expected edge cases, and exact failure handling.
+
+58\. Platform Decision Update — Minecraft Java 26.1
+
+Date added: 05 June 2026
+
+Decision:
+This project is a Minecraft Java Edition NeoForge-first mod. It is not a Bukkit, Spigot, or Paper plugin.
+
+Current verified target:
+The current verified documentation target is Minecraft Java Edition 26.1. The official Minecraft 26.1 release article was published on 24 March 2026 and describes the Tiny Takeover drop. NeoForge documentation is also currently available for version 26.1.
+
+Primary implementation target:
+Minecraft Java Edition 26.1 with NeoForge 26.1.
+
+Forward compatibility target:
+When the next Minecraft Java release becomes stable, the project should not immediately jump to it. First, verify that NeoForge or Forge support has stabilised, common dependencies have updated, and the mod can still pass its long-run simulation tests.
+
+Loader preference:
+1\. NeoForge first.
+2\. Forge-compatible architecture where practical.
+3\. Fabric is a possible future port after the core simulation engine is stable.
+4\. Bukkit, Spigot, and Paper are not valid primary targets for this project.
+
+Why this is a mod, not a Bukkit plugin:
+
+The Living World project needs deep world simulation, persistent custom world data, server tick integration, modular simulation systems, possible custom blocks, possible custom entities, custom networking, dedicated server testing, and long-term modded-server compatibility.
+
+A Bukkit, Spigot, or Paper plugin is better suited to server-side behaviour on mostly vanilla servers: commands, moderation tools, permissions, minigames, simple economy features, region protection, and server rule changes.
+
+This project is different. It is closer to an engine-level simulation mod. It needs access to mod-loader systems such as registries, events, data storage, networking, and client/server separation. Therefore, it belongs on NeoForge or Forge.
+
+Architecture rule:
+Core simulation code must remain as plain Java wherever possible. Minecraft-specific code must sit behind a platform adapter so future ports are possible.
+
+Required platform packages:
+
+com.livingworld.platform
+Common platform interfaces.
+
+com.livingworld.platform.neoforge
+NeoForge implementation.
+
+com.livingworld.platform.forge
+Optional future Forge compatibility layer.
+
+com.livingworld.integration.minecraft
+Boundary code that converts Minecraft classes into internal Living World data objects.
+
+Boundary conversion examples:
+
+\- BlockPos becomes an internal block coordinate object.
+\- ChunkPos becomes an internal chunk coordinate object.
+\- ResourceKey or dimension ID becomes a stable dimension string.
+\- ServerLevel is used only at the boundary, never stored inside core simulation objects.
+\- Entity references become stable IDs or event data, not long-lived direct object references.
+
+Version policy:
+
+\- Do not hard-code the architecture to one Minecraft minor version.
+\- Do not let gameplay modules depend directly on NeoForge classes.
+\- Keep mod-loader code in the platform layer.
+\- Keep region simulation, scheduler, persistence rules, and event logic in plain Java where possible.
+\- Before every Minecraft version upgrade, run all unit tests, migration tests, dedicated server tests, and long-run simulation tests.
+
+Volume 1 backlog addition — Platform Adapter Foundation
+
+Task P1 — Create PlatformAdapter interface
+
+File path:
+src/main/java/com/livingworld/platform/PlatformAdapter.java
+
+Purpose:
+Define the boundary between the Living World core engine and the active Minecraft mod loader.
+
+Required methods:
+\- String getPlatformName()
+\- String getMinecraftVersion()
+\- String getLoaderVersion()
+\- boolean isDedicatedServer()
+\- Path getWorldSaveDirectory()
+\- void registerCommands()
+\- void registerServerTickHook()
+\- void registerPlayerEventHooks()
+
+Definition of done:
+The core bootstrap can ask the platform adapter what loader and Minecraft version are active without directly importing NeoForge classes.
+
+Task P2 — Create NeoForgePlatformAdapter
+
+File path:
+src/main/java/com/livingworld/platform/neoforge/NeoForgePlatformAdapter.java
+
+Purpose:
+Implement PlatformAdapter using NeoForge APIs.
+
+Rules:
+\- This class may import NeoForge and Minecraft classes.
+\- Core simulation classes must not import NeoForge classes.
+\- The adapter should forward server tick events to SimulationManager.
+
+Definition of done:
+The mod logs active platform name, Minecraft version, and loader version during bootstrap.
+
+Task P3 — Create MinecraftCoordinateMapper
+
+File path:
+src/main/java/com/livingworld/integration/minecraft/MinecraftCoordinateMapper.java
+
+Purpose:
+Convert Minecraft positions into Living World coordinates.
+
+Required methods:
+\- RegionCoordinate fromBlockPos(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+\- RegionCoordinate fromChunkPos(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+
+Definition of done:
+Minecraft boundary code can convert positions without leaking Minecraft classes into region-core classes.
+
+Task P4 — Update project build policy
+
+File path:
+build.gradle or gradle.properties
+
+Purpose:
+Record the chosen Minecraft and NeoForge versions explicitly when implementation starts.
+
+Required values:
+\- minecraft\_version
+\- neoforge\_version
+\- mod\_id
+\- mod\_version
+\- java\_version
+
+Definition of done:
+The project build file clearly targets Minecraft Java 26.1 and NeoForge 26.1 unless a later verified stable target is chosen.
+
+Task P5 — Add version verification checklist
+
+File path:
+docs/version-verification-checklist.md
+
+Purpose:
+Prevent blind upgrading.
+
+Checklist:
+\- Confirm latest stable Minecraft Java release.
+\- Confirm matching NeoForge version exists.
+\- Confirm required Java version.
+\- Confirm mappings/toolchain changes.
+\- Confirm dedicated server launches.
+\- Confirm test mod loads.
+\- Confirm long-run simulation test passes.
+\- Confirm save files migrate correctly.
+
+Definition of done:
+Every Minecraft version bump must complete this checklist before becoming the main target.
+
+59\. Scope Correction — Ecosystem-Only Mod Direction
+
+Date added: 05 June 2026
+
+Decision:
+The Living World mod is now defined as an ecosystem-focused world evolution mod. It must not become an NPC civilisation simulator.
+
+This means the mod should focus on environmental systems, landscape change, resource pressure, pollution, soil health, water quality, biome pressure, vegetation spread, decay, recovery, erosion-style effects, and long-term ecological consequences.
+
+Removed from core scope:
+
+\- No custom NPC civilisation simulation.
+\- No autonomous villagers.
+\- No village growth system.
+\- No settlement AI.
+\- No faction diplomacy.
+\- No wars.
+\- No NPC economy.
+\- No wildlife population simulation as a primary system.
+\- No direct modification of vanilla villager behaviour.
+\- No requirement to alter passive mobs, hostile mobs, or animal spawning for the core mod.
+
+Allowed only as optional future addons:
+
+\- Compatibility hooks for existing village mods.
+\- Optional data export that other civilisation mods can read.
+\- Optional environmental effects that indirectly influence mob spawning if the server owner enables them.
+\- Optional addon modules for settlements or factions, kept outside the ecosystem core.
+
+New primary focus:
+
+1\. Region ecosystem state
+Each region stores ecosystem health values such as soil quality, moisture, vegetation density, water quality, pollution, decay, recovery pressure, temperature pressure, and resource depletion.
+
+2\. Vegetation and plant pressure
+The world can slowly gain or lose vegetation based on region conditions. This should include grass spread, sapling success chance, forest pressure, dead-zone formation, invasive overgrowth, and recovery after damage.
+
+3\. Soil system
+Soil should not be treated as permanent perfect dirt. Regions track soil fertility, compaction, contamination, moisture, and exhaustion. Farming, deforestation, overuse, fire, pollution, and lack of vegetation can reduce soil quality.
+
+4\. Water system
+Water quality is tracked at region level. Pollution near water, industrial blocks, mass farming, decay, and runoff can lower water quality. Clean neighbouring regions and rainfall-style recovery can improve it.
+
+5\. Pollution system
+Pollution is one of the main simulation drivers. It should spread slowly through neighbouring regions, decay over time, and create visible consequences when thresholds are crossed.
+
+6\. Decomposition and decay
+Organic material, fallen leaves, dead vegetation, and abandoned player impact should feed back into soil quality or disease/rot pressure. The world should feel like matter cycles through the environment.
+
+7\. Resource depletion
+Mining, quarrying, logging, farming, and repeated harvesting should reduce local resource scores. Regions should remember that they have been heavily exploited.
+
+8\. Recovery and succession
+Damaged areas should recover through ecological succession: barren ground becomes sparse grass, sparse grass becomes scrub, scrub becomes young woodland, and young woodland becomes mature forest where conditions allow.
+
+9\. Climate and seasonal pressure
+The core ecosystem may use seasonal modifiers and climate pressure, but this should remain environmental. It should not require animal or NPC simulation.
+
+10\. Visible world feedback
+The mod should eventually apply changes to loaded chunks, such as grass becoming coarse dirt, dirt becoming barren dirt, vegetation spreading, polluted water indicators, moss growth, dead vegetation, regrowth zones, and biome-edge transformation.
+
+Updated module list:
+
+Core required modules:
+
+\- Core Simulation
+\- Regions
+\- Persistence
+\- Event Bus
+\- Time System
+\- Debug Tools
+\- Ecosystem Metrics
+\- Soil System
+\- Water Quality System
+\- Pollution System
+\- Vegetation System
+\- Resource Depletion System
+\- Recovery/Succession System
+\- Visible World Effects System
+\- Configuration
+\- Profiling and Testing
+
+Removed or postponed modules:
+
+\- Settlements
+\- Factions
+\- NPC population
+\- Villager behaviour
+\- War system
+\- NPC economy
+\- Road generation
+\- Trade networks
+\- Wildlife simulation
+
+Architecture impact:
+
+The existing modular architecture remains valid, but the module package list must be simplified. The project should not spend time designing settlement AI, diplomacy, NPC jobs, village growth, or faction systems. Those are distractions from the actual goal.
+
+New recommended package structure:
+
+com.livingworld
+
+api
+bootstrap
+config
+core
+data
+events
+regions
+commands
+debug
+networking
+platform
+integration.minecraft
+modules.ecosystem
+modules.soil
+modules.water
+modules.pollution
+modules.vegetation
+modules.resources
+modules.recovery
+modules.worldeffects
+testing
+
+Updated Volume 1 rule:
+The foundation must support modules, but Volume 1 examples should stop assuming future settlement, faction, economy, or wildlife modules. Future examples should use ecosystem modules instead.
+
+Example module update order:
+
+1\. Climate pressure
+2\. Water quality
+3\. Soil quality
+4\. Pollution spread
+5\. Resource depletion
+6\. Vegetation pressure
+7\. Recovery and succession
+8\. Visible world effects
+9\. History/logging
+
+Updated first playable prototype:
+
+The first playable version should do this:
+
+\- Divide the world into regions.
+\- Track ecosystem health per region.
+\- Track pollution per region.
+\- Track soil quality per region.
+\- Track vegetation pressure per region.
+\- Save and load those values.
+\- Provide /lw region info.
+\- Allow /lw simulate ticks.
+\- Apply one visible effect in loaded chunks.
+
+First visible effect:
+If region pollution is high and soil quality is low, grass blocks in loaded chunks slowly degrade into dirt or coarse dirt.
+
+Second visible effect:
+If region vegetation pressure is high and soil quality is healthy, grass, moss, flowers, or saplings have a small chance to spread in loaded chunks.
+
+Third visible effect:
+If a region has been heavily logged, natural tree regrowth slows until soil and vegetation pressure recover.
+
+New project identity:
+This mod is not Minecraft Eco with villagers. It is Minecraft as a changing ecosystem. The player should feel that the land itself remembers damage, recovers slowly, spreads life where conditions are good, and degrades where conditions are abused.
+
+Design sentence:
+The Living World mod makes the environment evolve over time without adding civilisation simulation.
+
+60\. AI Prompt Pack — Local Model Workflow for Each Build Step
+
+Date added: 05 June 2026
+
+Purpose:
+This section gives copy-and-paste prompts for local AI development using Qwen3.5-9B as the main coding worker and Qwen3.6-27B as the planner, reviewer, debugger, and architecture guard.
+
+Model usage rule:
+
+\- Use Qwen3.5-9B for small, isolated implementation tasks.
+\- Use Qwen3.6-27B for architecture decisions, reviewing several files at once, diagnosing difficult errors, and checking that the code still follows the design.
+\- Do not ask Qwen3.5-9B to build broad systems.
+\- Do not waste Qwen3.6-27B on tiny one-class tasks unless Qwen3.5-9B fails twice.
+
+General 9B worker prompt template:
+
+Use this when asking Qwen3.5-9B to create or edit one file.
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+You are implementing one small Java task for a Minecraft NeoForge mod called Living World.
+
+Important project rules:
+\- Core simulation code must be plain Java wherever possible.
+\- Do not import Minecraft or NeoForge classes unless this specific task says to.
+\- Do not create extra systems beyond the task.
+\- Keep the code small and testable.
+\- Follow the package path exactly.
+\- Use clear names.
+\- Add validation where requested.
+\- If tests are requested, write the tests too.
+
+Task:
+\[PASTE TASK HERE\]
+
+Output required:
+1\. Brief explanation of what files you will create or edit.
+2\. Full code for each file.
+3\. Any test code required.
+4\. Notes about assumptions.
+
+Do not skip requirements.
+Do not add unrelated features.
+
+General 27B architect/reviewer prompt template:
+
+Use this when asking Qwen3.6-27B to review multiple files, fix design drift, or plan the next batch.
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+You are the senior architect reviewing the Living World Minecraft NeoForge mod.
+
+Project direction:
+This is an ecosystem-only world evolution mod. It does not simulate villagers, NPC civilisations, settlements, factions, wars, trade, roads, or wildlife AI.
+
+Architecture rules:
+\- Core simulation must remain plain Java where possible.
+\- Minecraft and NeoForge code must stay in platform or integration packages.
+\- Regions are the main simulation unit, not chunks.
+\- Modules must communicate through services, events, or public data contracts.
+\- Save data must be versioned.
+\- Debug and tests are mandatory.
+
+Review these files:
+\[PASTE FILES OR SUMMARIES\]
+
+Check for:
+1\. Incorrect Minecraft/NeoForge imports in core classes.
+2\. Scope creep into NPCs, factions, roads, or settlements.
+3\. Broken package boundaries.
+4\. Missing validation.
+5\. Bad lifecycle handling.
+6\. Save/versioning issues.
+7\. Test gaps.
+8\. Overly broad or fragile code.
+
+Output required:
+1\. Pass/fail summary.
+2\. Specific problems by file.
+3\. Exact fixes.
+4\. Revised code only where necessary.
+5\. Recommended next task.
+
+61\. Milestone 1 AI Prompts — Project Skeleton
+
+Task 1.1 prompt — Create base mod package
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/LivingWorldMod.java for a Minecraft NeoForge mod called Living World.
+
+Requirements:
+\- Package: com.livingworld
+\- Class name: LivingWorldMod
+\- Define public static final String MOD\_ID using LivingWorldConstants.MOD\_ID if that class already exists. If it does not exist yet, temporarily define MOD\_ID \= "livingworld" and add a TODO to replace it after constants are created.
+\- This class must contain only entrypoint wiring.
+\- It must not contain simulation logic.
+\- It must log a startup message.
+\- It must delegate startup work to com.livingworld.bootstrap.LivingWorldBootstrap if available.
+\- If NeoForge annotations/imports are needed, keep them only in this entrypoint file.
+
+Output:
+\- Full Java file.
+\- Any assumptions about the NeoForge version.
+\- Do not create unrelated classes.
+
+Task 1.2 prompt — Create bootstrap class
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java.
+
+Requirements:
+\- Package: com.livingworld.bootstrap
+\- Class name: LivingWorldBootstrap
+\- Methods:
+ \- void initialize()
+ \- void onCommonSetup()
+ \- void onServerStarting()
+ \- void onServerStarted()
+ \- void onServerStopping()
+\- Each method should log its lifecycle stage.
+\- Use LivingWorldLogger if available. If not available yet, use a minimal temporary logger comment and no System.out.
+\- Do not add gameplay logic.
+\- Do not create region, ecosystem, or persistence systems yet.
+
+Output:
+\- Full Java file.
+\- Short explanation of where it should be called from.
+
+Task 1.3 prompt — Create package placeholders
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create the package placeholder structure for the Living World mod.
+
+Packages:
+\- com.livingworld.api
+\- com.livingworld.bootstrap
+\- com.livingworld.config
+\- com.livingworld.core
+\- com.livingworld.core.lifecycle
+\- com.livingworld.core.registry
+\- com.livingworld.core.services
+\- com.livingworld.core.simulation
+\- com.livingworld.data
+\- com.livingworld.data.saved
+\- com.livingworld.data.migration
+\- com.livingworld.data.serialization
+\- com.livingworld.events
+\- com.livingworld.regions
+\- com.livingworld.regions.cache
+\- com.livingworld.regions.query
+\- com.livingworld.commands
+\- com.livingworld.debug
+\- com.livingworld.networking
+\- com.livingworld.platform
+\- com.livingworld.platform.neoforge
+\- com.livingworld.integration.minecraft
+\- com.livingworld.modules
+\- com.livingworld.modules.ecosystem
+\- com.livingworld.modules.soil
+\- com.livingworld.modules.water
+\- com.livingworld.modules.pollution
+\- com.livingworld.modules.vegetation
+\- com.livingworld.modules.resources
+\- com.livingworld.modules.recovery
+\- com.livingworld.modules.worldeffects
+\- com.livingworld.testing
+
+If Java requires at least one file per package in this project setup, create a package-info.java file with a one-line comment for each package.
+
+Do not add implementation logic.
+
+Task 1.4 prompt — Create constants
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/LivingWorldConstants.java.
+
+Requirements:
+\- Package: com.livingworld.core
+\- Final utility class.
+\- Private constructor.
+\- Constants:
+ \- public static final String MOD\_ID \= "livingworld";
+ \- public static final String MOD\_NAME \= "Living World";
+ \- public static final int CURRENT\_CORE\_SCHEMA\_VERSION \= 1;
+ \- public static final int DEFAULT\_REGION\_SIZE\_CHUNKS \= 8;
+ \- public static final int DEFAULT\_SIMULATION\_INTERVAL\_TICKS \= 100;
+\- Do not import Minecraft or NeoForge classes.
+\- Add short comments explaining each constant.
+
+Output:
+\- Full Java file.
+
+Milestone 1 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the completed Milestone 1 project skeleton for the Living World ecosystem mod.
+
+Files to review:
+\[PASTE LivingWorldMod.java, LivingWorldBootstrap.java, LivingWorldConstants.java, and package list\]
+
+Check:
+\- Entrypoint contains no simulation logic.
+\- Bootstrap owns startup flow.
+\- Constants are centralised.
+\- No ecosystem/NPC/settlement/faction systems were added early.
+\- Minecraft/NeoForge imports are restricted to entrypoint or platform boundary.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Next safe milestone.
+
+62\. Milestone 2 AI Prompts — Logging and Diagnostics
+
+Task 2.1 prompt — Create logger wrapper
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/LivingWorldLogger.java.
+
+Requirements:
+\- Package: com.livingworld.debug
+\- Class name: LivingWorldLogger
+\- Provide static methods:
+ \- info(String message)
+ \- warn(String message)
+ \- error(String message)
+ \- error(String message, Throwable throwable)
+ \- debug(String message)
+ \- info(DiagnosticCategory category, String message)
+ \- warn(DiagnosticCategory category, String message)
+ \- error(DiagnosticCategory category, String message)
+ \- debug(DiagnosticCategory category, String message)
+\- Use a standard logger appropriate for the mod environment if available.
+\- Do not use System.out.
+\- If debug config does not exist yet, allow debug messages for now and add a TODO to wire config later.
+\- Do not import ecosystem module classes.
+
+Output:
+\- Full Java file.
+
+Task 2.2 prompt — Create diagnostic category enum
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/DiagnosticCategory.java.
+
+Requirements:
+\- Package: com.livingworld.debug
+\- Enum values:
+ \- BOOTSTRAP
+ \- CONFIG
+ \- REGIONS
+ \- SIMULATION
+ \- PERSISTENCE
+ \- EVENTS
+ \- MODULES
+ \- COMMANDS
+ \- NETWORKING
+ \- PLATFORM
+ \- ECOSYSTEM
+ \- TESTING
+\- Add a method displayName() that returns a readable name.
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java enum.
+
+Milestone 2 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the logging and diagnostics foundation.
+
+Files:
+\[PASTE LivingWorldLogger.java and DiagnosticCategory.java\]
+
+Check:
+\- No System.out usage.
+\- Logger methods are consistent.
+\- Categories match the ecosystem-only architecture.
+\- No unnecessary Minecraft imports.
+\- Debug behaviour can later connect to config.
+
+Output:
+\- Problems found.
+\- Recommended fixes.
+\- Whether Milestone 3 can begin.
+
+63\. Milestone 3 AI Prompts — Configuration Foundation
+
+Task 3.1 prompt — Create SimulationConfig
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/config/SimulationConfig.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- int regionSizeChunks \= 8
+ \- int simulationIntervalTicks \= 100
+ \- int maxRegionsPerCycle \= 50
+ \- int maxMillisecondsPerCycle \= 25
+ \- int emergencyStopMilliseconds \= 40
+ \- boolean enableDebugCommands \= true
+ \- boolean enableProfiler \= true
+\- Add getters.
+\- Add setters only if needed for tests.
+\- Add validate() method.
+\- Validation rules:
+ \- regionSizeChunks \>= 1
+ \- simulationIntervalTicks \>= 1
+ \- maxRegionsPerCycle \>= 1
+ \- maxMillisecondsPerCycle \>= 1
+ \- emergencyStopMilliseconds \>= maxMillisecondsPerCycle
+\- Throw IllegalArgumentException with clear messages on invalid values.
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java file.
+\- Basic test suggestions.
+
+Task 3.2 prompt — Create ConfigService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ConfigService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- SimulationConfig getSimulationConfig()
+ \- void reload()
+ \- void validate()
+\- Import SimulationConfig from com.livingworld.config.
+\- Do not reference NeoForge config APIs here.
+
+Output:
+\- Full Java interface.
+
+Task 3.3 prompt — Create DefaultConfigService
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/config/DefaultConfigService.java.
+
+Requirements:
+\- Implements ConfigService.
+\- Holds a SimulationConfig instance.
+\- Constructor creates default SimulationConfig and validates it.
+\- getSimulationConfig returns the config.
+\- reload can be a safe placeholder for now, but it must revalidate.
+\- validate delegates to SimulationConfig.validate().
+\- Log validation success using LivingWorldLogger if available.
+\- Do not use NeoForge config classes yet.
+
+Output:
+\- Full Java file.
+
+Milestone 3 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the configuration foundation for the Living World ecosystem mod.
+
+Files:
+\[PASTE SimulationConfig.java, ConfigService.java, DefaultConfigService.java\]
+
+Check:
+\- Config is plain Java.
+\- Validation is strict and clear.
+\- No direct NeoForge dependency yet.
+\- Defaults match the design document.
+\- Future Forge/NeoForge config wiring can be added without rewriting core code.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Any missing config values for ecosystem-only MVP.
+
+64\. Milestone 4 AI Prompts — Core Service Registry
+
+Task 4.1 prompt — Create ServiceKey
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ServiceKey.java.
+
+Requirements:
+\- Generic immutable value object.
+\- Prefer Java record if project Java version supports it.
+\- Fields:
+ \- String id
+ \- Class\ serviceType
+\- Validate id is not null or blank.
+\- Validate serviceType is not null.
+\- Add stable toString().
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java file.
+
+Task 4.2 prompt — Create ServiceRegistry
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ServiceRegistry.java.
+
+Requirements:
+\- Plain Java class.
+\- Internally store services by ServiceKey.
+\- Methods:
+ \- \ void register(ServiceKey\ key, T service)
+ \- \ T get(ServiceKey\ key)
+ \- \ Optional\ find(ServiceKey\ key)
+ \- boolean isRegistered(ServiceKey\\> key)
+ \- void lock()
+ \- boolean isLocked()
+\- Reject duplicate registrations.
+\- Reject null keys and null services.
+\- If locked, reject new registrations.
+\- Missing get() should throw clear IllegalStateException.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested unit tests.
+
+Task 4.3 prompt — Create CoreServices
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/CoreServices.java.
+
+Requirements:
+\- Final utility class with private constructor.
+\- Define ServiceKey constants for:
+ \- CONFIG
+ \- REGIONS
+ \- SIMULATION
+ \- PERSISTENCE
+ \- EVENTS
+ \- MODULES
+ \- TIME
+ \- DEBUG
+ \- HISTORY
+\- If some service interfaces do not exist yet, add TODO comments and create keys only for existing interfaces, or use Object temporarily with clear TODOs.
+\- Do not create fake gameplay services.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Note any TODOs caused by missing interfaces.
+
+Milestone 4 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the core service registry.
+
+Files:
+\[PASTE ServiceKey.java, ServiceRegistry.java, CoreServices.java\]
+
+Check:
+\- Type safety is acceptable.
+\- Registry cannot be mutated after lock.
+\- Errors are clear.
+\- No hidden global state problems.
+\- No Minecraft imports.
+\- Design is suitable for module dependency injection later.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Risk notes.
+
+65\. Milestone 5 AI Prompts — Region Identity
+
+Task 5.1 prompt — Create RegionCoordinate
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionCoordinate.java.
+
+Requirements:
+\- Java record if available.
+\- Fields:
+ \- String dimensionId
+ \- int x
+ \- int z
+\- Validate dimensionId is not null or blank.
+\- Static methods:
+ \- fromChunk(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+ \- fromBlock(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+\- Instance methods:
+ \- int minChunkX(int regionSizeChunks)
+ \- int minChunkZ(int regionSizeChunks)
+ \- int maxChunkX(int regionSizeChunks)
+ \- int maxChunkZ(int regionSizeChunks)
+ \- int centerBlockX(int regionSizeChunks)
+ \- int centerBlockZ(int regionSizeChunks)
+ \- String stableId()
+\- Use Math.floorDiv so negative coordinates work correctly.
+\- Validate regionSizeChunks \>= 1\.
+\- Do not import Minecraft classes.
+
+Test requirements:
+Create RegionCoordinateTest if test framework exists.
+Test:
+\- block 0,0 maps to region 0,0
+\- block 127,127 maps to region 0,0 with region size 8 chunks
+\- block 128,0 maps to region 1,0
+\- block \-1,0 maps to region \-1,0
+\- block \-128,0 maps to region \-1,0
+\- block \-129,0 maps to region \-2,0
+\- stableId is stable
+\- works as HashMap key
+
+Output:
+\- Full Java file.
+\- Full test file if possible.
+
+Task 5.2 prompt — Create RegionLifecycleState
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionLifecycleState.java.
+
+Requirements:
+\- Enum values:
+ \- UNLOADED
+ \- LOADING
+ \- ACTIVE
+ \- DIRTY
+ \- SAVING
+ \- FAILED
+ \- UNLOADING
+\- Add comments explaining each state.
+\- Do not add methods unless useful.
+\- No Minecraft imports.
+
+Output:
+\- Full Java enum.
+
+Task 5.3 prompt — Create RegionFlags
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionFlags.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- boolean hasPlayerActivity
+ \- boolean hasHighPollution
+ \- boolean hasLowSoilQuality
+ \- boolean hasActiveEcosystemEvent
+ \- boolean forceLoadedBySimulation
+ \- boolean corrupted
+\- Do not include settlement, road, faction, or NPC flags.
+\- Add getters and setters.
+\- Add copy().
+\- Add clearTransientFlags(). This should clear hasPlayerActivity and hasActiveEcosystemEvent, but not corrupted.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 5 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review region identity classes.
+
+Files:
+\[PASTE RegionCoordinate.java, RegionLifecycleState.java, RegionFlags.java, and tests\]
+
+Check:
+\- Negative coordinate math is correct.
+\- No Minecraft classes leaked into region core.
+\- Flags match ecosystem-only scope.
+\- RegionCoordinate is safe as a HashMap key.
+\- Tests cover edge cases.
+
+Output:
+\- Pass/fail.
+\- Exact fixes if needed.
+
+66\. Milestone 6 AI Prompts — Region Core Data
+
+Task 6.1 prompt — Create RegionMetrics
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionMetrics.java.
+
+Requirements:
+\- Plain Java class.
+\- Ecosystem-only fields:
+ \- double ecosystemHealth
+ \- double pollutionScore
+ \- double soilQuality
+ \- double waterQuality
+ \- double vegetationPressure
+ \- double resourceDepletion
+ \- double recoveryPressure
+\- Values should normally be clamped between 0 and 100\.
+\- Add normalize().
+\- Add copy().
+\- Add static defaults().
+\- Defaults:
+ \- ecosystemHealth \= 60
+ \- pollutionScore \= 0
+ \- soilQuality \= 60
+ \- waterQuality \= 60
+ \- vegetationPressure \= 50
+ \- resourceDepletion \= 0
+ \- recoveryPressure \= 50
+\- Add applyDelta methods if simple and clean.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Task 6.2 prompt — Create RegionModuleData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionModuleData.java.
+
+Requirements:
+\- Stores module-specific data by module ID.
+\- Field:
+ \- Map\ moduleData
+\- Methods:
+ \- void put(String moduleId, Object data)
+ \- \ Optional\ get(String moduleId, Class\ type)
+ \- boolean contains(String moduleId)
+ \- Set\ moduleIds()
+ \- RegionModuleData copyShallow()
+\- Validate moduleId is not null or blank.
+\- Reject null data.
+\- If get type does not match, return Optional.empty instead of throwing.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 6.3 prompt — Create Region
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/Region.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- UUID id
+ \- RegionCoordinate coordinate
+ \- RegionLifecycleState lifecycleState
+ \- long createdAtSimulationTick
+ \- long lastUpdatedSimulationTick
+ \- boolean dirty
+ \- RegionFlags flags
+ \- RegionMetrics metrics
+ \- RegionModuleData moduleData
+\- Constructor validates required fields.
+\- Methods:
+ \- markDirty()
+ \- clearDirty()
+ \- isDirty()
+ \- updateLastSimulatedTick(long tick)
+ \- setLifecycleState(RegionLifecycleState state)
+ \- validate()
+\- validate() checks id, coordinate, lifecycleState, flags, metrics, and moduleData are not null.
+\- Do not include settlement, faction, road, or NPC fields.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 6 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the region core data classes.
+
+Files:
+\[PASTE RegionMetrics.java, RegionModuleData.java, Region.java\]
+
+Check:
+\- Metrics match ecosystem-only scope.
+\- Region is not bloated with future unrelated systems.
+\- Validation is strong.
+\- Dirty state behaviour is sensible.
+\- No Minecraft imports.
+\- No direct persistence logic inside Region.
+
+Output:
+\- Pass/fail.
+\- Exact corrections.
+
+67\. Milestone 7 AI Prompts — Region Creation and Lifecycle
+
+Task 7.1 prompt — Create RegionLifecycleController
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionLifecycleController.java.
+
+Requirements:
+\- Plain Java class.
+\- Methods:
+ \- boolean canTransition(RegionLifecycleState from, RegionLifecycleState to)
+ \- void transition(Region region, RegionLifecycleState target)
+\- Allowed transitions:
+ \- UNLOADED \-\> LOADING
+ \- LOADING \-\> ACTIVE
+ \- LOADING \-\> FAILED
+ \- ACTIVE \-\> DIRTY
+ \- DIRTY \-\> SAVING
+ \- SAVING \-\> ACTIVE
+ \- SAVING \-\> FAILED
+ \- ACTIVE \-\> UNLOADING
+ \- UNLOADING \-\> UNLOADED
+ \- FAILED \-\> LOADING
+\- Invalid transitions throw IllegalStateException with clear message.
+\- transition() must validate region is not null.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Task 7.2 prompt — Create RegionFactory
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionFactory.java.
+
+Requirements:
+\- Plain Java class.
+\- Method:
+ \- Region createNewRegion(RegionCoordinate coordinate, long simulationTick)
+\- New region rules:
+ \- random UUID
+ \- coordinate from argument
+ \- lifecycleState ACTIVE
+ \- createdAtSimulationTick \= simulationTick
+ \- lastUpdatedSimulationTick \= simulationTick
+ \- dirty \= true
+ \- default RegionFlags
+ \- RegionMetrics.defaults()
+ \- empty RegionModuleData
+ \- validate before return
+\- No Minecraft imports.
+\- Do not initialise ecology modules here yet; that comes after ModuleRegistry is connected.
+
+Output:
+\- Full Java file.
+
+Milestone 7 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review lifecycle and region creation.
+
+Files:
+\[PASTE RegionLifecycleController.java and RegionFactory.java\]
+
+Check:
+\- Invalid transitions are rejected.
+\- New regions are immediately dirty.
+\- Factory does not import Minecraft classes.
+\- Factory does not start implementing ecosystem gameplay prematurely.
+\- Tests cover valid and invalid transitions.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+68\. Milestone 8 AI Prompts — Module Contracts
+
+Task 8.1 prompt — Create SimulationModule interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/SimulationModule.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String getModuleId()
+ \- ModuleMetadata getMetadata()
+ \- void initialize(ModuleContext context)
+ \- void onServerStarted(ServerContext context)
+ \- void createDefaultRegionData(Region region)
+ \- ModuleUpdateResult updateRegion(RegionUpdateContext context)
+ \- void onLivingWorldEvent(LivingWorldEvent event)
+ \- void saveModuleData(PersistenceWriter writer)
+ \- void loadModuleData(PersistenceReader reader)
+ \- void shutdown()
+\- Create minimal placeholder interfaces/classes if missing:
+n \- ServerContext
+ \- RegionUpdateContext
+ \- LivingWorldEvent
+ \- PersistenceWriter
+ \- PersistenceReader
+\- Do not implement any real ecosystem module yet.
+\- No Minecraft imports in this interface.
+
+Output:
+\- Full Java interface.
+\- Any minimal placeholder files required.
+
+Task 8.2 prompt — Create ModuleMetadata
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleMetadata.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- String moduleId
+ \- String displayName
+ \- String version
+ \- String description
+ \- String requiredCoreVersion
+ \- List\ dependencies
+ \- List\ optionalDependencies
+ \- boolean defaultEnabled
+ \- boolean serverOnly
+ \- boolean experimental
+\- Validate moduleId and displayName are not blank.
+\- Replace null dependency lists with empty lists.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 8.3 prompt — Create ModuleContext
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleContext.java.
+
+Requirements:
+\- Plain Java class.
+\- Field:
+ \- ServiceRegistry services
+\- Constructor validates services is not null.
+\- Method:
+ \- \ T getService(ServiceKey\ key)
+\- Do not expose the whole registry for mutation if avoidable.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 8.4 prompt — Create ModuleUpdateResult
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleUpdateResult.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- boolean changedRegion
+ \- List\ generatedEvents
+ \- List\ historyRecords
+ \- int estimatedCost
+ \- List\ warnings
+\- Static constructors:
+ \- noChange()
+ \- changed()
+\- Null lists become empty lists.
+\- estimatedCost must not be negative.
+\- No Minecraft imports.
+
+If HistoryRecord does not exist, create a minimal placeholder in com.livingworld.modules or com.livingworld.events with TODO to move later.
+
+Output:
+\- Full Java file.
+\- Any placeholder file required.
+
+Task 8.5 prompt — Create ModuleRegistry
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleRegistry.java.
+
+Requirements:
+\- Plain Java class.
+\- Responsibilities:
+ \- register modules
+ \- reject duplicate module IDs
+ \- return all modules
+ \- return enabled modules
+ \- find by module ID
+ \- initialize all
+ \- shutdown all
+\- Methods:
+ \- void register(SimulationModule module)
+ \- List\ getAllModules()
+ \- List\ getEnabledModules()
+ \- Optional\ find(String moduleId)
+ \- void initializeAll(ModuleContext context)
+ \- void shutdownAll()
+\- For v1, enabled modules are modules where metadata.defaultEnabled is true.
+\- Do not implement dependency sorting yet; add TODO.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 8 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review module contract architecture.
+
+Files:
+\[PASTE SimulationModule.java, ModuleMetadata.java, ModuleContext.java, ModuleUpdateResult.java, ModuleRegistry.java\]
+
+Check:
+\- Modules are generic and not tied to settlements/factions/NPCs.
+\- Core module contracts do not import Minecraft classes.
+\- ModuleRegistry is simple enough for v1.
+\- Missing placeholders are sensible and marked as TODO.
+\- Architecture supports ecosystem modules later.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Next implementation task.
+
+69\. Milestone 9 AI Prompts — Event Foundation
+
+Task 9.1 prompt — Create LivingWorldEvent
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEvent.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String eventType()
+ \- long simulationTick()
+ \- String sourceModuleId()
+\- No Minecraft imports.
+\- Events must be usable by ecosystem modules later.
+
+Output:
+\- Full Java interface.
+
+Task 9.2 prompt — Create BaseLivingWorldEvent
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/BaseLivingWorldEvent.java.
+
+Requirements:
+\- Immutable class or record implementing LivingWorldEvent.
+\- Fields:
+ \- String eventType
+ \- long simulationTick
+ \- String sourceModuleId
+\- Validate eventType is not blank.
+\- Validate simulationTick is not negative.
+\- sourceModuleId may be "core" for core events but must not be blank.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 9.3 prompt — Create LivingWorldEventListener
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEventListener.java.
+
+Requirements:
+\- Functional interface.
+\- Method:
+ \- void onEvent(LivingWorldEvent event)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 9.4 prompt — Create LivingWorldEventBus
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEventBus.java.
+
+Requirements:
+\- Plain Java class.
+\- Methods:
+ \- void register(String eventType, LivingWorldEventListener listener)
+ \- void publish(LivingWorldEvent event)
+ \- int getPublishedEventCount()
+ \- int getListenerCount(String eventType)
+\- Validate eventType is not blank.
+\- Validate listener is not null.
+\- Event publishing should send the event to listeners registered for that event type.
+\- Unknown event type should not crash.
+\- Prevent obvious recursive event storms with a simple dispatching guard or TODO if not implemented.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Milestone 9 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the Living World event foundation.
+
+Files:
+\[PASTE LivingWorldEvent.java, BaseLivingWorldEvent.java, LivingWorldEventListener.java, LivingWorldEventBus.java\]
+
+Check:
+\- Events are plain Java.
+\- EventBus is not overcomplicated.
+\- Unknown events are safe.
+\- Recursion risk is noted or controlled.
+\- Event types can support pollution/soil/vegetation events later.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+70\. Milestone 10 AI Prompts — Time Service
+
+Task 10.1 prompt — Create LivingWorldCalendar
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/LivingWorldCalendar.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- long simulationTick
+ \- int day
+ \- int month
+ \- int year
+\- Default start: day 1, month 1, year 1, simulationTick 0\.
+\- Methods:
+ \- advanceTicks(long ticks)
+ \- copy()
+ \- toDisplayString()
+\- Keep the calendar simple for now.
+\- Use 30 days per month and 12 months per year unless config is added later.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 10.2 prompt — Create TimeService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/TimeService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- long getSimulationTick()
+ \- LivingWorldCalendar getCalendar()
+ \- void advanceSimulationTick()
+ \- void advanceSimulationTicks(long ticks)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 10.3 prompt — Create DefaultTimeService
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/DefaultTimeService.java.
+
+Requirements:
+\- Implements TimeService.
+\- Owns a LivingWorldCalendar.
+\- advanceSimulationTick advances by 1\.
+\- advanceSimulationTicks validates ticks \>= 0 and advances calendar.
+\- getCalendar returns a copy, not the internal mutable instance.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 10 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the Living World time system.
+
+Files:
+\[PASTE LivingWorldCalendar.java, TimeService.java, DefaultTimeService.java\]
+
+Check:
+\- Time is independent of Minecraft classes.
+\- Calendar cannot be mutated externally by accident.
+\- Behaviour is deterministic.
+\- Good enough for ecosystem simulation v1.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+71\. Milestone 11 AI Prompts — Scheduler and Simulation Manager
+
+Task 11.1 prompt — Create UpdateReason
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/UpdateReason.java.
+
+Requirements:
+\- Enum values:
+ \- NORMAL\_ROLLING\_UPDATE
+ \- PLAYER\_NEARBY
+ \- HIGH\_POLLUTION
+ \- LOW\_SOIL\_QUALITY
+ \- ACTIVE\_ECOSYSTEM\_EVENT
+ \- FORCED\_DEBUG\_COMMAND
+ \- SAVE\_MIGRATION\_REQUIRED
+\- Do not include settlement, road, faction, or NPC update reasons.
+\- No Minecraft imports.
+
+Output:
+\- Full Java enum.
+
+Task 11.2 prompt — Create RegionUpdateJob
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/RegionUpdateJob.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- RegionCoordinate coordinate
+ \- int priority
+ \- long queuedAtSimulationTick
+ \- Set\ requestedModules
+ \- UpdateReason reason
+\- Validate coordinate and reason are not null.
+\- priority must not be negative.
+\- queuedAtSimulationTick must not be negative.
+\- Null requestedModules becomes empty set.
+\- Add comparator for descending priority if clean.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 11.3 prompt — Create RegionPriorityCalculator
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/RegionPriorityCalculator.java.
+
+Requirements:
+\- Plain Java class.
+\- Method:
+ \- int calculatePriority(Region region)
+\- Initial ecosystem-only scoring:
+ \- base \= 5
+ \- hasPlayerActivity bonus \= 100
+ \- hasActiveEcosystemEvent bonus \= 75
+ \- hasHighPollution bonus \= 50
+ \- hasLowSoilQuality bonus \= 50
+ \- pollution bonus \= pollutionScore / 2
+ \- resource depletion bonus \= resourceDepletion / 3
+ \- recovery pressure bonus \= recoveryPressure / 4
+\- Validate region is not null.
+\- Result should be deterministic.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 11.4 prompt — Create SimulationScheduler
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/SimulationScheduler.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor accepts SimulationConfig.
+\- Fields:
+ \- long minecraftTickCounter
+ \- long simulationTickCounter
+ \- PriorityQueue\ updateQueue
+\- Methods:
+ \- void onMinecraftTick()
+ \- boolean shouldRunSimulationCycle()
+ \- void queueRegion(RegionUpdateJob job)
+ \- List\ pollJobsForCycle()
+ \- long getMinecraftTickCounter()
+ \- long getSimulationTickCounter()
+\- shouldRunSimulationCycle true when minecraftTickCounter reaches the configured interval.
+\- pollJobsForCycle returns at most maxRegionsPerCycle jobs.
+\- Higher priority jobs first.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested scheduler budget tests.
+
+Task 11.5 prompt — Create SimulationManager skeleton
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create the first version of src/main/java/com/livingworld/core/simulation/SimulationManager.java.
+
+This is an architecture-sensitive class. Keep it boring and coordinator-only.
+
+Requirements:
+\- Constructor dependencies:
+ \- SimulationScheduler scheduler
+ \- RegionManager regionManager
+ \- ModuleRegistry moduleRegistry
+ \- LivingWorldEventBus eventBus
+ \- TimeService timeService
+ \- PersistenceService persistenceService
+ \- SimulationProfiler profiler, if available. If not available, make it optional or TODO.
+\- Methods:
+ \- void onMinecraftServerTick()
+ \- void runSimulationCycle()
+ \- void runForcedSimulationTicks(int ticks)
+\- Responsibilities:
+ \- Advance scheduler on Minecraft tick.
+ \- If scheduler says cycle should run, run one cycle.
+ \- Poll region update jobs.
+ \- Resolve regions from RegionManager.
+ \- Run enabled modules in order.
+ \- Publish generated events.
+ \- Mark changed regions dirty.
+ \- Advance TimeService.
+\- Do not implement ecosystem rules here.
+\- Do not import Minecraft or NeoForge classes.
+\- Do not scan chunks.
+
+Output:
+\- Full Java file.
+\- Any missing interface TODOs.
+\- Explanation of control flow.
+
+Milestone 11 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review scheduler and SimulationManager.
+
+Files:
+\[PASTE UpdateReason.java, RegionUpdateJob.java, RegionPriorityCalculator.java, SimulationScheduler.java, SimulationManager.java\]
+
+Check:
+\- No Minecraft imports in scheduler/manager.
+\- Budgeting is respected.
+\- SimulationManager contains no gameplay rules.
+\- Ecosystem-only priority values are correct.
+\- Forced simulation cannot accidentally lock the server forever.
+\- Good enough before persistence and region manager are finished.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Next safest step.
+
+72\. Milestone 12 AI Prompts — Persistence Foundation
+
+Task 12.1 prompt — Create PersistenceWriter
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/serialization/PersistenceWriter.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- void writeString(String key, String value)
+ \- void writeInt(String key, int value)
+ \- void writeLong(String key, long value)
+ \- void writeDouble(String key, double value)
+ \- void writeBoolean(String key, boolean value)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 12.2 prompt — Create PersistenceReader
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/serialization/PersistenceReader.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String readString(String key, String defaultValue)
+ \- int readInt(String key, int defaultValue)
+ \- long readLong(String key, long defaultValue)
+ \- double readDouble(String key, double defaultValue)
+ \- boolean readBoolean(String key, boolean defaultValue)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 12.3 prompt — Create SaveMetadata
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/saved/SaveMetadata.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- int schemaVersion
+ \- String modVersion
+ \- long createdAt
+ \- long updatedAt
+\- Validate schemaVersion \> 0\.
+\- Validate modVersion is not blank.
+\- Validate updatedAt \>= createdAt.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 12.4 prompt — Create PersistenceService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/PersistenceService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- void markRegionDirty(Region region)
+ \- void saveDirtyRegions()
+ \- Optional\ loadRegion(RegionCoordinate coordinate)
+ \- void saveRegion(Region region)
+ \- void flushAll()
+\- No Minecraft imports.
+\- Do not implement file storage yet.
+
+Output:
+\- Full Java interface.
+
+Milestone 12 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review persistence foundation.
+
+Files:
+\[PASTE PersistenceWriter.java, PersistenceReader.java, SaveMetadata.java, PersistenceService.java\]
+
+Check:
+\- Persistence interfaces are plain Java.
+\- Region persistence is abstracted.
+\- Save metadata is versioned.
+\- No module writes files directly.
+\- Good enough before JSON/NBT implementation.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+73\. Milestone 13 AI Prompts — Region Storage and Manager
+
+Task 13.1 prompt — Create RegionStorage
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionStorage.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor dependency:
+ \- PersistenceService persistenceService
+\- Methods:
+ \- Optional\ load(RegionCoordinate coordinate)
+ \- void save(Region region)
+\- load delegates to persistenceService.loadRegion.
+\- save delegates to persistenceService.saveRegion.
+\- Validate dependencies and arguments.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.2 prompt — Create RegionCache
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/cache/RegionCache.java.
+
+Requirements:
+\- Plain Java class.
+\- Field:
+ \- Map\ activeRegions
+\- Methods:
+ \- Optional\ get(RegionCoordinate coordinate)
+ \- void put(Region region)
+ \- void remove(RegionCoordinate coordinate)
+ \- Collection\ allActive()
+ \- int size()
+\- Validate inputs.
+\- allActive should return an unmodifiable copy or safe view.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.3 prompt — Create RegionQueryEngine
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/query/RegionQueryEngine.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor dependency:
+ \- RegionCache cache
+\- Methods:
+ \- Optional\ getRegion(RegionCoordinate coordinate)
+ \- List\ getRegionsInRadius(RegionCoordinate center, int radius)
+ \- List\ getRegionsWithActiveEcosystemEvent()
+ \- List\ getRegionsAbovePollution(double threshold)
+ \- List\ getRegionsBelowSoilQuality(double threshold)
+\- Do not touch Minecraft chunks.
+\- Radius means region-coordinate radius.
+\- Validate radius \>= 0\.
+\- No settlement, road, faction, or NPC queries.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.4 prompt — Create RegionManager
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionManager.java.
+
+This is a core architecture class. Keep it clean and plain Java.
+
+Dependencies:
+\- RegionFactory regionFactory
+\- RegionStorage regionStorage
+\- RegionCache regionCache
+\- RegionQueryEngine queryEngine
+\- RegionLifecycleController lifecycleController
+\- SimulationConfig simulationConfig
+
+Methods:
+\- Region getOrCreateRegion(RegionCoordinate coordinate)
+\- Optional\ findRegion(RegionCoordinate coordinate)
+\- Region getOrCreateRegionAtBlock(String dimensionId, int blockX, int blockZ)
+\- Collection\ getActiveRegions()
+\- void markDirty(Region region)
+\- void unloadRegion(RegionCoordinate coordinate)
+
+Rules:
+\- getOrCreate first checks cache.
+\- If missing, try storage.
+\- If storage missing, use factory.
+\- New or modified regions must be marked dirty.
+\- Do not import Minecraft or NeoForge classes.
+\- Do not scan chunks.
+\- Do not apply visible world effects.
+
+Output:
+\- Full Java file.
+\- Explanation of load/create flow.
+\- Edge cases.
+
+Milestone 13 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review RegionStorage, RegionCache, RegionQueryEngine, and RegionManager.
+
+Files:
+\[PASTE FILES\]
+
+Check:
+\- RegionManager load/create flow is correct.
+\- No duplicate region instances are likely.
+\- No Minecraft imports.
+\- Queries are ecosystem-focused.
+\- Dirty handling is sensible.
+\- Region lifecycle transitions are not abused.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Tests to add.
+
+74\. Milestone 14 AI Prompts — Debug Commands
+
+Task 14.1 prompt — Create command root
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java for a NeoForge Minecraft mod.
+
+This file is allowed to use Minecraft/NeoForge command classes because it is in the commands boundary.
+
+Requirements:
+\- Register /lw command tree.
+\- Initial subcommands:
+ \- /lw status
+ \- /lw region info
+ \- /lw modules list
+ \- /lw simulate \
+\- If exact NeoForge command registration API is uncertain, create a clean skeleton with TODO comments at API-specific points.
+\- Command implementation should delegate to service classes where possible.
+\- Do not place ecosystem simulation rules inside command classes.
+
+Output:
+\- Full Java file.
+\- Notes about API assumptions.
+
+Task 14.2 prompt — Create RegionInfoCommand
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/RegionInfoCommand.java.
+
+This class may use Minecraft command/source classes if necessary, but region logic must stay in RegionManager.
+
+Output should include:
+\- Region coordinate
+\- Lifecycle state
+\- Dirty state
+\- Ecosystem metrics
+\- Flags
+\- Module IDs present
+
+Requirements:
+\- Use RegionManager to get region data.
+\- Use coordinate mapper or boundary conversion instead of putting Minecraft classes into RegionCoordinate.
+\- Do not reference settlements, factions, NPCs, roads, or economy.
+
+Output:
+\- Full Java file.
+\- API assumptions.
+
+Task 14.3 prompt — Create SimulateCommand
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/SimulateCommand.java.
+
+Requirements:
+\- Operator-only command.
+\- Accept tick count.
+\- Safe maximum default: 1000 ticks.
+\- Calls SimulationManager.runForcedSimulationTicks(ticks).
+\- Rejects negative or zero ticks.
+\- Prints clear success/failure output.
+\- Does not implement simulation rules itself.
+
+Output:
+\- Full Java file.
+\- Notes on NeoForge/Minecraft command API assumptions.
+
+Milestone 14 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review command implementation.
+
+Files:
+\[PASTE LivingWorldCommandRoot.java, RegionInfoCommand.java, SimulateCommand.java\]
+
+Check:
+\- Minecraft/NeoForge imports are limited to command boundary.
+\- Commands delegate to services.
+\- /lw simulate has safety limits.
+\- Output is useful for debugging ecosystem state.
+\- No gameplay logic hidden in commands.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+75\. Milestone 15 AI Prompts — Profiling
+
+Task 15.1 prompt — Create SimulationProfiler
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/SimulationProfiler.java.
+
+Requirements:
+\- Plain Java class.
+\- Tracks:
+ \- cycle start time
+ \- cycle end time
+ \- per-module timings
+ \- per-region timings if simple
+ \- event count
+ \- save count
+ \- budget overruns
+\- Methods:
+ \- beginCycle()
+ \- endCycle()
+ \- beginModule(String moduleId)
+ \- endModule(String moduleId)
+ \- recordEvent()
+ \- recordSave()
+ \- recordBudgetOverrun()
+ \- SimulationProfileSnapshot createSnapshot()
+\- Use System.nanoTime internally for timing.
+\- Do not use System.out.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 15.2 prompt — Create SimulationProfileSnapshot
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/SimulationProfileSnapshot.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- long totalCycleNanos
+ \- Map\ moduleTimings
+ \- int eventsPublished
+ \- int regionsUpdated
+ \- int savesPerformed
+ \- boolean budgetExceeded
+\- Add method toHumanReadableString().
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 15 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review simulation profiling classes.
+
+Files:
+\[PASTE SimulationProfiler.java and SimulationProfileSnapshot.java\]
+
+Check:
+\- Profiler can measure module cost.
+\- Snapshot is immutable or safely copied.
+\- No server-spam logging built in.
+\- Usable by debug commands later.
+\- No Minecraft imports.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+76\. Milestone 16 AI Prompts — Tests and Long-Run Validation
+
+Task 16.1 prompt — Create TestSimulationModule
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/testing/TestSimulationModule.java.
+
+Requirements:
+\- Implements SimulationModule.
+\- Module ID: test
+\- Metadata display name: Test Simulation Module
+\- On initialize, set initialized \= true.
+\- On updateRegion, increment an internal update counter.
+\- Every 10 updates, return ModuleUpdateResult.changed().
+\- Otherwise return ModuleUpdateResult.noChange().
+\- No Minecraft imports.
+\- This is for engine testing only, not gameplay.
+
+Output:
+\- Full Java file.
+
+Task 16.2 prompt — Create RegionCoordinateTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/regions/RegionCoordinateTest.java.
+
+Tests:
+\- block 0,0 maps to region 0,0
+\- block 127,127 maps to region 0,0 with region size 8 chunks
+\- block 128,0 maps to region 1,0
+\- block \-1,0 maps to region \-1,0
+\- block \-128,0 maps to region \-1,0
+\- block \-129,0 maps to region \-2,0
+\- stableId remains stable
+\- RegionCoordinate works as HashMap key
+
+Use the project’s test framework. If unknown, assume JUnit 5\.
+
+Output:
+\- Full test file.
+
+Task 16.3 prompt — Create RegionLifecycleControllerTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/regions/RegionLifecycleControllerTest.java.
+
+Tests:
+\- Allowed transitions succeed.
+\- Invalid transitions throw IllegalStateException.
+\- FAILED can transition to LOADING.
+\- ACTIVE cannot transition directly to SAVING.
+
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.4 prompt — Create SchedulerBudgetTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/core/simulation/SchedulerBudgetTest.java.
+
+Tests:
+\- Given 500 jobs and maxRegionsPerCycle 50, one cycle returns 50 jobs.
+\- Higher priority jobs are returned first.
+\- Jobs not processed remain queued.
+\- shouldRunSimulationCycle respects simulationIntervalTicks.
+
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.5 prompt — Create EventBusTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/events/EventBusTest.java.
+
+Tests:
+\- Listener receives event.
+\- Listener receives event once.
+\- Multiple listeners receive the event.
+\- Unknown event type does not crash.
+
+Use BaseLivingWorldEvent for test events.
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.6 prompt — Create LongRunSimulationTest
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/test/java/com/livingworld/testing/LongRunSimulationTest.java.
+
+Purpose:
+Prove the foundation can run for a long time without collapsing.
+
+Test setup:
+\- Create 1000 fake regions.
+\- Register TestSimulationModule.
+\- Run 100,000 simulation ticks or a reduced count if local test runtime is too high.
+\- Save dirty regions periodically using a fake/in-memory PersistenceService.
+
+Pass conditions:
+\- No crash.
+\- No unhandled exception.
+\- No invalid lifecycle transition.
+\- Dirty region count does not grow forever.
+\- Profiler reports cycle data.
+
+Requirements:
+\- Keep it plain Java where possible.
+\- Do not require a full Minecraft client.
+\- If full implementation requires missing services, create small in-memory fakes inside the test.
+
+Output:
+\- Full test file.
+\- Explanation of any fake services.
+
+Milestone 16 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the engine test suite.
+
+Files:
+\[PASTE all test files and TestSimulationModule.java\]
+
+Check:
+\- Tests cover foundation risks.
+\- Tests do not require Minecraft client unless absolutely necessary.
+\- Long-run test is realistic for local hardware.
+\- Tests catch coordinate, lifecycle, scheduler, event, and simulation failures.
+\- No NPC/settlement/faction/wildlife scope creep.
+
+Output:
+\- Pass/fail.
+\- Missing tests.
+\- Recommended final fixes before Volume 2\.
+
+77\. Platform Adapter AI Prompts
+
+Task P1 prompt — Create PlatformAdapter interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/platform/PlatformAdapter.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String getPlatformName()
+ \- String getMinecraftVersion()
+ \- String getLoaderVersion()
+ \- boolean isDedicatedServer()
+ \- Path getWorldSaveDirectory()
+ \- void registerCommands()
+ \- void registerServerTickHook()
+ \- void registerPlayerEventHooks()
+\- Import java.nio.file.Path only.
+\- No NeoForge imports here.
+
+Output:
+\- Full Java interface.
+
+Task P2 prompt — Create NeoForgePlatformAdapter skeleton
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/platform/neoforge/NeoForgePlatformAdapter.java.
+
+Purpose:
+Implement PlatformAdapter using NeoForge as the active loader.
+
+Rules:
+\- This class may import NeoForge and Minecraft classes.
+\- Core simulation classes must not import NeoForge or Minecraft classes.
+\- If exact NeoForge API names are uncertain for the target version, add clear TODOs at those points instead of inventing unsafe code.
+\- Must log platform name, Minecraft version, and loader version during bootstrap.
+\- Must provide hooks that can forward server ticks to SimulationManager later.
+
+Output:
+\- Full Java file or safe skeleton.
+\- API assumptions.
+\- TODOs requiring verification.
+
+Task P3 prompt — Create MinecraftCoordinateMapper
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/integration/minecraft/MinecraftCoordinateMapper.java.
+
+Requirements:
+\- Boundary class for converting Minecraft coordinates into Living World coordinates.
+\- For now, avoid importing Minecraft classes unless necessary.
+\- Methods:
+ \- RegionCoordinate fromBlockPos(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+ \- RegionCoordinate fromChunkPos(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+\- Delegate to RegionCoordinate.fromBlock and RegionCoordinate.fromChunk.
+\- No gameplay logic.
+
+Output:
+\- Full Java file.
+
+Platform review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the platform adapter layer.
+
+Files:
+\[PASTE PlatformAdapter.java, NeoForgePlatformAdapter.java, MinecraftCoordinateMapper.java\]
+
+Check:
+\- NeoForge imports are isolated to platform/neoforge or command boundary.
+\- Core simulation remains plain Java.
+\- Platform API is not too wide.
+\- Version reporting is possible.
+\- Server tick hook can eventually call SimulationManager.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Any NeoForge API calls that need checking against current docs.
+
+78\. Ecosystem MVP AI Prompts — To Use After Volume 1 Passes
+
+Do not use these until the Volume 1 completion gate passes.
+
+Ecosystem MVP prompt 1 — Create EcosystemRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ecosystem/EcosystemRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double ecosystemHealth
+ \- double stress
+ \- double resilience
+ \- double recoveryRate
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- applyStress(double amount)
+ \- applyRecovery(double amount)
+\- No Minecraft imports.
+\- No wildlife, NPC, village, faction, or economy logic.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 2 — Create SoilRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/soil/SoilRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double fertility
+ \- double moisture
+ \- double contamination
+ \- double compaction
+ \- double erosion
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- degrade(double amount)
+ \- recover(double amount)
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 3 — Create PollutionRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/pollution/PollutionRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double airPollution
+ \- double groundPollution
+ \- double waterPollution
+ \- double decayResistance
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- addPollution(double air, double ground, double water)
+ \- decay(double amount)
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 4 — Create VegetationRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/vegetation/VegetationRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double grassPressure
+ \- double flowerPressure
+ \- double shrubPressure
+ \- double treePressure
+ \- double deadVegetation
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- reduceFromLogging(double amount)
+ \- recover(double amount)
+\- No Minecraft imports.
+\- Do not simulate animal populations.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 5 — Create simple ecosystem update formulas
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Design the first simple ecosystem update formulas for the Living World mod.
+
+Scope:
+\- Ecosystem-only.
+\- No animals.
+\- No villagers.
+\- No settlements.
+\- No factions.
+
+Inputs per region:
+\- ecosystemHealth
+\- soil fertility
+\- soil moisture
+\- soil contamination
+\- water quality
+\- air/ground/water pollution
+\- vegetation pressure
+\- resource depletion
+\- recovery pressure
+
+Output required:
+1\. Simple formulas for one simulation tick.
+2\. Pseudocode for update order.
+3\. Edge cases.
+4\. Values that should be configurable.
+5\. Safety caps so values stay between 0 and 100\.
+6\. Explanation simple enough to turn into Java classes.
+
+Do not write Minecraft block-changing code yet.
+
+79\. Daily Local AI Working Method
+
+Use this method every coding session.
+
+Step 1:
+Use Qwen3.6-27B for planning the next 3 to 5 tiny tasks.
+
+Prompt:
+MODEL: Qwen3.6-27B
+
+Given the current Living World project state below, choose the next 3 to 5 safest tasks.
+
+Current state:
+\[PASTE WHAT EXISTS\]
+
+Rules:
+\- Ecosystem-only mod.
+\- No NPCs, factions, settlements, roads, or wildlife simulation.
+\- Core simulation remains plain Java.
+\- Minecraft/NeoForge imports stay in platform, integration, or command packages.
+\- Each task must be completable by Qwen3.5-9B in one file or one test file.
+
+Output:
+For each task give:
+\- task name
+\- target model
+\- file path
+\- exact prompt to give Qwen3.5-9B
+\- tests required
+\- definition of done
+
+Step 2:
+Give one task at a time to Qwen3.5-9B.
+
+Step 3:
+Run build/tests.
+
+Step 4:
+If build fails, give the exact error to Qwen3.5-9B once.
+
+Repair prompt:
+MODEL: Qwen3.5-9B
+
+The previous code failed to compile.
+
+Error:
+\[PASTE ERROR\]
+
+Relevant files:
+\[PASTE FILES\]
+
+Fix only the error.
+Do not rewrite unrelated code.
+Do not add new systems.
+Return the corrected file only.
+
+Step 5:
+If the second 9B attempt fails, escalate to Qwen3.6-27B.
+
+Escalation prompt:
+MODEL: Qwen3.6-27B
+
+Qwen3.5-9B failed twice to fix this issue.
+
+Goal:
+\[PASTE TASK GOAL\]
+
+Error:
+\[PASTE ERROR\]
+
+Files:
+\[PASTE RELEVANT FILES\]
+
+Find the root cause and provide the smallest safe fix.
+Do not redesign the system unless the design is the root cause.
+Do not add unrelated features.
+
+Output:
+\- root cause
+\- corrected code
+\- why the fix works
+\- any follow-up test needed
+
+Step 6:
+After every successful task, ask Qwen3.6-27B to review the milestone when enough files exist.
+
+80\. Prompt Discipline Rules
+
+These rules are mandatory when working with local AI.
+
+Rule 1:
+Never ask a 9B model to build a whole subsystem.
+
+Rule 2:
+Never give vague prompts such as "make the ecosystem" or "fix the mod".
+
+Rule 3:
+Always include the file path.
+
+Rule 4:
+Always include the class name.
+
+Rule 5:
+Always state whether Minecraft or NeoForge imports are allowed.
+
+Rule 6:
+Always state what is out of scope.
+
+Rule 7:
+Always ask for tests when the code is plain Java.
+
+Rule 8:
+Always run tests before moving on.
+
+Rule 9:
+After two failed repair attempts by Qwen3.5-9B, escalate to Qwen3.6-27B.
+
+Rule 10:
+If Qwen3.6-27B says the task is too broad, split it into smaller files.
+
+81\. Local Model Role Summary
+
+Qwen3.5-9B role:
+\- one class
+\- one enum
+\- one record
+\- one interface
+\- one test file
+\- simple bug fix
+\- simple refactor
+\- simple documentation
+
+Qwen3.6-27B role:
+\- architecture review
+\- multi-file debugging
+\- NeoForge uncertainty
+\- save design
+\- scheduler design
+\- module boundary review
+\- version upgrade review
+\- difficult compile errors
+\- planning next batches
+
+Do not swap these roles unless necessary.
diff --git a/Docs/prompts.md b/Docs/prompts.md
new file mode 100644
index 0000000..836b853
--- /dev/null
+++ b/Docs/prompts.md
@@ -0,0 +1,2285 @@
+60\. AI Prompt Pack — Local Model Workflow for Each Build Step
+
+Date added: 05 June 2026
+
+Purpose:
+This section gives copy-and-paste prompts for local AI development using Qwen3.5-9B as the main coding worker and Qwen3.6-27B as the planner, reviewer, debugger, and architecture guard.
+
+Model usage rule:
+
+\- Use Qwen3.5-9B for small, isolated implementation tasks.
+\- Use Qwen3.6-27B for architecture decisions, reviewing several files at once, diagnosing difficult errors, and checking that the code still follows the design.
+\- Do not ask Qwen3.5-9B to build broad systems.
+\- Do not waste Qwen3.6-27B on tiny one-class tasks unless Qwen3.5-9B fails twice.
+
+General 9B worker prompt template:
+
+Use this when asking Qwen3.5-9B to create or edit one file.
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+You are implementing one small Java task for a Minecraft NeoForge mod called Living World.
+
+Important project rules:
+\- Core simulation code must be plain Java wherever possible.
+\- Do not import Minecraft or NeoForge classes unless this specific task says to.
+\- Do not create extra systems beyond the task.
+\- Keep the code small and testable.
+\- Follow the package path exactly.
+\- Use clear names.
+\- Add validation where requested.
+\- If tests are requested, write the tests too.
+
+Task:
+\[PASTE TASK HERE\]
+
+Output required:
+1\. Brief explanation of what files you will create or edit.
+2\. Full code for each file.
+3\. Any test code required.
+4\. Notes about assumptions.
+
+Do not skip requirements.
+Do not add unrelated features.
+
+General 27B architect/reviewer prompt template:
+
+Use this when asking Qwen3.6-27B to review multiple files, fix design drift, or plan the next batch.
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+You are the senior architect reviewing the Living World Minecraft NeoForge mod.
+
+Project direction:
+This is an ecosystem-only world evolution mod. It does not simulate villagers, NPC civilisations, settlements, factions, wars, trade, roads, or wildlife AI.
+
+Architecture rules:
+\- Core simulation must remain plain Java where possible.
+\- Minecraft and NeoForge code must stay in platform or integration packages.
+\- Regions are the main simulation unit, not chunks.
+\- Modules must communicate through services, events, or public data contracts.
+\- Save data must be versioned.
+\- Debug and tests are mandatory.
+
+Review these files:
+\[PASTE FILES OR SUMMARIES\]
+
+Check for:
+1\. Incorrect Minecraft/NeoForge imports in core classes.
+2\. Scope creep into NPCs, factions, roads, or settlements.
+3\. Broken package boundaries.
+4\. Missing validation.
+5\. Bad lifecycle handling.
+6\. Save/versioning issues.
+7\. Test gaps.
+8\. Overly broad or fragile code.
+
+Output required:
+1\. Pass/fail summary.
+2\. Specific problems by file.
+3\. Exact fixes.
+4\. Revised code only where necessary.
+5\. Recommended next task.
+
+61\. Milestone 1 AI Prompts — Project Skeleton
+
+Task 1.1 prompt — Create base mod package
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/LivingWorldMod.java for a Minecraft NeoForge mod called Living World.
+
+Requirements:
+\- Package: com.livingworld
+\- Class name: LivingWorldMod
+\- Define public static final String MOD\_ID using LivingWorldConstants.MOD\_ID if that class already exists. If it does not exist yet, temporarily define MOD\_ID \= "livingworld" and add a TODO to replace it after constants are created.
+\- This class must contain only entrypoint wiring.
+\- It must not contain simulation logic.
+\- It must log a startup message.
+\- It must delegate startup work to com.livingworld.bootstrap.LivingWorldBootstrap if available.
+\- If NeoForge annotations/imports are needed, keep them only in this entrypoint file.
+
+Output:
+\- Full Java file.
+\- Any assumptions about the NeoForge version.
+\- Do not create unrelated classes.
+
+Task 1.2 prompt — Create bootstrap class
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java.
+
+Requirements:
+\- Package: com.livingworld.bootstrap
+\- Class name: LivingWorldBootstrap
+\- Methods:
+ \- void initialize()
+ \- void onCommonSetup()
+ \- void onServerStarting()
+ \- void onServerStarted()
+ \- void onServerStopping()
+\- Each method should log its lifecycle stage.
+\- Use LivingWorldLogger if available. If not available yet, use a minimal temporary logger comment and no System.out.
+\- Do not add gameplay logic.
+\- Do not create region, ecosystem, or persistence systems yet.
+
+Output:
+\- Full Java file.
+\- Short explanation of where it should be called from.
+
+Task 1.3 prompt — Create package placeholders
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create the package placeholder structure for the Living World mod.
+
+Packages:
+\- com.livingworld.api
+\- com.livingworld.bootstrap
+\- com.livingworld.config
+\- com.livingworld.core
+\- com.livingworld.core.lifecycle
+\- com.livingworld.core.registry
+\- com.livingworld.core.services
+\- com.livingworld.core.simulation
+\- com.livingworld.data
+\- com.livingworld.data.saved
+\- com.livingworld.data.migration
+\- com.livingworld.data.serialization
+\- com.livingworld.events
+\- com.livingworld.regions
+\- com.livingworld.regions.cache
+\- com.livingworld.regions.query
+\- com.livingworld.commands
+\- com.livingworld.debug
+\- com.livingworld.networking
+\- com.livingworld.platform
+\- com.livingworld.platform.neoforge
+\- com.livingworld.integration.minecraft
+\- com.livingworld.modules
+\- com.livingworld.modules.ecosystem
+\- com.livingworld.modules.soil
+\- com.livingworld.modules.water
+\- com.livingworld.modules.pollution
+\- com.livingworld.modules.vegetation
+\- com.livingworld.modules.resources
+\- com.livingworld.modules.recovery
+\- com.livingworld.modules.worldeffects
+\- com.livingworld.testing
+
+If Java requires at least one file per package in this project setup, create a package-info.java file with a one-line comment for each package.
+
+Do not add implementation logic.
+
+Task 1.4 prompt — Create constants
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/LivingWorldConstants.java.
+
+Requirements:
+\- Package: com.livingworld.core
+\- Final utility class.
+\- Private constructor.
+\- Constants:
+ \- public static final String MOD\_ID \= "livingworld";
+ \- public static final String MOD\_NAME \= "Living World";
+ \- public static final int CURRENT\_CORE\_SCHEMA\_VERSION \= 1;
+ \- public static final int DEFAULT\_REGION\_SIZE\_CHUNKS \= 8;
+ \- public static final int DEFAULT\_SIMULATION\_INTERVAL\_TICKS \= 100;
+\- Do not import Minecraft or NeoForge classes.
+\- Add short comments explaining each constant.
+
+Output:
+\- Full Java file.
+
+Milestone 1 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the completed Milestone 1 project skeleton for the Living World ecosystem mod.
+
+Files to review:
+\[LivingWorldMod.java, LivingWorldBootstrap.java, LivingWorldConstants.java, and package list]
+
+Check:
+\- Entrypoint contains no simulation logic.
+\- Bootstrap owns startup flow.
+\- Constants are centralised.
+\- No ecosystem/NPC/settlement/faction systems were added early.
+\- Minecraft/NeoForge imports are restricted to entrypoint or platform boundary.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Next safe milestone.
+
+62\. Milestone 2 AI Prompts — Logging and Diagnostics
+
+Task 2.1 prompt — Create logger wrapper
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/LivingWorldLogger.java.
+
+Requirements:
+\- Package: com.livingworld.debug
+\- Class name: LivingWorldLogger
+\- Provide static methods:
+ \- info(String message)
+ \- warn(String message)
+ \- error(String message)
+ \- error(String message, Throwable throwable)
+ \- debug(String message)
+ \- info(DiagnosticCategory category, String message)
+ \- warn(DiagnosticCategory category, String message)
+ \- error(DiagnosticCategory category, String message)
+ \- debug(DiagnosticCategory category, String message)
+\- Use a standard logger appropriate for the mod environment if available.
+\- Do not use System.out.
+\- If debug config does not exist yet, allow debug messages for now and add a TODO to wire config later.
+\- Do not import ecosystem module classes.
+
+Output:
+\- Full Java file.
+
+Task 2.2 prompt — Create diagnostic category enum
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/DiagnosticCategory.java.
+
+Requirements:
+\- Package: com.livingworld.debug
+\- Enum values:
+ \- BOOTSTRAP
+ \- CONFIG
+ \- REGIONS
+ \- SIMULATION
+ \- PERSISTENCE
+ \- EVENTS
+ \- MODULES
+ \- COMMANDS
+ \- NETWORKING
+ \- PLATFORM
+ \- ECOSYSTEM
+ \- TESTING
+\- Add a method displayName() that returns a readable name.
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java enum.
+
+Milestone 2 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the logging and diagnostics foundation.
+
+Files:
+\[PASTE LivingWorldLogger.java and DiagnosticCategory.java\]
+
+Check:
+\- No System.out usage.
+\- Logger methods are consistent.
+\- Categories match the ecosystem-only architecture.
+\- No unnecessary Minecraft imports.
+\- Debug behaviour can later connect to config.
+
+Output:
+\- Problems found.
+\- Recommended fixes.
+\- Whether Milestone 3 can begin.
+
+63\. Milestone 3 AI Prompts — Configuration Foundation
+
+Task 3.1 prompt — Create SimulationConfig
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/config/SimulationConfig.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- int regionSizeChunks \= 8
+ \- int simulationIntervalTicks \= 100
+ \- int maxRegionsPerCycle \= 50
+ \- int maxMillisecondsPerCycle \= 25
+ \- int emergencyStopMilliseconds \= 40
+ \- boolean enableDebugCommands \= true
+ \- boolean enableProfiler \= true
+\- Add getters.
+\- Add setters only if needed for tests.
+\- Add validate() method.
+\- Validation rules:
+ \- regionSizeChunks \>= 1
+ \- simulationIntervalTicks \>= 1
+ \- maxRegionsPerCycle \>= 1
+ \- maxMillisecondsPerCycle \>= 1
+ \- emergencyStopMilliseconds \>= maxMillisecondsPerCycle
+\- Throw IllegalArgumentException with clear messages on invalid values.
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java file.
+\- Basic test suggestions.
+
+Task 3.2 prompt — Create ConfigService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ConfigService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- SimulationConfig getSimulationConfig()
+ \- void reload()
+ \- void validate()
+\- Import SimulationConfig from com.livingworld.config.
+\- Do not reference NeoForge config APIs here.
+
+Output:
+\- Full Java interface.
+
+Task 3.3 prompt — Create DefaultConfigService
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/config/DefaultConfigService.java.
+
+Requirements:
+\- Implements ConfigService.
+\- Holds a SimulationConfig instance.
+\- Constructor creates default SimulationConfig and validates it.
+\- getSimulationConfig returns the config.
+\- reload can be a safe placeholder for now, but it must revalidate.
+\- validate delegates to SimulationConfig.validate().
+\- Log validation success using LivingWorldLogger if available.
+\- Do not use NeoForge config classes yet.
+
+Output:
+\- Full Java file.
+
+Milestone 3 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the configuration foundation for the Living World ecosystem mod.
+
+Files:
+\[PASTE SimulationConfig.java, ConfigService.java, DefaultConfigService.java\]
+
+Check:
+\- Config is plain Java.
+\- Validation is strict and clear.
+\- No direct NeoForge dependency yet.
+\- Defaults match the design document.
+\- Future Forge/NeoForge config wiring can be added without rewriting core code.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Any missing config values for ecosystem-only MVP.
+
+64\. Milestone 4 AI Prompts — Core Service Registry
+
+Task 4.1 prompt — Create ServiceKey
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ServiceKey.java.
+
+Requirements:
+\- Generic immutable value object.
+\- Prefer Java record if project Java version supports it.
+\- Fields:
+ \- String id
+ \- Class\ serviceType
+\- Validate id is not null or blank.
+\- Validate serviceType is not null.
+\- Add stable toString().
+\- Do not import Minecraft or NeoForge classes.
+
+Output:
+\- Full Java file.
+
+Task 4.2 prompt — Create ServiceRegistry
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/ServiceRegistry.java.
+
+Requirements:
+\- Plain Java class.
+\- Internally store services by ServiceKey.
+\- Methods:
+ \- \ void register(ServiceKey\ key, T service)
+ \- \ T get(ServiceKey\ key)
+ \- \ Optional\ find(ServiceKey\ key)
+ \- boolean isRegistered(ServiceKey\\> key)
+ \- void lock()
+ \- boolean isLocked()
+\- Reject duplicate registrations.
+\- Reject null keys and null services.
+\- If locked, reject new registrations.
+\- Missing get() should throw clear IllegalStateException.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested unit tests.
+
+Task 4.3 prompt — Create CoreServices
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/CoreServices.java.
+
+Requirements:
+\- Final utility class with private constructor.
+\- Define ServiceKey constants for:
+ \- CONFIG
+ \- REGIONS
+ \- SIMULATION
+ \- PERSISTENCE
+ \- EVENTS
+ \- MODULES
+ \- TIME
+ \- DEBUG
+ \- HISTORY
+\- If some service interfaces do not exist yet, add TODO comments and create keys only for existing interfaces, or use Object temporarily with clear TODOs.
+\- Do not create fake gameplay services.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Note any TODOs caused by missing interfaces.
+
+Milestone 4 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the core service registry.
+
+Files:
+\[ServiceKey.java, ServiceRegistry.java, CoreServices.java\]
+
+Check:
+\- Type safety is acceptable.
+\- Registry cannot be mutated after lock.
+\- Errors are clear.
+\- No hidden global state problems.
+\- No Minecraft imports.
+\- Design is suitable for module dependency injection later.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Risk notes.
+
+65\. Milestone 5 AI Prompts — Region Identity
+
+Task 5.1 prompt — Create RegionCoordinate
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionCoordinate.java.
+
+Requirements:
+\- Java record if available.
+\- Fields:
+ \- String dimensionId
+ \- int x
+ \- int z
+\- Validate dimensionId is not null or blank.
+\- Static methods:
+ \- fromChunk(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+ \- fromBlock(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+\- Instance methods:
+ \- int minChunkX(int regionSizeChunks)
+ \- int minChunkZ(int regionSizeChunks)
+ \- int maxChunkX(int regionSizeChunks)
+ \- int maxChunkZ(int regionSizeChunks)
+ \- int centerBlockX(int regionSizeChunks)
+ \- int centerBlockZ(int regionSizeChunks)
+ \- String stableId()
+\- Use Math.floorDiv so negative coordinates work correctly.
+\- Validate regionSizeChunks \>= 1\.
+\- Do not import Minecraft classes.
+
+Test requirements:
+Create RegionCoordinateTest if test framework exists.
+Test:
+\- block 0,0 maps to region 0,0
+\- block 127,127 maps to region 0,0 with region size 8 chunks
+\- block 128,0 maps to region 1,0
+\- block \-1,0 maps to region \-1,0
+\- block \-128,0 maps to region \-1,0
+\- block \-129,0 maps to region \-2,0
+\- stableId is stable
+\- works as HashMap key
+
+Output:
+\- Full Java file.
+\- Full test file if possible.
+
+Task 5.2 prompt — Create RegionLifecycleState
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionLifecycleState.java.
+
+Requirements:
+\- Enum values:
+ \- UNLOADED
+ \- LOADING
+ \- ACTIVE
+ \- DIRTY
+ \- SAVING
+ \- FAILED
+ \- UNLOADING
+\- Add comments explaining each state.
+\- Do not add methods unless useful.
+\- No Minecraft imports.
+
+Output:
+\- Full Java enum.
+
+Task 5.3 prompt — Create RegionFlags
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionFlags.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- boolean hasPlayerActivity
+ \- boolean hasHighPollution
+ \- boolean hasLowSoilQuality
+ \- boolean hasActiveEcosystemEvent
+ \- boolean forceLoadedBySimulation
+ \- boolean corrupted
+\- Do not include settlement, road, faction, or NPC flags.
+\- Add getters and setters.
+\- Add copy().
+\- Add clearTransientFlags(). This should clear hasPlayerActivity and hasActiveEcosystemEvent, but not corrupted.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 5 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review region identity classes.
+
+Files:
+\[RegionCoordinate.java, RegionLifecycleState.java, RegionFlags.java, and tests\]
+
+Check:
+\- Negative coordinate math is correct.
+\- No Minecraft classes leaked into region core.
+\- Flags match ecosystem-only scope.
+\- RegionCoordinate is safe as a HashMap key.
+\- Tests cover edge cases.
+
+Output:
+\- Pass/fail.
+\- Exact fixes if needed.
+
+66\. Milestone 6 AI Prompts — Region Core Data
+
+Task 6.1 prompt — Create RegionMetrics
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionMetrics.java.
+
+Requirements:
+\- Plain Java class.
+\- Ecosystem-only fields:
+ \- double ecosystemHealth
+ \- double pollutionScore
+ \- double soilQuality
+ \- double waterQuality
+ \- double vegetationPressure
+ \- double resourceDepletion
+ \- double recoveryPressure
+\- Values should normally be clamped between 0 and 100\.
+\- Add normalize().
+\- Add copy().
+\- Add static defaults().
+\- Defaults:
+ \- ecosystemHealth \= 60
+ \- pollutionScore \= 0
+ \- soilQuality \= 60
+ \- waterQuality \= 60
+ \- vegetationPressure \= 50
+ \- resourceDepletion \= 0
+ \- recoveryPressure \= 50
+\- Add applyDelta methods if simple and clean.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Task 6.2 prompt — Create RegionModuleData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionModuleData.java.
+
+Requirements:
+\- Stores module-specific data by module ID.
+\- Field:
+ \- Map\ moduleData
+\- Methods:
+ \- void put(String moduleId, Object data)
+ \- \ Optional\ get(String moduleId, Class\ type)
+ \- boolean contains(String moduleId)
+ \- Set\ moduleIds()
+ \- RegionModuleData copyShallow()
+\- Validate moduleId is not null or blank.
+\- Reject null data.
+\- If get type does not match, return Optional.empty instead of throwing.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 6.3 prompt — Create Region
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/Region.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- UUID id
+ \- RegionCoordinate coordinate
+ \- RegionLifecycleState lifecycleState
+ \- long createdAtSimulationTick
+ \- long lastUpdatedSimulationTick
+ \- boolean dirty
+ \- RegionFlags flags
+ \- RegionMetrics metrics
+ \- RegionModuleData moduleData
+\- Constructor validates required fields.
+\- Methods:
+ \- markDirty()
+ \- clearDirty()
+ \- isDirty()
+ \- updateLastSimulatedTick(long tick)
+ \- setLifecycleState(RegionLifecycleState state)
+ \- validate()
+\- validate() checks id, coordinate, lifecycleState, flags, metrics, and moduleData are not null.
+\- Do not include settlement, faction, road, or NPC fields.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 6 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the region core data classes.
+
+Files:
+\[PASTE RegionMetrics.java, RegionModuleData.java, Region.java\]
+
+Check:
+\- Metrics match ecosystem-only scope.
+\- Region is not bloated with future unrelated systems.
+\- Validation is strong.
+\- Dirty state behaviour is sensible.
+\- No Minecraft imports.
+\- No direct persistence logic inside Region.
+
+Output:
+\- Pass/fail.
+\- Exact corrections.
+
+67\. Milestone 7 AI Prompts — Region Creation and Lifecycle
+
+Task 7.1 prompt — Create RegionLifecycleController
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionLifecycleController.java.
+
+Requirements:
+\- Plain Java class.
+\- Methods:
+ \- boolean canTransition(RegionLifecycleState from, RegionLifecycleState to)
+ \- void transition(Region region, RegionLifecycleState target)
+\- Allowed transitions:
+ \- UNLOADED \-\> LOADING
+ \- LOADING \-\> ACTIVE
+ \- LOADING \-\> FAILED
+ \- ACTIVE \-\> DIRTY
+ \- DIRTY \-\> SAVING
+ \- SAVING \-\> ACTIVE
+ \- SAVING \-\> FAILED
+ \- ACTIVE \-\> UNLOADING
+ \- UNLOADING \-\> UNLOADED
+ \- FAILED \-\> LOADING
+\- Invalid transitions throw IllegalStateException with clear message.
+\- transition() must validate region is not null.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Task 7.2 prompt — Create RegionFactory
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionFactory.java.
+
+Requirements:
+\- Plain Java class.
+\- Method:
+ \- Region createNewRegion(RegionCoordinate coordinate, long simulationTick)
+\- New region rules:
+ \- random UUID
+ \- coordinate from argument
+ \- lifecycleState ACTIVE
+ \- createdAtSimulationTick \= simulationTick
+ \- lastUpdatedSimulationTick \= simulationTick
+ \- dirty \= true
+ \- default RegionFlags
+ \- RegionMetrics.defaults()
+ \- empty RegionModuleData
+ \- validate before return
+\- No Minecraft imports.
+\- Do not initialise ecology modules here yet; that comes after ModuleRegistry is connected.
+
+Output:
+\- Full Java file.
+
+Milestone 7 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review lifecycle and region creation.
+
+Files:
+\[PASTE RegionLifecycleController.java and RegionFactory.java\]
+
+Check:
+\- Invalid transitions are rejected.
+\- New regions are immediately dirty.
+\- Factory does not import Minecraft classes.
+\- Factory does not start implementing ecosystem gameplay prematurely.
+\- Tests cover valid and invalid transitions.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+68\. Milestone 8 AI Prompts — Module Contracts
+
+Task 8.1 prompt — Create SimulationModule interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/SimulationModule.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String getModuleId()
+ \- ModuleMetadata getMetadata()
+ \- void initialize(ModuleContext context)
+ \- void onServerStarted(ServerContext context)
+ \- void createDefaultRegionData(Region region)
+ \- ModuleUpdateResult updateRegion(RegionUpdateContext context)
+ \- void onLivingWorldEvent(LivingWorldEvent event)
+ \- void saveModuleData(PersistenceWriter writer)
+ \- void loadModuleData(PersistenceReader reader)
+ \- void shutdown()
+\- Create minimal placeholder interfaces/classes if missing:
+n \- ServerContext
+ \- RegionUpdateContext
+ \- LivingWorldEvent
+ \- PersistenceWriter
+ \- PersistenceReader
+\- Do not implement any real ecosystem module yet.
+\- No Minecraft imports in this interface.
+
+Output:
+\- Full Java interface.
+\- Any minimal placeholder files required.
+
+Task 8.2 prompt — Create ModuleMetadata
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleMetadata.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- String moduleId
+ \- String displayName
+ \- String version
+ \- String description
+ \- String requiredCoreVersion
+ \- List\ dependencies
+ \- List\ optionalDependencies
+ \- boolean defaultEnabled
+ \- boolean serverOnly
+ \- boolean experimental
+\- Validate moduleId and displayName are not blank.
+\- Replace null dependency lists with empty lists.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 8.3 prompt — Create ModuleContext
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleContext.java.
+
+Requirements:
+\- Plain Java class.
+\- Field:
+ \- ServiceRegistry services
+\- Constructor validates services is not null.
+\- Method:
+ \- \ T getService(ServiceKey\ key)
+\- Do not expose the whole registry for mutation if avoidable.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 8.4 prompt — Create ModuleUpdateResult
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleUpdateResult.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- boolean changedRegion
+ \- List\ generatedEvents
+ \- List\ historyRecords
+ \- int estimatedCost
+ \- List\ warnings
+\- Static constructors:
+ \- noChange()
+ \- changed()
+\- Null lists become empty lists.
+\- estimatedCost must not be negative.
+\- No Minecraft imports.
+
+If HistoryRecord does not exist, create a minimal placeholder in com.livingworld.modules or com.livingworld.events with TODO to move later.
+
+Output:
+\- Full Java file.
+\- Any placeholder file required.
+
+Task 8.5 prompt — Create ModuleRegistry
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ModuleRegistry.java.
+
+Requirements:
+\- Plain Java class.
+\- Responsibilities:
+ \- register modules
+ \- reject duplicate module IDs
+ \- return all modules
+ \- return enabled modules
+ \- find by module ID
+ \- initialize all
+ \- shutdown all
+\- Methods:
+ \- void register(SimulationModule module)
+ \- List\ getAllModules()
+ \- List\ getEnabledModules()
+ \- Optional\ find(String moduleId)
+ \- void initializeAll(ModuleContext context)
+ \- void shutdownAll()
+\- For v1, enabled modules are modules where metadata.defaultEnabled is true.
+\- Do not implement dependency sorting yet; add TODO.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 8 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review module contract architecture.
+
+Files:
+\[PASTE SimulationModule.java, ModuleMetadata.java, ModuleContext.java, ModuleUpdateResult.java, ModuleRegistry.java\]
+
+Check:
+\- Modules are generic and not tied to settlements/factions/NPCs.
+\- Core module contracts do not import Minecraft classes.
+\- ModuleRegistry is simple enough for v1.
+\- Missing placeholders are sensible and marked as TODO.
+\- Architecture supports ecosystem modules later.
+
+Output:
+\- Pass/fail.
+\- Required fixes.
+\- Next implementation task.
+
+69\. Milestone 9 AI Prompts — Event Foundation
+
+Task 9.1 prompt — Create LivingWorldEvent
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEvent.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String eventType()
+ \- long simulationTick()
+ \- String sourceModuleId()
+\- No Minecraft imports.
+\- Events must be usable by ecosystem modules later.
+
+Output:
+\- Full Java interface.
+
+Task 9.2 prompt — Create BaseLivingWorldEvent
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/BaseLivingWorldEvent.java.
+
+Requirements:
+\- Immutable class or record implementing LivingWorldEvent.
+\- Fields:
+ \- String eventType
+ \- long simulationTick
+ \- String sourceModuleId
+\- Validate eventType is not blank.
+\- Validate simulationTick is not negative.
+\- sourceModuleId may be "core" for core events but must not be blank.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 9.3 prompt — Create LivingWorldEventListener
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEventListener.java.
+
+Requirements:
+\- Functional interface.
+\- Method:
+ \- void onEvent(LivingWorldEvent event)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 9.4 prompt — Create LivingWorldEventBus
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/events/LivingWorldEventBus.java.
+
+Requirements:
+\- Plain Java class.
+\- Methods:
+ \- void register(String eventType, LivingWorldEventListener listener)
+ \- void publish(LivingWorldEvent event)
+ \- int getPublishedEventCount()
+ \- int getListenerCount(String eventType)
+\- Validate eventType is not blank.
+\- Validate listener is not null.
+\- Event publishing should send the event to listeners registered for that event type.
+\- Unknown event type should not crash.
+\- Prevent obvious recursive event storms with a simple dispatching guard or TODO if not implemented.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested tests.
+
+Milestone 9 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the Living World event foundation.
+
+Files:
+\[PASTE LivingWorldEvent.java, BaseLivingWorldEvent.java, LivingWorldEventListener.java, LivingWorldEventBus.java\]
+
+Check:
+\- Events are plain Java.
+\- EventBus is not overcomplicated.
+\- Unknown events are safe.
+\- Recursion risk is noted or controlled.
+\- Event types can support pollution/soil/vegetation events later.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+70\. Milestone 10 AI Prompts — Time Service
+
+Task 10.1 prompt — Create LivingWorldCalendar
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/LivingWorldCalendar.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- long simulationTick
+ \- int day
+ \- int month
+ \- int year
+\- Default start: day 1, month 1, year 1, simulationTick 0\.
+\- Methods:
+ \- advanceTicks(long ticks)
+ \- copy()
+ \- toDisplayString()
+\- Keep the calendar simple for now.
+\- Use 30 days per month and 12 months per year unless config is added later.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 10.2 prompt — Create TimeService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/TimeService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- long getSimulationTick()
+ \- LivingWorldCalendar getCalendar()
+ \- void advanceSimulationTick()
+ \- void advanceSimulationTicks(long ticks)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 10.3 prompt — Create DefaultTimeService
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/DefaultTimeService.java.
+
+Requirements:
+\- Implements TimeService.
+\- Owns a LivingWorldCalendar.
+\- advanceSimulationTick advances by 1\.
+\- advanceSimulationTicks validates ticks \>= 0 and advances calendar.
+\- getCalendar returns a copy, not the internal mutable instance.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 10 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the Living World time system.
+
+Files:
+\[PASTE LivingWorldCalendar.java, TimeService.java, DefaultTimeService.java\]
+
+Check:
+\- Time is independent of Minecraft classes.
+\- Calendar cannot be mutated externally by accident.
+\- Behaviour is deterministic.
+\- Good enough for ecosystem simulation v1.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+71\. Milestone 11 AI Prompts — Scheduler and Simulation Manager
+
+Task 11.1 prompt — Create UpdateReason
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/UpdateReason.java.
+
+Requirements:
+\- Enum values:
+ \- NORMAL\_ROLLING\_UPDATE
+ \- PLAYER\_NEARBY
+ \- HIGH\_POLLUTION
+ \- LOW\_SOIL\_QUALITY
+ \- ACTIVE\_ECOSYSTEM\_EVENT
+ \- FORCED\_DEBUG\_COMMAND
+ \- SAVE\_MIGRATION\_REQUIRED
+\- Do not include settlement, road, faction, or NPC update reasons.
+\- No Minecraft imports.
+
+Output:
+\- Full Java enum.
+
+Task 11.2 prompt — Create RegionUpdateJob
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/RegionUpdateJob.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- RegionCoordinate coordinate
+ \- int priority
+ \- long queuedAtSimulationTick
+ \- Set\ requestedModules
+ \- UpdateReason reason
+\- Validate coordinate and reason are not null.
+\- priority must not be negative.
+\- queuedAtSimulationTick must not be negative.
+\- Null requestedModules becomes empty set.
+\- Add comparator for descending priority if clean.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 11.3 prompt — Create RegionPriorityCalculator
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/RegionPriorityCalculator.java.
+
+Requirements:
+\- Plain Java class.
+\- Method:
+ \- int calculatePriority(Region region)
+\- Initial ecosystem-only scoring:
+ \- base \= 5
+ \- hasPlayerActivity bonus \= 100
+ \- hasActiveEcosystemEvent bonus \= 75
+ \- hasHighPollution bonus \= 50
+ \- hasLowSoilQuality bonus \= 50
+ \- pollution bonus \= pollutionScore / 2
+ \- resource depletion bonus \= resourceDepletion / 3
+ \- recovery pressure bonus \= recoveryPressure / 4
+\- Validate region is not null.
+\- Result should be deterministic.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 11.4 prompt — Create SimulationScheduler
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/simulation/SimulationScheduler.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor accepts SimulationConfig.
+\- Fields:
+ \- long minecraftTickCounter
+ \- long simulationTickCounter
+ \- PriorityQueue\ updateQueue
+\- Methods:
+ \- void onMinecraftTick()
+ \- boolean shouldRunSimulationCycle()
+ \- void queueRegion(RegionUpdateJob job)
+ \- List\ pollJobsForCycle()
+ \- long getMinecraftTickCounter()
+ \- long getSimulationTickCounter()
+\- shouldRunSimulationCycle true when minecraftTickCounter reaches the configured interval.
+\- pollJobsForCycle returns at most maxRegionsPerCycle jobs.
+\- Higher priority jobs first.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+\- Suggested scheduler budget tests.
+
+Task 11.5 prompt — Create SimulationManager skeleton
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create the first version of src/main/java/com/livingworld/core/simulation/SimulationManager.java.
+
+This is an architecture-sensitive class. Keep it boring and coordinator-only.
+
+Requirements:
+\- Constructor dependencies:
+ \- SimulationScheduler scheduler
+ \- RegionManager regionManager
+ \- ModuleRegistry moduleRegistry
+ \- LivingWorldEventBus eventBus
+ \- TimeService timeService
+ \- PersistenceService persistenceService
+ \- SimulationProfiler profiler, if available. If not available, make it optional or TODO.
+\- Methods:
+ \- void onMinecraftServerTick()
+ \- void runSimulationCycle()
+ \- void runForcedSimulationTicks(int ticks)
+\- Responsibilities:
+ \- Advance scheduler on Minecraft tick.
+ \- If scheduler says cycle should run, run one cycle.
+ \- Poll region update jobs.
+ \- Resolve regions from RegionManager.
+ \- Run enabled modules in order.
+ \- Publish generated events.
+ \- Mark changed regions dirty.
+ \- Advance TimeService.
+\- Do not implement ecosystem rules here.
+\- Do not import Minecraft or NeoForge classes.
+\- Do not scan chunks.
+
+Output:
+\- Full Java file.
+\- Any missing interface TODOs.
+\- Explanation of control flow.
+
+Milestone 11 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review scheduler and SimulationManager.
+
+Files:
+\[PASTE UpdateReason.java, RegionUpdateJob.java, RegionPriorityCalculator.java, SimulationScheduler.java, SimulationManager.java\]
+
+Check:
+\- No Minecraft imports in scheduler/manager.
+\- Budgeting is respected.
+\- SimulationManager contains no gameplay rules.
+\- Ecosystem-only priority values are correct.
+\- Forced simulation cannot accidentally lock the server forever.
+\- Good enough before persistence and region manager are finished.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Next safest step.
+
+72\. Milestone 12 AI Prompts — Persistence Foundation
+
+Task 12.1 prompt — Create PersistenceWriter
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/serialization/PersistenceWriter.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- void writeString(String key, String value)
+ \- void writeInt(String key, int value)
+ \- void writeLong(String key, long value)
+ \- void writeDouble(String key, double value)
+ \- void writeBoolean(String key, boolean value)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 12.2 prompt — Create PersistenceReader
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/serialization/PersistenceReader.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String readString(String key, String defaultValue)
+ \- int readInt(String key, int defaultValue)
+ \- long readLong(String key, long defaultValue)
+ \- double readDouble(String key, double defaultValue)
+ \- boolean readBoolean(String key, boolean defaultValue)
+\- No Minecraft imports.
+
+Output:
+\- Full Java interface.
+
+Task 12.3 prompt — Create SaveMetadata
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/data/saved/SaveMetadata.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- int schemaVersion
+ \- String modVersion
+ \- long createdAt
+ \- long updatedAt
+\- Validate schemaVersion \> 0\.
+\- Validate modVersion is not blank.
+\- Validate updatedAt \>= createdAt.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 12.4 prompt — Create PersistenceService interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/core/services/PersistenceService.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- void markRegionDirty(Region region)
+ \- void saveDirtyRegions()
+ \- Optional\ loadRegion(RegionCoordinate coordinate)
+ \- void saveRegion(Region region)
+ \- void flushAll()
+\- No Minecraft imports.
+\- Do not implement file storage yet.
+
+Output:
+\- Full Java interface.
+
+Milestone 12 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review persistence foundation.
+
+Files:
+\[PASTE PersistenceWriter.java, PersistenceReader.java, SaveMetadata.java, PersistenceService.java\]
+
+Check:
+\- Persistence interfaces are plain Java.
+\- Region persistence is abstracted.
+\- Save metadata is versioned.
+\- No module writes files directly.
+\- Good enough before JSON/NBT implementation.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+73\. Milestone 13 AI Prompts — Region Storage and Manager
+
+Task 13.1 prompt — Create RegionStorage
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionStorage.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor dependency:
+ \- PersistenceService persistenceService
+\- Methods:
+ \- Optional\ load(RegionCoordinate coordinate)
+ \- void save(Region region)
+\- load delegates to persistenceService.loadRegion.
+\- save delegates to persistenceService.saveRegion.
+\- Validate dependencies and arguments.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.2 prompt — Create RegionCache
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/cache/RegionCache.java.
+
+Requirements:
+\- Plain Java class.
+\- Field:
+ \- Map\ activeRegions
+\- Methods:
+ \- Optional\ get(RegionCoordinate coordinate)
+ \- void put(Region region)
+ \- void remove(RegionCoordinate coordinate)
+ \- Collection\ allActive()
+ \- int size()
+\- Validate inputs.
+\- allActive should return an unmodifiable copy or safe view.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.3 prompt — Create RegionQueryEngine
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/query/RegionQueryEngine.java.
+
+Requirements:
+\- Plain Java class.
+\- Constructor dependency:
+ \- RegionCache cache
+\- Methods:
+ \- Optional\ getRegion(RegionCoordinate coordinate)
+ \- List\ getRegionsInRadius(RegionCoordinate center, int radius)
+ \- List\ getRegionsWithActiveEcosystemEvent()
+ \- List\ getRegionsAbovePollution(double threshold)
+ \- List\ getRegionsBelowSoilQuality(double threshold)
+\- Do not touch Minecraft chunks.
+\- Radius means region-coordinate radius.
+\- Validate radius \>= 0\.
+\- No settlement, road, faction, or NPC queries.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 13.4 prompt — Create RegionManager
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/regions/RegionManager.java.
+
+This is a core architecture class. Keep it clean and plain Java.
+
+Dependencies:
+\- RegionFactory regionFactory
+\- RegionStorage regionStorage
+\- RegionCache regionCache
+\- RegionQueryEngine queryEngine
+\- RegionLifecycleController lifecycleController
+\- SimulationConfig simulationConfig
+
+Methods:
+\- Region getOrCreateRegion(RegionCoordinate coordinate)
+\- Optional\ findRegion(RegionCoordinate coordinate)
+\- Region getOrCreateRegionAtBlock(String dimensionId, int blockX, int blockZ)
+\- Collection\ getActiveRegions()
+\- void markDirty(Region region)
+\- void unloadRegion(RegionCoordinate coordinate)
+
+Rules:
+\- getOrCreate first checks cache.
+\- If missing, try storage.
+\- If storage missing, use factory.
+\- New or modified regions must be marked dirty.
+\- Do not import Minecraft or NeoForge classes.
+\- Do not scan chunks.
+\- Do not apply visible world effects.
+
+Output:
+\- Full Java file.
+\- Explanation of load/create flow.
+\- Edge cases.
+
+Milestone 13 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review RegionStorage, RegionCache, RegionQueryEngine, and RegionManager.
+
+Files:
+\[PASTE FILES\]
+
+Check:
+\- RegionManager load/create flow is correct.
+\- No duplicate region instances are likely.
+\- No Minecraft imports.
+\- Queries are ecosystem-focused.
+\- Dirty handling is sensible.
+\- Region lifecycle transitions are not abused.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Tests to add.
+
+74\. Milestone 14 AI Prompts — Debug Commands
+
+Task 14.1 prompt — Create command root
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/LivingWorldCommandRoot.java for a NeoForge Minecraft mod.
+
+This file is allowed to use Minecraft/NeoForge command classes because it is in the commands boundary.
+
+Requirements:
+\- Register /lw command tree.
+\- Initial subcommands:
+ \- /lw status
+ \- /lw region info
+ \- /lw modules list
+ \- /lw simulate \
+\- If exact NeoForge command registration API is uncertain, create a clean skeleton with TODO comments at API-specific points.
+\- Command implementation should delegate to service classes where possible.
+\- Do not place ecosystem simulation rules inside command classes.
+
+Output:
+\- Full Java file.
+\- Notes about API assumptions.
+
+Task 14.2 prompt — Create RegionInfoCommand
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/RegionInfoCommand.java.
+
+This class may use Minecraft command/source classes if necessary, but region logic must stay in RegionManager.
+
+Output should include:
+\- Region coordinate
+\- Lifecycle state
+\- Dirty state
+\- Ecosystem metrics
+\- Flags
+\- Module IDs present
+
+Requirements:
+\- Use RegionManager to get region data.
+\- Use coordinate mapper or boundary conversion instead of putting Minecraft classes into RegionCoordinate.
+\- Do not reference settlements, factions, NPCs, roads, or economy.
+
+Output:
+\- Full Java file.
+\- API assumptions.
+
+Task 14.3 prompt — Create SimulateCommand
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/commands/SimulateCommand.java.
+
+Requirements:
+\- Operator-only command.
+\- Accept tick count.
+\- Safe maximum default: 1000 ticks.
+\- Calls SimulationManager.runForcedSimulationTicks(ticks).
+\- Rejects negative or zero ticks.
+\- Prints clear success/failure output.
+\- Does not implement simulation rules itself.
+
+Output:
+\- Full Java file.
+\- Notes on NeoForge/Minecraft command API assumptions.
+
+Milestone 14 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review command implementation.
+
+Files:
+\[PASTE LivingWorldCommandRoot.java, RegionInfoCommand.java, SimulateCommand.java\]
+
+Check:
+\- Minecraft/NeoForge imports are limited to command boundary.
+\- Commands delegate to services.
+\- /lw simulate has safety limits.
+\- Output is useful for debugging ecosystem state.
+\- No gameplay logic hidden in commands.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+75\. Milestone 15 AI Prompts — Profiling
+
+Task 15.1 prompt — Create SimulationProfiler
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/SimulationProfiler.java.
+
+Requirements:
+\- Plain Java class.
+\- Tracks:
+ \- cycle start time
+ \- cycle end time
+ \- per-module timings
+ \- per-region timings if simple
+ \- event count
+ \- save count
+ \- budget overruns
+\- Methods:
+ \- beginCycle()
+ \- endCycle()
+ \- beginModule(String moduleId)
+ \- endModule(String moduleId)
+ \- recordEvent()
+ \- recordSave()
+ \- recordBudgetOverrun()
+ \- SimulationProfileSnapshot createSnapshot()
+\- Use System.nanoTime internally for timing.
+\- Do not use System.out.
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Task 15.2 prompt — Create SimulationProfileSnapshot
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/debug/SimulationProfileSnapshot.java.
+
+Requirements:
+\- Immutable class or record.
+\- Fields:
+ \- long totalCycleNanos
+ \- Map\ moduleTimings
+ \- int eventsPublished
+ \- int regionsUpdated
+ \- int savesPerformed
+ \- boolean budgetExceeded
+\- Add method toHumanReadableString().
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Milestone 15 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review simulation profiling classes.
+
+Files:
+\[PASTE SimulationProfiler.java and SimulationProfileSnapshot.java\]
+
+Check:
+\- Profiler can measure module cost.
+\- Snapshot is immutable or safely copied.
+\- No server-spam logging built in.
+\- Usable by debug commands later.
+\- No Minecraft imports.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+
+76\. Milestone 16 AI Prompts — Tests and Long-Run Validation
+
+Task 16.1 prompt — Create TestSimulationModule
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/testing/TestSimulationModule.java.
+
+Requirements:
+\- Implements SimulationModule.
+\- Module ID: test
+\- Metadata display name: Test Simulation Module
+\- On initialize, set initialized \= true.
+\- On updateRegion, increment an internal update counter.
+\- Every 10 updates, return ModuleUpdateResult.changed().
+\- Otherwise return ModuleUpdateResult.noChange().
+\- No Minecraft imports.
+\- This is for engine testing only, not gameplay.
+
+Output:
+\- Full Java file.
+
+Task 16.2 prompt — Create RegionCoordinateTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/regions/RegionCoordinateTest.java.
+
+Tests:
+\- block 0,0 maps to region 0,0
+\- block 127,127 maps to region 0,0 with region size 8 chunks
+\- block 128,0 maps to region 1,0
+\- block \-1,0 maps to region \-1,0
+\- block \-128,0 maps to region \-1,0
+\- block \-129,0 maps to region \-2,0
+\- stableId remains stable
+\- RegionCoordinate works as HashMap key
+
+Use the project’s test framework. If unknown, assume JUnit 5\.
+
+Output:
+\- Full test file.
+
+Task 16.3 prompt — Create RegionLifecycleControllerTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/regions/RegionLifecycleControllerTest.java.
+
+Tests:
+\- Allowed transitions succeed.
+\- Invalid transitions throw IllegalStateException.
+\- FAILED can transition to LOADING.
+\- ACTIVE cannot transition directly to SAVING.
+
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.4 prompt — Create SchedulerBudgetTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/core/simulation/SchedulerBudgetTest.java.
+
+Tests:
+\- Given 500 jobs and maxRegionsPerCycle 50, one cycle returns 50 jobs.
+\- Higher priority jobs are returned first.
+\- Jobs not processed remain queued.
+\- shouldRunSimulationCycle respects simulationIntervalTicks.
+
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.5 prompt — Create EventBusTest
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/test/java/com/livingworld/events/EventBusTest.java.
+
+Tests:
+\- Listener receives event.
+\- Listener receives event once.
+\- Multiple listeners receive the event.
+\- Unknown event type does not crash.
+
+Use BaseLivingWorldEvent for test events.
+Use JUnit 5 unless project uses something else.
+
+Output:
+\- Full test file.
+
+Task 16.6 prompt — Create LongRunSimulationTest
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/test/java/com/livingworld/testing/LongRunSimulationTest.java.
+
+Purpose:
+Prove the foundation can run for a long time without collapsing.
+
+Test setup:
+\- Create 1000 fake regions.
+\- Register TestSimulationModule.
+\- Run 100,000 simulation ticks or a reduced count if local test runtime is too high.
+\- Save dirty regions periodically using a fake/in-memory PersistenceService.
+
+Pass conditions:
+\- No crash.
+\- No unhandled exception.
+\- No invalid lifecycle transition.
+\- Dirty region count does not grow forever.
+\- Profiler reports cycle data.
+
+Requirements:
+\- Keep it plain Java where possible.
+\- Do not require a full Minecraft client.
+\- If full implementation requires missing services, create small in-memory fakes inside the test.
+
+Output:
+\- Full test file.
+\- Explanation of any fake services.
+
+Milestone 16 review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the engine test suite.
+
+Files:
+\[PASTE all test files and TestSimulationModule.java\]
+
+Check:
+\- Tests cover foundation risks.
+\- Tests do not require Minecraft client unless absolutely necessary.
+\- Long-run test is realistic for local hardware.
+\- Tests catch coordinate, lifecycle, scheduler, event, and simulation failures.
+\- No NPC/settlement/faction/wildlife scope creep.
+
+Output:
+\- Pass/fail.
+\- Missing tests.
+\- Recommended final fixes before Volume 2\.
+
+77\. Platform Adapter AI Prompts
+
+Task P1 prompt — Create PlatformAdapter interface
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/platform/PlatformAdapter.java.
+
+Requirements:
+\- Interface.
+\- Methods:
+ \- String getPlatformName()
+ \- String getMinecraftVersion()
+ \- String getLoaderVersion()
+ \- boolean isDedicatedServer()
+ \- Path getWorldSaveDirectory()
+ \- void registerCommands()
+ \- void registerServerTickHook()
+ \- void registerPlayerEventHooks()
+\- Import java.nio.file.Path only.
+\- No NeoForge imports here.
+
+Output:
+\- Full Java interface.
+
+Task P2 prompt — Create NeoForgePlatformAdapter skeleton
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Create src/main/java/com/livingworld/platform/neoforge/NeoForgePlatformAdapter.java.
+
+Purpose:
+Implement PlatformAdapter using NeoForge as the active loader.
+
+Rules:
+\- This class may import NeoForge and Minecraft classes.
+\- Core simulation classes must not import NeoForge or Minecraft classes.
+\- If exact NeoForge API names are uncertain for the target version, add clear TODOs at those points instead of inventing unsafe code.
+\- Must log platform name, Minecraft version, and loader version during bootstrap.
+\- Must provide hooks that can forward server ticks to SimulationManager later.
+
+Output:
+\- Full Java file or safe skeleton.
+\- API assumptions.
+\- TODOs requiring verification.
+
+Task P3 prompt — Create MinecraftCoordinateMapper
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/integration/minecraft/MinecraftCoordinateMapper.java.
+
+Requirements:
+\- Boundary class for converting Minecraft coordinates into Living World coordinates.
+\- For now, avoid importing Minecraft classes unless necessary.
+\- Methods:
+ \- RegionCoordinate fromBlockPos(String dimensionId, int blockX, int blockZ, int regionSizeChunks)
+ \- RegionCoordinate fromChunkPos(String dimensionId, int chunkX, int chunkZ, int regionSizeChunks)
+\- Delegate to RegionCoordinate.fromBlock and RegionCoordinate.fromChunk.
+\- No gameplay logic.
+
+Output:
+\- Full Java file.
+
+Platform review prompt
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Review the platform adapter layer.
+
+Files:
+\[PASTE PlatformAdapter.java, NeoForgePlatformAdapter.java, MinecraftCoordinateMapper.java\]
+
+Check:
+\- NeoForge imports are isolated to platform/neoforge or command boundary.
+\- Core simulation remains plain Java.
+\- Platform API is not too wide.
+\- Version reporting is possible.
+\- Server tick hook can eventually call SimulationManager.
+
+Output:
+\- Pass/fail.
+\- Fixes.
+\- Any NeoForge API calls that need checking against current docs.
+
+78\. Ecosystem MVP AI Prompts — To Use After Volume 1 Passes
+
+Do not use these until the Volume 1 completion gate passes.
+
+Ecosystem MVP prompt 1 — Create EcosystemRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/ecosystem/EcosystemRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double ecosystemHealth
+ \- double stress
+ \- double resilience
+ \- double recoveryRate
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- applyStress(double amount)
+ \- applyRecovery(double amount)
+\- No Minecraft imports.
+\- No wildlife, NPC, village, faction, or economy logic.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 2 — Create SoilRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/soil/SoilRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double fertility
+ \- double moisture
+ \- double contamination
+ \- double compaction
+ \- double erosion
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- degrade(double amount)
+ \- recover(double amount)
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 3 — Create PollutionRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/pollution/PollutionRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double airPollution
+ \- double groundPollution
+ \- double waterPollution
+ \- double decayResistance
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- addPollution(double air, double ground, double water)
+ \- decay(double amount)
+\- No Minecraft imports.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 4 — Create VegetationRegionData
+
+MODEL: Qwen3.5-9B
+
+PROMPT:
+Create src/main/java/com/livingworld/modules/vegetation/VegetationRegionData.java.
+
+Requirements:
+\- Plain Java class.
+\- Fields:
+ \- double grassPressure
+ \- double flowerPressure
+ \- double shrubPressure
+ \- double treePressure
+ \- double deadVegetation
+\- Values clamped 0 to 100\.
+\- Methods:
+ \- defaults()
+ \- normalize()
+ \- copy()
+ \- reduceFromLogging(double amount)
+ \- recover(double amount)
+\- No Minecraft imports.
+\- Do not simulate animal populations.
+
+Output:
+\- Full Java file.
+
+Ecosystem MVP prompt 5 — Create simple ecosystem update formulas
+
+MODEL: Qwen3.6-27B
+
+PROMPT:
+Design the first simple ecosystem update formulas for the Living World mod.
+
+Scope:
+\- Ecosystem-only.
+\- No animals.
+\- No villagers.
+\- No settlements.
+\- No factions.
+
+Inputs per region:
+\- ecosystemHealth
+\- soil fertility
+\- soil moisture
+\- soil contamination
+\- water quality
+\- air/ground/water pollution
+\- vegetation pressure
+\- resource depletion
+\- recovery pressure
+
+Output required:
+1\. Simple formulas for one simulation tick.
+2\. Pseudocode for update order.
+3\. Edge cases.
+4\. Values that should be configurable.
+5\. Safety caps so values stay between 0 and 100\.
+6\. Explanation simple enough to turn into Java classes.
+
+Do not write Minecraft block-changing code yet.
+
+79\. Daily Local AI Working Method
+
+Use this method every coding session.
+
+Step 1:
+Use Qwen3.6-27B for planning the next 3 to 5 tiny tasks.
+
+Prompt:
+MODEL: Qwen3.6-27B
+
+Given the current Living World project state below, choose the next 3 to 5 safest tasks.
+
+Current state:
+\[PASTE WHAT EXISTS\]
+
+Rules:
+\- Ecosystem-only mod.
+\- No NPCs, factions, settlements, roads, or wildlife simulation.
+\- Core simulation remains plain Java.
+\- Minecraft/NeoForge imports stay in platform, integration, or command packages.
+\- Each task must be completable by Qwen3.5-9B in one file or one test file.
+
+Output:
+For each task give:
+\- task name
+\- target model
+\- file path
+\- exact prompt to give Qwen3.5-9B
+\- tests required
+\- definition of done
+
+Step 2:
+Give one task at a time to Qwen3.5-9B.
+
+Step 3:
+Run build/tests.
+
+Step 4:
+If build fails, give the exact error to Qwen3.5-9B once.
+
+Repair prompt:
+MODEL: Qwen3.5-9B
+
+The previous code failed to compile.
+
+Error:
+\[PASTE ERROR\]
+
+Relevant files:
+\[PASTE FILES\]
+
+Fix only the error.
+Do not rewrite unrelated code.
+Do not add new systems.
+Return the corrected file only.
+
+Step 5:
+If the second 9B attempt fails, escalate to Qwen3.6-27B.
+
+Escalation prompt:
+MODEL: Qwen3.6-27B
+
+Qwen3.5-9B failed twice to fix this issue.
+
+Goal:
+\[PASTE TASK GOAL\]
+
+Error:
+\[PASTE ERROR\]
+
+Files:
+\[PASTE RELEVANT FILES\]
+
+Find the root cause and provide the smallest safe fix.
+Do not redesign the system unless the design is the root cause.
+Do not add unrelated features.
+
+Output:
+\- root cause
+\- corrected code
+\- why the fix works
+\- any follow-up test needed
+
+Step 6:
+After every successful task, ask Qwen3.6-27B to review the milestone when enough files exist.
+
+80\. Prompt Discipline Rules
+
+These rules are mandatory when working with local AI.
+
+Rule 1:
+Never ask a 9B model to build a whole subsystem.
+
+Rule 2:
+Never give vague prompts such as "make the ecosystem" or "fix the mod".
+
+Rule 3:
+Always include the file path.
+
+Rule 4:
+Always include the class name.
+
+Rule 5:
+Always state whether Minecraft or NeoForge imports are allowed.
+
+Rule 6:
+Always state what is out of scope.
+
+Rule 7:
+Always ask for tests when the code is plain Java.
+
+Rule 8:
+Always run tests before moving on.
+
+Rule 9:
+After two failed repair attempts by Qwen3.5-9B, escalate to Qwen3.6-27B.
+
+Rule 10:
+If Qwen3.6-27B says the task is too broad, split it into smaller files.
+
+81\. Local Model Role Summary
+
+Qwen3.5-9B role:
+\- one class
+\- one enum
+\- one record
+\- one interface
+\- one test file
+\- simple bug fix
+\- simple refactor
+\- simple documentation
+
+Qwen3.6-27B role:
+\- architecture review
+\- multi-file debugging
+\- NeoForge uncertainty
+\- save design
+\- scheduler design
+\- module boundary review
+\- version upgrade review
+\- difficult compile errors
+\- planning next batches
+
+Do not swap these roles unless necessary.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..1205924
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,47 @@
+plugins {
+ id 'java-library'
+ id 'net.neoforged.moddev' version '2.0.107'
+}
+
+group = 'com.livingworld'
+version = '0.1.0'
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
+}
+
+neoForge {
+ version = '21.1.172'
+
+ runs {
+ client {
+ client()
+ }
+
+ server {
+ server()
+ }
+ }
+
+ mods {
+ living_world {
+ sourceSet sourceSets.main
+ }
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2'
+}
+
+test {
+ useJUnitPlatform()
+}
diff --git a/build/classes/java/main/com/livingworld/LivingWorldMod.class b/build/classes/java/main/com/livingworld/LivingWorldMod.class
new file mode 100644
index 0000000..4647a95
Binary files /dev/null and b/build/classes/java/main/com/livingworld/LivingWorldMod.class differ
diff --git a/build/classes/java/main/com/livingworld/bootstrap/LivingWorldBootstrap.class b/build/classes/java/main/com/livingworld/bootstrap/LivingWorldBootstrap.class
new file mode 100644
index 0000000..da4adb2
Binary files /dev/null and b/build/classes/java/main/com/livingworld/bootstrap/LivingWorldBootstrap.class differ
diff --git a/build/classes/java/main/com/livingworld/config/DefaultConfigService.class b/build/classes/java/main/com/livingworld/config/DefaultConfigService.class
new file mode 100644
index 0000000..c15b192
Binary files /dev/null and b/build/classes/java/main/com/livingworld/config/DefaultConfigService.class differ
diff --git a/build/classes/java/main/com/livingworld/config/SimulationConfig.class b/build/classes/java/main/com/livingworld/config/SimulationConfig.class
new file mode 100644
index 0000000..f72ed59
Binary files /dev/null and b/build/classes/java/main/com/livingworld/config/SimulationConfig.class differ
diff --git a/build/classes/java/main/com/livingworld/core/LivingWorldConstants.class b/build/classes/java/main/com/livingworld/core/LivingWorldConstants.class
new file mode 100644
index 0000000..043432d
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/LivingWorldConstants.class differ
diff --git a/build/classes/java/main/com/livingworld/core/services/ConfigService.class b/build/classes/java/main/com/livingworld/core/services/ConfigService.class
new file mode 100644
index 0000000..be797df
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/services/ConfigService.class differ
diff --git a/build/classes/java/main/com/livingworld/core/services/CoreServices.class b/build/classes/java/main/com/livingworld/core/services/CoreServices.class
new file mode 100644
index 0000000..658d8e3
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/services/CoreServices.class differ
diff --git a/build/classes/java/main/com/livingworld/core/services/ServiceKey.class b/build/classes/java/main/com/livingworld/core/services/ServiceKey.class
new file mode 100644
index 0000000..babaf1c
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/services/ServiceKey.class differ
diff --git a/build/classes/java/main/com/livingworld/core/services/ServiceRegistry.class b/build/classes/java/main/com/livingworld/core/services/ServiceRegistry.class
new file mode 100644
index 0000000..731fd30
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/services/ServiceRegistry.class differ
diff --git a/build/classes/java/main/com/livingworld/core/services/TimeService.class b/build/classes/java/main/com/livingworld/core/services/TimeService.class
new file mode 100644
index 0000000..af82fe9
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/services/TimeService.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/DefaultTimeService.class b/build/classes/java/main/com/livingworld/core/simulation/DefaultTimeService.class
new file mode 100644
index 0000000..859446a
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/DefaultTimeService.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/LivingWorldCalendar.class b/build/classes/java/main/com/livingworld/core/simulation/LivingWorldCalendar.class
new file mode 100644
index 0000000..ee04ba7
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/LivingWorldCalendar.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/PersistenceService.class b/build/classes/java/main/com/livingworld/core/simulation/PersistenceService.class
new file mode 100644
index 0000000..e162aaf
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/PersistenceService.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/RegionManager.class b/build/classes/java/main/com/livingworld/core/simulation/RegionManager.class
new file mode 100644
index 0000000..70db7ee
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/RegionManager.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/RegionPriorityCalculator.class b/build/classes/java/main/com/livingworld/core/simulation/RegionPriorityCalculator.class
new file mode 100644
index 0000000..0017408
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/RegionPriorityCalculator.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/RegionUpdateJob.class b/build/classes/java/main/com/livingworld/core/simulation/RegionUpdateJob.class
new file mode 100644
index 0000000..31649ae
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/RegionUpdateJob.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/SimulationManager.class b/build/classes/java/main/com/livingworld/core/simulation/SimulationManager.class
new file mode 100644
index 0000000..474bc8d
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/SimulationManager.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/SimulationProfiler.class b/build/classes/java/main/com/livingworld/core/simulation/SimulationProfiler.class
new file mode 100644
index 0000000..3ada266
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/SimulationProfiler.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler$TestSuggestions.class b/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler$TestSuggestions.class
new file mode 100644
index 0000000..bde38c0
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler$TestSuggestions.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler.class b/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler.class
new file mode 100644
index 0000000..2559962
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/SimulationScheduler.class differ
diff --git a/build/classes/java/main/com/livingworld/core/simulation/UpdateReason.class b/build/classes/java/main/com/livingworld/core/simulation/UpdateReason.class
new file mode 100644
index 0000000..ba27a56
Binary files /dev/null and b/build/classes/java/main/com/livingworld/core/simulation/UpdateReason.class differ
diff --git a/build/classes/java/main/com/livingworld/data/serialization/PersistenceReader.class b/build/classes/java/main/com/livingworld/data/serialization/PersistenceReader.class
new file mode 100644
index 0000000..2f6e719
Binary files /dev/null and b/build/classes/java/main/com/livingworld/data/serialization/PersistenceReader.class differ
diff --git a/build/classes/java/main/com/livingworld/data/serialization/PersistenceWriter.class b/build/classes/java/main/com/livingworld/data/serialization/PersistenceWriter.class
new file mode 100644
index 0000000..79a3d8f
Binary files /dev/null and b/build/classes/java/main/com/livingworld/data/serialization/PersistenceWriter.class differ
diff --git a/build/classes/java/main/com/livingworld/debug/DiagnosticCategory.class b/build/classes/java/main/com/livingworld/debug/DiagnosticCategory.class
new file mode 100644
index 0000000..91c8a90
Binary files /dev/null and b/build/classes/java/main/com/livingworld/debug/DiagnosticCategory.class differ
diff --git a/build/classes/java/main/com/livingworld/debug/LivingWorldLogger.class b/build/classes/java/main/com/livingworld/debug/LivingWorldLogger.class
new file mode 100644
index 0000000..9fd64fa
Binary files /dev/null and b/build/classes/java/main/com/livingworld/debug/LivingWorldLogger.class differ
diff --git a/build/classes/java/main/com/livingworld/events/BaseLivingWorldEvent.class b/build/classes/java/main/com/livingworld/events/BaseLivingWorldEvent.class
new file mode 100644
index 0000000..a1b048b
Binary files /dev/null and b/build/classes/java/main/com/livingworld/events/BaseLivingWorldEvent.class differ
diff --git a/build/classes/java/main/com/livingworld/events/LivingWorldEvent.class b/build/classes/java/main/com/livingworld/events/LivingWorldEvent.class
new file mode 100644
index 0000000..3561283
Binary files /dev/null and b/build/classes/java/main/com/livingworld/events/LivingWorldEvent.class differ
diff --git a/build/classes/java/main/com/livingworld/events/LivingWorldEventBus.class b/build/classes/java/main/com/livingworld/events/LivingWorldEventBus.class
new file mode 100644
index 0000000..13efda6
Binary files /dev/null and b/build/classes/java/main/com/livingworld/events/LivingWorldEventBus.class differ
diff --git a/build/classes/java/main/com/livingworld/events/LivingWorldEventListener.class b/build/classes/java/main/com/livingworld/events/LivingWorldEventListener.class
new file mode 100644
index 0000000..dabfb99
Binary files /dev/null and b/build/classes/java/main/com/livingworld/events/LivingWorldEventListener.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/HistoryRecord.class b/build/classes/java/main/com/livingworld/modules/HistoryRecord.class
new file mode 100644
index 0000000..3b5e709
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/HistoryRecord.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/ModuleContext.class b/build/classes/java/main/com/livingworld/modules/ModuleContext.class
new file mode 100644
index 0000000..3a196b4
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/ModuleContext.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/ModuleMetadata.class b/build/classes/java/main/com/livingworld/modules/ModuleMetadata.class
new file mode 100644
index 0000000..bfeecbc
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/ModuleMetadata.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/ModuleRegistry.class b/build/classes/java/main/com/livingworld/modules/ModuleRegistry.class
new file mode 100644
index 0000000..dfcc5f7
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/ModuleRegistry.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/ModuleUpdateResult.class b/build/classes/java/main/com/livingworld/modules/ModuleUpdateResult.class
new file mode 100644
index 0000000..58e9e76
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/ModuleUpdateResult.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/RegionUpdateContext.class b/build/classes/java/main/com/livingworld/modules/RegionUpdateContext.class
new file mode 100644
index 0000000..261144a
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/RegionUpdateContext.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/ServerContext.class b/build/classes/java/main/com/livingworld/modules/ServerContext.class
new file mode 100644
index 0000000..562faba
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/ServerContext.class differ
diff --git a/build/classes/java/main/com/livingworld/modules/SimulationModule.class b/build/classes/java/main/com/livingworld/modules/SimulationModule.class
new file mode 100644
index 0000000..a433777
Binary files /dev/null and b/build/classes/java/main/com/livingworld/modules/SimulationModule.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/Region.class b/build/classes/java/main/com/livingworld/regions/Region.class
new file mode 100644
index 0000000..f899d8e
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/Region.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionCoordinate.class b/build/classes/java/main/com/livingworld/regions/RegionCoordinate.class
new file mode 100644
index 0000000..610343a
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionCoordinate.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionFactory.class b/build/classes/java/main/com/livingworld/regions/RegionFactory.class
new file mode 100644
index 0000000..e2d3706
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionFactory.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionFlags.class b/build/classes/java/main/com/livingworld/regions/RegionFlags.class
new file mode 100644
index 0000000..2a26cd5
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionFlags.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionLifecycleController.class b/build/classes/java/main/com/livingworld/regions/RegionLifecycleController.class
new file mode 100644
index 0000000..7892a52
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionLifecycleController.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionLifecycleState.class b/build/classes/java/main/com/livingworld/regions/RegionLifecycleState.class
new file mode 100644
index 0000000..8e99154
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionLifecycleState.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionMetrics.class b/build/classes/java/main/com/livingworld/regions/RegionMetrics.class
new file mode 100644
index 0000000..7013dfc
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionMetrics.class differ
diff --git a/build/classes/java/main/com/livingworld/regions/RegionModuleData.class b/build/classes/java/main/com/livingworld/regions/RegionModuleData.class
new file mode 100644
index 0000000..c083b39
Binary files /dev/null and b/build/classes/java/main/com/livingworld/regions/RegionModuleData.class differ
diff --git a/build/classes/java/test/com/livingworld/config/SimulationConfigTest$DefaultValues.class b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$DefaultValues.class
new file mode 100644
index 0000000..c0190ea
Binary files /dev/null and b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$DefaultValues.class differ
diff --git a/build/classes/java/test/com/livingworld/config/SimulationConfigTest$InvalidValues.class b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$InvalidValues.class
new file mode 100644
index 0000000..2f4663e
Binary files /dev/null and b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$InvalidValues.class differ
diff --git a/build/classes/java/test/com/livingworld/config/SimulationConfigTest$Setters.class b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$Setters.class
new file mode 100644
index 0000000..f25c7ad
Binary files /dev/null and b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$Setters.class differ
diff --git a/build/classes/java/test/com/livingworld/config/SimulationConfigTest$ValidValues.class b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$ValidValues.class
new file mode 100644
index 0000000..1597561
Binary files /dev/null and b/build/classes/java/test/com/livingworld/config/SimulationConfigTest$ValidValues.class differ
diff --git a/build/classes/java/test/com/livingworld/config/SimulationConfigTest.class b/build/classes/java/test/com/livingworld/config/SimulationConfigTest.class
new file mode 100644
index 0000000..1b42e87
Binary files /dev/null and b/build/classes/java/test/com/livingworld/config/SimulationConfigTest.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$DuplicateRegistrationRejection.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$DuplicateRegistrationRejection.class
new file mode 100644
index 0000000..c3789d4
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$DuplicateRegistrationRejection.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$GetMissingThrows.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$GetMissingThrows.class
new file mode 100644
index 0000000..b513b74
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$GetMissingThrows.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$LockMechanism.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$LockMechanism.class
new file mode 100644
index 0000000..b78c353
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$LockMechanism.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$NullArgumentValidation.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$NullArgumentValidation.class
new file mode 100644
index 0000000..6df1e4c
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$NullArgumentValidation.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$PlainJava.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$PlainJava.class
new file mode 100644
index 0000000..a2d55ed
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$PlainJava.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$RegistrationAndRetrieval.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$RegistrationAndRetrieval.class
new file mode 100644
index 0000000..3e19a8b
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest$RegistrationAndRetrieval.class differ
diff --git a/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest.class b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest.class
new file mode 100644
index 0000000..6d35f86
Binary files /dev/null and b/build/classes/java/test/com/livingworld/core/services/ServiceRegistryTest.class differ
diff --git a/build/classes/java/test/com/livingworld/events/LivingWorldEventBusTest.class b/build/classes/java/test/com/livingworld/events/LivingWorldEventBusTest.class
new file mode 100644
index 0000000..e100f48
Binary files /dev/null and b/build/classes/java/test/com/livingworld/events/LivingWorldEventBusTest.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$CenterBlockMethods.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$CenterBlockMethods.class
new file mode 100644
index 0000000..401ee1d
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$CenterBlockMethods.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ChunkBoundaryMethods.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ChunkBoundaryMethods.class
new file mode 100644
index 0000000..c119f9e
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ChunkBoundaryMethods.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$DimensionIdValidation.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$DimensionIdValidation.class
new file mode 100644
index 0000000..42221ed
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$DimensionIdValidation.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromBlockMapping.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromBlockMapping.class
new file mode 100644
index 0000000..e20ee06
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromBlockMapping.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromChunkMapping.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromChunkMapping.class
new file mode 100644
index 0000000..be5b5f8
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$FromChunkMapping.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$HashMapKeyTests.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$HashMapKeyTests.class
new file mode 100644
index 0000000..2100757
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$HashMapKeyTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$RegionSizeValidation.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$RegionSizeValidation.class
new file mode 100644
index 0000000..490d82a
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$RegionSizeValidation.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$StableIdTests.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$StableIdTests.class
new file mode 100644
index 0000000..4178428
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$StableIdTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ToStringTests.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ToStringTests.class
new file mode 100644
index 0000000..7271e65
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest$ToStringTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest.class b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest.class
new file mode 100644
index 0000000..3a9c743
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionCoordinateTest.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFactoryTest.class b/build/classes/java/test/com/livingworld/regions/RegionFactoryTest.class
new file mode 100644
index 0000000..771c951
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFactoryTest.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ClearTransientFlagTests.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ClearTransientFlagTests.class
new file mode 100644
index 0000000..6db3f59
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ClearTransientFlagTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$CopyTests.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$CopyTests.class
new file mode 100644
index 0000000..4e583c5
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$CopyTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$DefaultValues.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$DefaultValues.class
new file mode 100644
index 0000000..6b43b4e
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$DefaultValues.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$GetterSetterTests.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$GetterSetterTests.class
new file mode 100644
index 0000000..c3e952b
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$GetterSetterTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ToStringTests.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ToStringTests.class
new file mode 100644
index 0000000..0420169
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest$ToStringTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionFlagsTest.class b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest.class
new file mode 100644
index 0000000..45a0c72
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionFlagsTest.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$AllowedTransitions.class b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$AllowedTransitions.class
new file mode 100644
index 0000000..3ff6ded
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$AllowedTransitions.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$DisallowedTransitions.class b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$DisallowedTransitions.class
new file mode 100644
index 0000000..fbb44d9
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$DisallowedTransitions.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$NullHandling.class b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$NullHandling.class
new file mode 100644
index 0000000..9cdb361
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$NullHandling.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$TransitionSideEffects.class b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$TransitionSideEffects.class
new file mode 100644
index 0000000..2c42110
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest$TransitionSideEffects.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest.class b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest.class
new file mode 100644
index 0000000..f301a15
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionLifecycleControllerTest.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ApplyDeltaTests.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ApplyDeltaTests.class
new file mode 100644
index 0000000..d90e83a
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ApplyDeltaTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ConstantsTests.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ConstantsTests.class
new file mode 100644
index 0000000..9bbb8c6
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ConstantsTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$CopyTests.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$CopyTests.class
new file mode 100644
index 0000000..c33be5c
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$CopyTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$DefaultValues.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$DefaultValues.class
new file mode 100644
index 0000000..9f9f754
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$DefaultValues.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$GetterSetterClamping.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$GetterSetterClamping.class
new file mode 100644
index 0000000..d647963
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$GetterSetterClamping.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$NormalizeTests.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$NormalizeTests.class
new file mode 100644
index 0000000..d1e232b
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$NormalizeTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ToStringTests.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ToStringTests.class
new file mode 100644
index 0000000..ca82919
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest$ToStringTests.class differ
diff --git a/build/classes/java/test/com/livingworld/regions/RegionMetricsTest.class b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest.class
new file mode 100644
index 0000000..0792259
Binary files /dev/null and b/build/classes/java/test/com/livingworld/regions/RegionMetricsTest.class differ
diff --git a/build/moddev/artifacts/neoforge-21.1.172-client-extra-aka-minecraft-resources.jar b/build/moddev/artifacts/neoforge-21.1.172-client-extra-aka-minecraft-resources.jar
new file mode 100644
index 0000000..b26c422
Binary files /dev/null and b/build/moddev/artifacts/neoforge-21.1.172-client-extra-aka-minecraft-resources.jar differ
diff --git a/build/moddev/artifacts/neoforge-21.1.172-merged.jar b/build/moddev/artifacts/neoforge-21.1.172-merged.jar
new file mode 100644
index 0000000..5bcdf0a
Binary files /dev/null and b/build/moddev/artifacts/neoforge-21.1.172-merged.jar differ
diff --git a/build/moddev/artifacts/neoforge-21.1.172-sources.jar b/build/moddev/artifacts/neoforge-21.1.172-sources.jar
new file mode 100644
index 0000000..514786b
Binary files /dev/null and b/build/moddev/artifacts/neoforge-21.1.172-sources.jar differ
diff --git a/build/moddev/artifacts/neoforge-21.1.172.jar b/build/moddev/artifacts/neoforge-21.1.172.jar
new file mode 100644
index 0000000..4796b2d
Binary files /dev/null and b/build/moddev/artifacts/neoforge-21.1.172.jar differ
diff --git a/build/reports/problems/problems-report.html b/build/reports/problems/problems-report.html
new file mode 100644
index 0000000..17a27a4
--- /dev/null
+++ b/build/reports/problems/problems-report.html
@@ -0,0 +1,666 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Gradle Configuration Cache
+
+
+
+
+
+
org.opentest4j.AssertionFailedError: expected: <1> but was: <0>
+ at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
+ at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
+ at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
+ at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:150)
+ at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:145)
+ at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:531)
+ at com.livingworld.events.LivingWorldEventBusTest.getPublishedEventCountIncrementsOnPublish(LivingWorldEventBusTest.java:114)
+ at java.base/java.lang.reflect.Method.invoke(Method.java:580)
+ at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
+ at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
+
+ * This class contains only mod loader wiring. All simulation logic is
+ * delegated to the bootstrap system and core services.
+ */
+@Mod(LivingWorldConstants.MOD_ID)
+public class LivingWorldMod {
+
+ public static final String MOD_ID = LivingWorldConstants.MOD_ID;
+
+ public LivingWorldMod(IEventBus eventBus) {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "Living World mod starting...");
+
+ // Delegate startup work to the bootstrap system.
+ new LivingWorldBootstrap().initialize();
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "Living World Bootstrap initialized successfully.");
+ }
+}
diff --git a/src/main/java/com/livingworld/api/package-info.java b/src/main/java/com/livingworld/api/package-info.java
new file mode 100644
index 0000000..fdbcde3
--- /dev/null
+++ b/src/main/java/com/livingworld/api/package-info.java
@@ -0,0 +1,2 @@
+/** Living World API package — public interfaces and utilities. */
+package com.livingworld.api;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java
new file mode 100644
index 0000000..2bc0eb1
--- /dev/null
+++ b/src/main/java/com/livingworld/bootstrap/LivingWorldBootstrap.java
@@ -0,0 +1,48 @@
+package com.livingworld.bootstrap;
+
+import com.livingworld.debug.DiagnosticCategory;
+import com.livingworld.debug.LivingWorldLogger;
+
+/**
+ * Bootstrap class for Living World mod startup lifecycle.
+ *
+ * Each method logs its lifecycle stage. No gameplay logic, region/ecosystem,
+ * or persistence systems are implemented yet.
+ */
+public class LivingWorldBootstrap {
+
+ /**
+ * Called once during mod construction.
+ */
+ public void initialize() {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "initialize — mod bootstrap initialized.");
+ }
+
+ /**
+ * Called during common (dedicated & integrated server) setup phase.
+ */
+ public void onCommonSetup() {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "onCommonSetup — common setup phase reached.");
+ }
+
+ /**
+ * Called when the server is starting.
+ */
+ public void onServerStarting() {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "onServerStarting — server starting.");
+ }
+
+ /**
+ * Called when the server has finished starting.
+ */
+ public void onServerStarted() {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "onServerStarted — server started.");
+ }
+
+ /**
+ * Called when the server is stopping.
+ */
+ public void onServerStopping() {
+ LivingWorldLogger.info(DiagnosticCategory.BOOTSTRAP, "onServerStopping — server stopping.");
+ }
+}
diff --git a/src/main/java/com/livingworld/bootstrap/package-info.java b/src/main/java/com/livingworld/bootstrap/package-info.java
new file mode 100644
index 0000000..a8cf2eb
--- /dev/null
+++ b/src/main/java/com/livingworld/bootstrap/package-info.java
@@ -0,0 +1,2 @@
+/** Bootstrap package — mod initialization and lifecycle wiring. */
+package com.livingworld.bootstrap;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/commands/package-info.java b/src/main/java/com/livingworld/commands/package-info.java
new file mode 100644
index 0000000..245c5d2
--- /dev/null
+++ b/src/main/java/com/livingworld/commands/package-info.java
@@ -0,0 +1,2 @@
+/** Commands package — mod command definitions. */
+package com.livingworld.commands;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/config/DefaultConfigService.java b/src/main/java/com/livingworld/config/DefaultConfigService.java
new file mode 100644
index 0000000..ddb836f
--- /dev/null
+++ b/src/main/java/com/livingworld/config/DefaultConfigService.java
@@ -0,0 +1,60 @@
+package com.livingworld.config;
+
+import com.livingworld.core.services.ConfigService;
+import com.livingworld.debug.DiagnosticCategory;
+import com.livingworld.debug.LivingWorldLogger;
+
+/**
+ * Default implementation of {@link ConfigService}.
+ *
+ *
Holds a single {@link SimulationConfig} instance. The constructor creates
+ * a fresh default configuration and validates it immediately so that invalid
+ * defaults are caught at startup rather than at runtime.
+ */
+public class DefaultConfigService implements ConfigService {
+
+ private SimulationConfig config;
+
+ /**
+ * Creates a new service with default simulation settings.
+ *
+ * @throws RuntimeException if the default configuration fails validation
+ */
+ public DefaultConfigService() {
+ this.config = new SimulationConfig();
+ validate(); // validates and logs success
+ }
+
+ @Override
+ public SimulationConfig getSimulationConfig() {
+ return config;
+ }
+
+ /**
+ * Reloads configuration by creating a fresh default {@link SimulationConfig}
+ * and revalidating it.
+ */
+ @Override
+ public void reload() {
+ this.config = new SimulationConfig();
+ validate(); // validates and logs success
+ }
+
+ /**
+ * Validates the current configuration by delegating to
+ * {@link SimulationConfig#validate()}. On success logs an informational
+ * message via {@link LivingWorldLogger}.
+ *
+ * @throws RuntimeException if validation fails (wraps {@link IllegalArgumentException})
+ */
+ @Override
+ public void validate() {
+ try {
+ config.validate();
+ LivingWorldLogger.info(DiagnosticCategory.CONFIG, "Configuration validated successfully: " + config);
+ } catch (IllegalArgumentException e) {
+ LivingWorldLogger.error(DiagnosticCategory.CONFIG, "Configuration validation failed", e);
+ throw new RuntimeException("Configuration validation failed", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/config/SimulationConfig.java b/src/main/java/com/livingworld/config/SimulationConfig.java
new file mode 100644
index 0000000..0329465
--- /dev/null
+++ b/src/main/java/com/livingworld/config/SimulationConfig.java
@@ -0,0 +1,166 @@
+package com.livingworld.config;
+
+/**
+ * Configuration class for simulation parameters.
+ *
+ * This class holds plain integer and boolean fields that control how the
+ * living world simulation behaves at runtime. It is intentionally free of
+ * any Minecraft or NeoForge dependencies so it can be instantiated in pure
+ * JUnit tests.
+ */
+public final class SimulationConfig {
+
+ // ------------------------------------------------------------------
+ // Field defaults
+ // ------------------------------------------------------------------
+
+ /** Size of a region in chunks (must be >= 1). */
+ private int regionSizeChunks = 8;
+
+ /** Interval between simulation cycles, in game ticks (must be >= 1). */
+ private int simulationIntervalTicks = 100;
+
+ /** Maximum number of regions processed per cycle (must be >= 1). */
+ private int maxRegionsPerCycle = 50;
+
+ /** Maximum time budget for a single cycle in milliseconds (must be >= 1). */
+ private int maxMillisecondsPerCycle = 25;
+
+ /** Emergency stop threshold when simulation is overrunning (>= maxMillisecondsPerCycle). */
+ private int emergencyStopMilliseconds = 40;
+
+ /** Enable diagnostic / debug commands. */
+ private boolean enableDebugCommands = true;
+
+ /** Enable the built-in profiler. */
+ private boolean enableProfiler = true;
+
+ // ------------------------------------------------------------------
+ // Constructors
+ // ------------------------------------------------------------------
+
+ /** Default constructor – uses all default values. */
+ public SimulationConfig() {
+ // Intentionally empty; fields are initialised at declaration.
+ }
+
+ // ------------------------------------------------------------------
+ // Getters
+ // ------------------------------------------------------------------
+
+ public int getRegionSizeChunks() {
+ return regionSizeChunks;
+ }
+
+ public int getSimulationIntervalTicks() {
+ return simulationIntervalTicks;
+ }
+
+ public int getMaxRegionsPerCycle() {
+ return maxRegionsPerCycle;
+ }
+
+ public int getMaxMillisecondsPerCycle() {
+ return maxMillisecondsPerCycle;
+ }
+
+ public int getEmergencyStopMilliseconds() {
+ return emergencyStopMilliseconds;
+ }
+
+ public boolean isEnableDebugCommands() {
+ return enableDebugCommands;
+ }
+
+ public boolean isEnableProfiler() {
+ return enableProfiler;
+ }
+
+ // ------------------------------------------------------------------
+ // Setters (package-private for testability)
+ // ------------------------------------------------------------------
+
+ public void setRegionSizeChunks(final int regionSizeChunks) {
+ this.regionSizeChunks = regionSizeChunks;
+ }
+
+ public void setSimulationIntervalTicks(final int simulationIntervalTicks) {
+ this.simulationIntervalTicks = simulationIntervalTicks;
+ }
+
+ public void setMaxRegionsPerCycle(final int maxRegionsPerCycle) {
+ this.maxRegionsPerCycle = maxRegionsPerCycle;
+ }
+
+ public void setMaxMillisecondsPerCycle(final int maxMillisecondsPerCycle) {
+ this.maxMillisecondsPerCycle = maxMillisecondsPerCycle;
+ }
+
+ public void setEmergencyStopMilliseconds(final int emergencyStopMilliseconds) {
+ this.emergencyStopMilliseconds = emergencyStopMilliseconds;
+ }
+
+ public void setEnableDebugCommands(final boolean enableDebugCommands) {
+ this.enableDebugCommands = enableDebugCommands;
+ }
+
+ public void setEnableProfiler(final boolean enableProfiler) {
+ this.enableProfiler = enableProfiler;
+ }
+
+ // ------------------------------------------------------------------
+ // Validation
+ // ------------------------------------------------------------------
+
+ /**
+ * Validates every field against its constraints. Throws
+ * {@link IllegalArgumentException} with a descriptive message if any
+ * constraint is violated.
+ *
+ * @throws IllegalArgumentException if validation fails
+ */
+ public void validate() {
+ if (regionSizeChunks < 1) {
+ throw new IllegalArgumentException(
+ "regionSizeChunks must be >= 1, got: " + regionSizeChunks);
+ }
+
+ if (simulationIntervalTicks < 1) {
+ throw new IllegalArgumentException(
+ "simulationIntervalTicks must be >= 1, got: " + simulationIntervalTicks);
+ }
+
+ if (maxRegionsPerCycle < 1) {
+ throw new IllegalArgumentException(
+ "maxRegionsPerCycle must be >= 1, got: " + maxRegionsPerCycle);
+ }
+
+ if (maxMillisecondsPerCycle < 1) {
+ throw new IllegalArgumentException(
+ "maxMillisecondsPerCycle must be >= 1, got: " + maxMillisecondsPerCycle);
+ }
+
+ if (emergencyStopMilliseconds < maxMillisecondsPerCycle) {
+ throw new IllegalArgumentException(
+ "emergencyStopMilliseconds (" + emergencyStopMilliseconds
+ + ") must be >= maxMillisecondsPerCycle (" + maxMillisecondsPerCycle + ")");
+ }
+ }
+
+ // ------------------------------------------------------------------
+ // Utility / Debug
+ // ------------------------------------------------------------------
+
+ @Override
+ public String toString() {
+ return "SimulationConfig{"
+ + "regionSizeChunks=" + regionSizeChunks
+ + ", simulationIntervalTicks=" + simulationIntervalTicks
+ + ", maxRegionsPerCycle=" + maxRegionsPerCycle
+ + ", maxMillisecondsPerCycle=" + maxMillisecondsPerCycle
+ + ", emergencyStopMilliseconds=" + emergencyStopMilliseconds
+ + ", enableDebugCommands=" + enableDebugCommands
+ + ", enableProfiler=" + enableProfiler
+ + '}';
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/config/package-info.java b/src/main/java/com/livingworld/config/package-info.java
new file mode 100644
index 0000000..37a7046
--- /dev/null
+++ b/src/main/java/com/livingworld/config/package-info.java
@@ -0,0 +1,2 @@
+/** Configuration package — mod configuration classes and settings. */
+package com.livingworld.config;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/LivingWorldConstants.java b/src/main/java/com/livingworld/core/LivingWorldConstants.java
new file mode 100644
index 0000000..158af9b
--- /dev/null
+++ b/src/main/java/com/livingworld/core/LivingWorldConstants.java
@@ -0,0 +1,26 @@
+package com.livingworld.core;
+
+/**
+ * Constants used throughout the Living World mod.
+ */
+public final class LivingWorldConstants {
+
+ private LivingWorldConstants() {
+ // Utility class — no instantiation.
+ }
+
+ /** The unique mod identifier string. */
+ public static final String MOD_ID = "livingworld";
+
+ /** Human-readable mod name displayed in the mod list. */
+ public static final String MOD_NAME = "Living World";
+
+ /** Current schema version for data persistence and migration tracking. */
+ public static final int CURRENT_CORE_SCHEMA_VERSION = 1;
+
+ /** Default region size measured in chunks (8x8 chunks). */
+ public static final int DEFAULT_REGION_SIZE_CHUNKS = 8;
+
+ /** Default simulation update interval in ticks (100 ticks ≈ 5 seconds). */
+ public static final int DEFAULT_SIMULATION_INTERVAL_TICKS = 100;
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/lifecycle/package-info.java b/src/main/java/com/livingworld/core/lifecycle/package-info.java
new file mode 100644
index 0000000..b969d82
--- /dev/null
+++ b/src/main/java/com/livingworld/core/lifecycle/package-info.java
@@ -0,0 +1,2 @@
+/** Core lifecycle package — mod event lifecycle management. */
+package com.livingworld.core.lifecycle;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/package-info.java b/src/main/java/com/livingworld/core/package-info.java
new file mode 100644
index 0000000..2370a3c
--- /dev/null
+++ b/src/main/java/com/livingworld/core/package-info.java
@@ -0,0 +1,2 @@
+/** Core package — fundamental mod infrastructure and shared utilities. */
+package com.livingworld.core;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/registry/package-info.java b/src/main/java/com/livingworld/core/registry/package-info.java
new file mode 100644
index 0000000..c69e538
--- /dev/null
+++ b/src/main/java/com/livingworld/core/registry/package-info.java
@@ -0,0 +1,2 @@
+/** Core registry package — block, item, and entity registration utilities. */
+package com.livingworld.core.registry;
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/services/ConfigService.java b/src/main/java/com/livingworld/core/services/ConfigService.java
new file mode 100644
index 0000000..35f7d07
--- /dev/null
+++ b/src/main/java/com/livingworld/core/services/ConfigService.java
@@ -0,0 +1,39 @@
+package com.livingworld.core.services;
+
+import com.livingworld.config.SimulationConfig;
+
+/**
+ * Service interface for managing simulation configuration.
+ *
+ * Implementations of this interface provide access to the current
+ * {@link SimulationConfig}, support reloading from external sources,
+ * and validate that all values are within acceptable ranges.
+ */
+public interface ConfigService {
+
+ /**
+ * Returns the current simulation configuration.
+ *
+ * @return the active {@link SimulationConfig} instance
+ */
+ SimulationConfig getSimulationConfig();
+
+ /**
+ * Reloads configuration from its external source (e.g., config file, mod settings).
+ * Implementations should handle I/O and deserialization internally.
+ */
+ void reload();
+
+ /**
+ * Validates the current configuration by delegating to {@link SimulationConfig#validate()}.
+ *
+ * @throws RuntimeException if validation fails (wraps {@link IllegalArgumentException})
+ */
+ default void validate() {
+ try {
+ getSimulationConfig().validate();
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException("Configuration validation failed", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/core/services/CoreServices.java b/src/main/java/com/livingworld/core/services/CoreServices.java
new file mode 100644
index 0000000..cc2e8ca
--- /dev/null
+++ b/src/main/java/com/livingworld/core/services/CoreServices.java
@@ -0,0 +1,69 @@
+package com.livingworld.core.services;
+
+import com.livingworld.core.simulation.PersistenceService;
+import com.livingworld.core.simulation.RegionManager;
+import com.livingworld.core.simulation.SimulationManager;
+import com.livingworld.events.LivingWorldEventBus;
+import com.livingworld.modules.ModuleRegistry;
+
+/**
+ * Central list of built-in service keys for the Living World core services.
+ *
+ *
This class is a final utility class with a private constructor. Each field
+ * defines a {@link ServiceKey} that will be used to register and retrieve core
+ * services once their implementations exist.
+ *
+ *
Only CONFIG can use its real type (ConfigService) since that interface already exists.
+ * All other keys currently use Object as a placeholder with TODO comments pointing to the
+ * relevant milestone where the actual service implementation will be created.
+ *
+ *
Migration Guide
+ *
As each service interface is created during its milestone, migrate its key from
+ * {@code Object} to the real type. For example:
+ *
{@code
+ * // Before (placeholder):
+ * @SuppressWarnings("unchecked")
+ * public static final ServiceKey
+ *
Benefits of typed keys: compile-time type safety, no unchecked casts in caller code,
+ * and the {@link ServiceRegistry#find(ServiceKey)} method returns {@code Optional} with
+ * the correct type.
+ */
+public final class CoreServices {
+
+ private CoreServices() {
+ // Utility class — no instantiation allowed.
+ }
+
+ /** ConfigService key — interface already exists. */
+ public static final ServiceKey CONFIG = new ServiceKey<>("config", ConfigService.class);
+
+ public static final ServiceKey REGIONS =
+ new ServiceKey<>("regions", RegionManager.class);
+
+ public static final ServiceKey SIMULATION =
+ new ServiceKey<>("simulation", SimulationManager.class);
+
+ public static final ServiceKey PERSISTENCE =
+ new ServiceKey<>("persistence", PersistenceService.class);
+
+ public static final ServiceKey EVENTS =
+ new ServiceKey<>("events", LivingWorldEventBus.class);
+
+ public static final ServiceKey MODULES =
+ new ServiceKey<>("modules", ModuleRegistry.class);
+
+ public static final ServiceKey TIME =
+ new ServiceKey<>("time", TimeService.class);
+
+ // TODO: Replace Object with DebugService when created (Milestone 15)
+ @SuppressWarnings("unchecked")
+ public static final ServiceKey
+ *
+ *
The region is validated before being returned. If validation fails,
+ * an {@link IllegalStateException} is thrown.
+ *
+ * @param coordinate the spatial position of the new region (must not be null)
+ * @param simulationTick the current simulation tick
+ * @return a valid new Region instance
+ * @throws IllegalArgumentException if coordinate is null
+ */
+ public Region createNewRegion(RegionCoordinate coordinate, long simulationTick) {
+ if (coordinate == null) {
+ throw new IllegalArgumentException("coordinate must not be null");
+ }
+
+ UUID id = UUID.randomUUID();
+ RegionLifecycleState lifecycleState = RegionLifecycleState.ACTIVE;
+ boolean dirty = true;
+ RegionFlags flags = new RegionFlags();
+ RegionMetrics metrics = RegionMetrics.defaults();
+ RegionModuleData moduleData = new RegionModuleData();
+
+ Region region = new Region(
+ id,
+ coordinate,
+ lifecycleState,
+ simulationTick,
+ simulationTick,
+ dirty,
+ flags,
+ metrics,
+ moduleData
+ );
+
+ // Validate before returning; throws IllegalStateException if invalid
+ region.validate();
+
+ return region;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/regions/RegionFlags.java b/src/main/java/com/livingworld/regions/RegionFlags.java
new file mode 100644
index 0000000..81a5f83
--- /dev/null
+++ b/src/main/java/com/livingworld/regions/RegionFlags.java
@@ -0,0 +1,162 @@
+package com.livingworld.regions;
+
+/**
+ * Boolean flags that describe the current state of a region.
+ *
+ *
This class tracks transient and persistent conditions affecting a region,
+ * such as player activity, pollution levels, soil quality, active ecosystem events,
+ * simulation force-loading, and data corruption.
+ */
+public class RegionFlags {
+
+ private boolean hasPlayerActivity;
+ private boolean hasHighPollution;
+ private boolean hasLowSoilQuality;
+ private boolean hasActiveEcosystemEvent;
+ private boolean forceLoadedBySimulation;
+ private boolean corrupted;
+
+ /**
+ * Default constructor. All flags are initialized to false.
+ */
+ public RegionFlags() {
+ // all fields default to false
+ }
+
+ // ------------------------------------------------------------------
+ // Getters and Setters
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns true if players have interacted with this region.
+ */
+ public boolean isHasPlayerActivity() {
+ return hasPlayerActivity;
+ }
+
+ /**
+ * Sets whether players have interacted with this region.
+ */
+ public void setHasPlayerActivity(boolean hasPlayerActivity) {
+ this.hasPlayerActivity = hasPlayerActivity;
+ }
+
+ /**
+ * Returns true if pollution levels in this region are high.
+ */
+ public boolean isHasHighPollution() {
+ return hasHighPollution;
+ }
+
+ /**
+ * Sets whether pollution levels are high.
+ */
+ public void setHasHighPollution(boolean hasHighPollution) {
+ this.hasHighPollution = hasHighPollution;
+ }
+
+ /**
+ * Returns true if soil quality in this region is low.
+ */
+ public boolean isHasLowSoilQuality() {
+ return hasLowSoilQuality;
+ }
+
+ /**
+ * Sets whether soil quality is low.
+ */
+ public void setHasLowSoilQuality(boolean hasLowSoilQuality) {
+ this.hasLowSoilQuality = hasLowSoilQuality;
+ }
+
+ /**
+ * Returns true if an active ecosystem event (fire, flood, etc.) is occurring.
+ */
+ public boolean isHasActiveEcosystemEvent() {
+ return hasActiveEcosystemEvent;
+ }
+
+ /**
+ * Sets whether an active ecosystem event is occurring.
+ */
+ public void setHasActiveEcosystemEvent(boolean hasActiveEcosystemEvent) {
+ this.hasActiveEcosystemEvent = hasActiveEcosystemEvent;
+ }
+
+ /**
+ * Returns true if the region is force-loaded by simulation and cannot be
+ * unloaded by normal garbage collection.
+ */
+ public boolean isForceLoadedBySimulation() {
+ return forceLoadedBySimulation;
+ }
+
+ /**
+ * Sets whether the region is force-loaded by simulation.
+ */
+ public void setForceLoadedBySimulation(boolean forceLoadedBySimulation) {
+ this.forceLoadedBySimulation = forceLoadedBySimulation;
+ }
+
+ /**
+ * Returns true if this region has corrupted or inconsistent data.
+ */
+ public boolean isCorrupted() {
+ return corrupted;
+ }
+
+ /**
+ * Sets whether this region is corrupted.
+ */
+ public void setCorrupted(boolean corrupted) {
+ this.corrupted = corrupted;
+ }
+
+ // ------------------------------------------------------------------
+ // Copy and Clear
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns a new {@link RegionFlags} instance with identical field values.
+ *
+ *
The returned instance is independent; modifying it will not affect
+ * the original flags.
Persistent flags such as {@code corrupted}, {@code hasHighPollution},
+ * {@code hasLowSoilQuality}, and {@code forceLoadedBySimulation} are preserved.
This is a plain Java utility class that provides static methods for validating
+ * and executing transitions between {@link RegionLifecycleState} values. All allowed
+ * transitions are hardcoded in an internal lookup table.
+ *
+ *
Allowed transitions:
+ *
+ *
UNLOADED → LOADING
+ *
LOADING → ACTIVE
+ *
LOADING → FAILED
+ *
ACTIVE → DIRTY
+ *
DIRTY → SAVING
+ *
SAVING → ACTIVE
+ *
SAVING → FAILED
+ *
ACTIVE → UNLOADING
+ *
UNLOADING → UNLOADED
+ *
FAILED → LOADING
+ *
+ */
+public class RegionLifecycleController {
+
+ private static final String SEPARATOR = "->";
+
+ /** Unmodifiable set of allowed transition keys in the format "FROM->TO". */
+ private static final Set ALLOWED_TRANSITIONS;
+
+ static {
+ Set table = new HashSet<>();
+ table.add("UNLOADED" + SEPARATOR + "LOADING");
+ table.add("LOADING" + SEPARATOR + "ACTIVE");
+ table.add("LOADING" + SEPARATOR + "FAILED");
+ table.add("ACTIVE" + SEPARATOR + "DIRTY");
+ table.add("DIRTY" + SEPARATOR + "SAVING");
+ table.add("SAVING" + SEPARATOR + "ACTIVE");
+ table.add("SAVING" + SEPARATOR + "FAILED");
+ table.add("ACTIVE" + SEPARATOR + "UNLOADING");
+ table.add("UNLOADING" + SEPARATOR + "UNLOADED");
+ table.add("FAILED" + SEPARATOR + "LOADING");
+ ALLOWED_TRANSITIONS = Collections.unmodifiableSet(table);
+ }
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private RegionLifecycleController() {
+ // utility class
+ }
+
+ // ------------------------------------------------------------------
+ // Transition validation
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns whether the specified transition from {@code from} to {@code to} is allowed.
+ *
+ * @param from the current lifecycle state (must not be null)
+ * @param to the target lifecycle state (must not be null)
+ * @return true if this transition is permitted
+ * @throws IllegalArgumentException if either parameter is null
+ */
+ public static boolean canTransition(RegionLifecycleState from, RegionLifecycleState to) {
+ if (from == null) {
+ throw new IllegalArgumentException("from state must not be null");
+ }
+ if (to == null) {
+ throw new IllegalArgumentException("to state must not be null");
+ }
+
+ String key = from.name() + SEPARATOR + to.name();
+ return ALLOWED_TRANSITIONS.contains(key);
+ }
+
+ // ------------------------------------------------------------------
+ // Transition execution
+ // ------------------------------------------------------------------
+
+ /**
+ * Transitions the given region to the target lifecycle state.
+ *
+ *
Validates that the transition from the region's current state to the
+ * target is allowed. If valid, updates the region's lifecycle state and marks
+ * it dirty.
+ *
+ * @param region the region to transition (must not be null)
+ * @param target the target lifecycle state (must not be null)
+ * @throws IllegalArgumentException if region or target is null
+ * @throws IllegalStateException if the transition is not allowed
+ */
+ public static void transition(Region region, RegionLifecycleState target) {
+ if (region == null) {
+ throw new IllegalArgumentException("region must not be null");
+ }
+ if (target == null) {
+ throw new IllegalArgumentException("target state must not be null");
+ }
+
+ RegionLifecycleState current = region.getLifecycleState();
+
+ if (!canTransition(current, target)) {
+ throw new IllegalStateException(
+ "Invalid lifecycle transition: " + current.name() + " -> " + target.name());
+ }
+
+ region.setLifecycleState(target);
+ region.markDirty();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/regions/RegionLifecycleState.java b/src/main/java/com/livingworld/regions/RegionLifecycleState.java
new file mode 100644
index 0000000..3b1bcb1
--- /dev/null
+++ b/src/main/java/com/livingworld/regions/RegionLifecycleState.java
@@ -0,0 +1,52 @@
+package com.livingworld.regions;
+
+/**
+ * Lifecycle states for a region in the Living World simulation.
+ *
+ *
This enum tracks the state transitions of a region as it is loaded,
+ * simulated, saved, and unloaded during gameplay.
+ */
+public enum RegionLifecycleState {
+
+ /**
+ * The region is not currently loaded in memory.
+ * No data is held; the region exists only on disk (or has never been created).
+ */
+ UNLOADED,
+
+ /**
+ * The region is being read from disk and initialized.
+ * Data structures are being constructed but the region is not yet ready for simulation.
+ */
+ LOADING,
+
+ /**
+ * The region is fully loaded and actively processing simulation ticks.
+ * Entities, blocks, and other systems within this region are updated each cycle.
+ */
+ ACTIVE,
+
+ /**
+ * The region has been modified since it was last saved.
+ * These changes must be persisted to disk before the region can be safely unloaded.
+ */
+ DIRTY,
+
+ /**
+ * The region's data is being written to disk.
+ * No modifications should occur while in this state.
+ */
+ SAVING,
+
+ /**
+ * An error occurred during loading, saving, or simulation.
+ * The region cannot continue normal operations and requires manual intervention or reset.
+ */
+ FAILED,
+
+ /**
+ * The region is being removed from memory after simulation.
+ * Data is being flushed to disk (if dirty) and internal structures are being released.
+ */
+ UNLOADING;
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/regions/RegionMetrics.java b/src/main/java/com/livingworld/regions/RegionMetrics.java
new file mode 100644
index 0000000..0084c30
--- /dev/null
+++ b/src/main/java/com/livingworld/regions/RegionMetrics.java
@@ -0,0 +1,387 @@
+package com.livingworld.regions;
+
+/**
+ * Metrics that describe the health and state of an ecosystem within a region.
+ *
+ *
All values are clamped between 0 and 100 to represent percentages or
+ * normalized scores. This class provides methods for normalizing, copying,
+ * and creating default instances.
+ */
+public class RegionMetrics {
+
+ private double ecosystemHealth;
+ private double pollutionScore;
+ private double soilQuality;
+ private double waterQuality;
+ private double vegetationPressure;
+ private double resourceDepletion;
+ private double recoveryPressure;
+
+ // ------------------------------------------------------------------
+ // Constants
+ // ------------------------------------------------------------------
+
+ /** Minimum allowed value for all metrics. */
+ public static final double MIN_VALUE = 0;
+
+ /** Maximum allowed value for all metrics. */
+ public static final double MAX_VALUE = 100;
+
+ // ------------------------------------------------------------------
+ // Default values
+ // ------------------------------------------------------------------
+
+ /** Default ecosystem health score. */
+ private static final double DEFAULT_ECOSYSTEM_HEALTH = 60;
+
+ /** Default pollution score. */
+ private static final double DEFAULT_POLLUTION_SCORE = 0;
+
+ /** Default soil quality score. */
+ private static final double DEFAULT_SOIL_QUALITY = 60;
+
+ /** Default water quality score. */
+ private static final double DEFAULT_WATER_QUALITY = 60;
+
+ /** Default vegetation pressure score. */
+ private static final double DEFAULT_VEGETATION_PRESSURE = 50;
+
+ /** Default resource depletion score. */
+ private static final double DEFAULT_RESOURCE_DEPLETION = 0;
+
+ /** Default recovery pressure score. */
+ private static final double DEFAULT_RECOVERY_PRESSURE = 50;
+
+ // ------------------------------------------------------------------
+ // Constructor
+ // ------------------------------------------------------------------
+
+ /**
+ * Default constructor. All fields are initialized to 0.
+ */
+ public RegionMetrics() {
+ // all fields default to 0.0
+ }
+
+ // ------------------------------------------------------------------
+ // Getters and Setters
+ // ------------------------------------------------------------------
+
+ /**
+ * Returns the ecosystem health score (0-100).
+ *
+ *
Higher values indicate a healthier, more balanced ecosystem.
+ */
+ public double getEcosystemHealth() {
+ return ecosystemHealth;
+ }
+
+ /**
+ * Sets the ecosystem health score.
+ *
+ *
Each field is modified by its corresponding delta value, then clamped
+ * between 0 and 100.
+ *
+ * @param ecosystemHealthDelta the change to apply to ecosystem health
+ * @param pollutionScoreDelta the change to apply to pollution score
+ * @param soilQualityDelta the change to apply to soil quality
+ * @param waterQualityDelta the change to apply to water quality
+ * @param vegetationPressureDelta the change to apply to vegetation pressure
+ * @param resourceDepletionDelta the change to apply to resource depletion
+ * @param recoveryPressureDelta the change to apply to recovery pressure
+ * @return this metrics instance for method chaining
+ */
+ public RegionMetrics applyDelta(
+ double ecosystemHealthDelta,
+ double pollutionScoreDelta,
+ double soilQualityDelta,
+ double waterQualityDelta,
+ double vegetationPressureDelta,
+ double resourceDepletionDelta,
+ double recoveryPressureDelta) {
+
+ this.ecosystemHealth = clamp(this.ecosystemHealth + ecosystemHealthDelta);
+ this.pollutionScore = clamp(this.pollutionScore + pollutionScoreDelta);
+ this.soilQuality = clamp(this.soilQuality + soilQualityDelta);
+ this.waterQuality = clamp(this.waterQuality + waterQualityDelta);
+ this.vegetationPressure = clamp(this.vegetationPressure + vegetationPressureDelta);
+ this.resourceDepletion = clamp(this.resourceDepletion + resourceDepletionDelta);
+ this.recoveryPressure = clamp(this.recoveryPressure + recoveryPressureDelta);
+
+ return this;
+ }
+
+ /**
+ * Applies a delta to the ecosystem health score and returns this instance.
+ */
+ public RegionMetrics applyEcosystemHealthDelta(double delta) {
+ this.ecosystemHealth = clamp(this.ecosystemHealth + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the pollution score and returns this instance.
+ */
+ public RegionMetrics applyPollutionScoreDelta(double delta) {
+ this.pollutionScore = clamp(this.pollutionScore + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the soil quality score and returns this instance.
+ */
+ public RegionMetrics applySoilQualityDelta(double delta) {
+ this.soilQuality = clamp(this.soilQuality + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the water quality score and returns this instance.
+ */
+ public RegionMetrics applyWaterQualityDelta(double delta) {
+ this.waterQuality = clamp(this.waterQuality + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the vegetation pressure score and returns this instance.
+ */
+ public RegionMetrics applyVegetationPressureDelta(double delta) {
+ this.vegetationPressure = clamp(this.vegetationPressure + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the resource depletion score and returns this instance.
+ */
+ public RegionMetrics applyResourceDepletionDelta(double delta) {
+ this.resourceDepletion = clamp(this.resourceDepletion + delta);
+ return this;
+ }
+
+ /**
+ * Applies a delta to the recovery pressure score and returns this instance.
+ */
+ public RegionMetrics applyRecoveryPressureDelta(double delta) {
+ this.recoveryPressure = clamp(this.recoveryPressure + delta);
+ return this;
+ }
+
+ // ------------------------------------------------------------------
+ // Normalization
+ // ------------------------------------------------------------------
+
+ /**
+ * Clamps all metric values between 0 and 100.
+ *
+ *
This method modifies the current instance in place and returns it
+ * for method chaining.
+ */
+ public RegionMetrics normalize() {
+ this.ecosystemHealth = clamp(this.ecosystemHealth);
+ this.pollutionScore = clamp(this.pollutionScore);
+ this.soilQuality = clamp(this.soilQuality);
+ this.waterQuality = clamp(this.waterQuality);
+ this.vegetationPressure = clamp(this.vegetationPressure);
+ this.resourceDepletion = clamp(this.resourceDepletion);
+ this.recoveryPressure = clamp(this.recoveryPressure);
+ return this;
+ }
+
+ // ------------------------------------------------------------------
+ // Utility Methods
+ // ------------------------------------------------------------------
+
+ /**
+ * Clamps a value between 0 and 100.
+ */
+ private static double clamp(double value) {
+ if (value < MIN_VALUE) {
+ return MIN_VALUE;
+ }
+ if (value > MAX_VALUE) {
+ return MAX_VALUE;
+ }
+ return value;
+ }
+
+ // ------------------------------------------------------------------
+ // Standard Overrides
+ // ------------------------------------------------------------------
+
+ @Override
+ public String toString() {
+ return "RegionMetrics{"
+ + "ecosystemHealth=" + ecosystemHealth
+ + ", pollutionScore=" + pollutionScore
+ + ", soilQuality=" + soilQuality
+ + ", waterQuality=" + waterQuality
+ + ", vegetationPressure=" + vegetationPressure
+ + ", resourceDepletion=" + resourceDepletion
+ + ", recoveryPressure=" + recoveryPressure
+ + "}";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/livingworld/regions/RegionModuleData.java b/src/main/java/com/livingworld/regions/RegionModuleData.java
new file mode 100644
index 0000000..c0cf87c
--- /dev/null
+++ b/src/main/java/com/livingworld/regions/RegionModuleData.java
@@ -0,0 +1,105 @@
+package com.livingworld.regions;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Stores module-specific data by module ID.
+ */
+public class RegionModuleData {
+
+ private Map moduleData;
+
+ /**
+ * Creates a new empty RegionModuleData instance.
+ */
+ public RegionModuleData() {
+ this.moduleData = new HashMap<>();
+ }
+
+ /**
+ * Associates the given data with the specified module ID.
+ *
+ * @param moduleId the module identifier (must not be null or blank)
+ * @param data the data to store (must not be null)
+ * @throws IllegalArgumentException if moduleId is null or blank
+ * @throws IllegalArgumentException if data is null
+ */
+ public void put(String moduleId, Object data) {
+ if (moduleId == null || moduleId.isBlank()) {
+ throw new IllegalArgumentException("moduleId must not be null or blank");
+ }
+ if (data == null) {
+ throw new IllegalArgumentException("Data for module '" + moduleId + "' must not be null");
+ }
+ this.moduleData.put(moduleId, data);
+ }
+
+ /**
+ * Returns the data associated with the given module ID, cast to the requested type.
+ *
+ *
If the module ID is not present or the stored data does not match the
+ * requested type, this method returns {@link Optional#empty()} instead of
+ * throwing an exception.
+ *
+ * @param moduleId the module identifier (must not be null or blank)
+ * @param type the expected type of the stored data
+ * @param the target type
+ * @return the data cast to {@code type}, or {@link Optional#empty()} if not found or type mismatch
+ */
+ @SuppressWarnings("unchecked")
+ public Optional get(String moduleId, Class type) {
+ if (moduleId == null || moduleId.isBlank()) {
+ throw new IllegalArgumentException("moduleId must not be null or blank");
+ }
+ Object value = this.moduleData.get(moduleId);
+ if (value == null) {
+ return Optional.empty();
+ }
+ if (!type.isInstance(value)) {
+ return Optional.empty();
+ }
+ return Optional.of((T) value);
+ }
+
+ /**
+ * Returns whether this instance contains data for the given module ID.
+ *
+ * @param moduleId the module identifier (must not be null or blank)
+ * @return true if data exists for the given module ID
+ * @throws IllegalArgumentException if moduleId is null or blank
+ */
+ public boolean contains(String moduleId) {
+ if (moduleId == null || moduleId.isBlank()) {
+ throw new IllegalArgumentException("moduleId must not be null or blank");
+ }
+ return this.moduleData.containsKey(moduleId);
+ }
+
+ /**
+ * Returns all module IDs currently stored.
+ *
+ * @return an unmodifiable set of module identifiers
+ */
+ public Set moduleIds() {
+ return Collections.unmodifiableSet(new HashSet<>(this.moduleData.keySet()));
+ }
+
+ /**
+ * Returns a shallow copy of this instance.
+ *
+ *
The returned {@link RegionModuleData} has its own map, but the values
+ * inside are shared references.