Files
rivencraft/docs/INSTABILITY_RUNTIME.md
T
2026-10-10 15:16:08 -04:00

5.8 KiB

Instability provider runtime (Milestone 6, issue #66)

Each new Age stores an InstabilityPlan beside its frozen Instability score. The version-1 plan contains provider IDs and levels. Selection uses the saved score rounded down to a 500-point step and the Age seed. It independently walks Legacy's basic, harsh, destructive, eating, and death decks with their audited entry costs (0, 2,500, 10,000, 15,000, 20,000), shuffling each deck deterministically before paying its weighted card costs. The source card weights and default provider costs are copied from the user's local Mystcraft 0.13.7.06 InstabilityData class. This preserves Legacy's multiple-deck behavior, but does not claim byte-for-byte reproduction of its historical Java RNG state, difficulty multiplier, config overrides, or 400-chunk block profiling delay.

The saved provider IDs are independent of installed handlers. A missing optional handler leaves its ID and level intact and is skipped at runtime. A syntactically invalid saved ID or unsupported plan version fails loading explicitly; an unknown but valid ID is preserved and logged once when encountered. Disabling instability or world mutation never rewrites a saved score or provider plan. Saves from #64 with a frozen score but no provider plan are selected once from that score and Age seed, then marked dirty for persistence. Older pre-score Ages remain neutral and inert.

From 0.5.8.11, live block profiling adds a separate effective score and provider plan once 400 Age and Overworld chunks have been sampled. The authored score/plan described above remain saved as the base; the effective provider selection can change as block abundance is observed.

The server scheduler runs only for loaded rivencraft:age/* levels with a player present and an Age definition. It uses only chunks already loaded near those players, never requests a chunk, and rotates among eligible Ages when the per-tick cap is reached. Configuration bounds the cooldown (minimum 20 ticks), active Ages, handlers and actions per Age, effective provider level, and examined loaded chunks. A handler must claim a shared action permit before each effect. A throwing handler is logged and quarantined temporarily without stopping the server. World-mutating handlers are enabled by default to match Legacy; the setting can still disable them. These limits are guards for upcoming providers, not proof that an arbitrary third-party handler cannot misuse world APIs.

Issue #67 registers the non-world-mutating potion handlers; see status-effect policy. Issue #68 adds configurable colored decay, enabled by default for newly generated configs. Issue #69 adds lightning and explosions; issue #70 adds meteor, scorching, and erosion. The runtime rejects Overworld and preview dimension IDs; its player requirement excludes unattended snapshot chunk loaders. GameTests cover deterministic selection, save round-trips, score-only migration, unknown IDs, scope checks, fair admission, and action caps.

Issue #72 adds server config, per-Age controls, diagnostics, and book feedback. Its operator controls never rewrite a frozen score or provider plan.

The Milestone 6 regression and migration record maps the automated acceptance checks and lists the in-game restart, optional-mod, and hazard-visual scenarios still requiring verification.

Lightning and explosions (#69)

The lightning and explosions cards now run only in loaded Rivencraft Ages with players. Legacy rolled once per chunk per tick: explosions at 1/1000 and lightning at 1/5000 during thunder or 1/100000 otherwise. Each selected hazard card gets an independent roll every scheduler pass, rather than waiting for the rotating two-provider sample. The roll uses up to 81 already-loaded chunks near Age players and the exact probability of at least one Legacy opportunity over that many chunk-ticks. It permits at most one event per hazard type per pass. A per-Age saved sequence and last-event time prevent the same roll/event from replaying after a restart. Lightning also skips an existing bolt at the target.

Legacy used a real lightning bolt and a flaming, block-damaging strength-3 explosion. Both remain enabled by default. Unlike Legacy, the bolt is visual-only and its damage/fire are applied through separate bounded paths. The explosion uses NeoForge's normal explosion hooks plus break-event checks, with a calculator that restricts destruction to one already-loaded chunk, protects spawn, block entities, portals, decay-protected blocks and Rivencraft infrastructure, and caps affected blocks and entity damage. The visual/audio explosion still occurs when griefing is disabled. mobGriefing and doFireTick gate block changes and ignition; survival/adventure player damage is separately configurable. These are deliberate modern server-safety differences from Legacy.

Server config instability_hazards controls enablement, block damage, player damage, fire, interval, maximum nearby loaded chunks, maximum destroyed blocks, damaged entities, damage per entity, and explosion radius. instability.world_mutation=false also suppresses block damage and fire without suppressing visuals or entity damage. No hazard is dispatched into preview, Overworld, or another Age.

For an operator smoke test inside an Age, /rivencraft age hazard pulse lightning and /rivencraft age hazard pulse explosion force one event in a safe loaded chunk. They still honor the Age scope, enable switch, cooldown, spawn exclusion, game rules and damage policies. Repeat after minimum_gap_ticks (default 20 ticks); run the same command in the Overworld to verify that it refuses to fire. The earlier 200-tick min_interval_ticks test key is retired; existing configs receive the new default when NeoForge corrects them.