magicciv/.project/objectives/g2-12a-layer-data-model-save-oos.md
Natalie 2de6051c5f chore(objectives): fix Game-1 owner integrity + flesh out underground (g2-12) cluster
Game-1 dashboard fix: reassign 5 objectives off specialist-agent names
onto valid team-leads so objectives-report.py regenerates (it aborts on
any owner lacking a .project/team-leads/<owner>.md identity):
  p1-61 game-data->terraformer, p1-57 game-systems->envoy,
  p2-73/p2-60/p2-74 godot-engine|godot-ui->wireguard.

Underground (Game 2, stays OOS): decompose g2-12 umbrella into 8 ordered
phase objectives g2-12a..h (data model+save, worldgen, excavation, cross-
layer movement+pathfinding, per-layer fog, collapse, layer UI, AI
awareness); g2-11 blocked_by tightened to [g2-12a, g2-12c].

Dashboard regenerated: 319 objectives, README.md + objectives.json.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:24:32 -07:00

2.3 KiB

id title priority status scope category owner created updated_at blocked_by follow_ups
g2-12a Underground — N-layer data model + save format (Game 2) — OOS p3 oos game2 terrain unassigned 2026-06-06 2026-06-06

Context

Foundation phase of the underground layer stack (g2-12). Today the simulation is a single 2D hex grid: mc-core::grid::TileState { col, row, … elevation } with no z/layer axis (elevation is a continuous surface-height float, not a discrete layer). Per VERTICAL_LAYERS.md, Age of Dwarves needs Surface + Underground L1/L2/L3 as separate GameMap instances sharing one (col,row) coordinate system, with units carrying a current_layer field.

This objective adds the data model + save format only — no gameplay, generation, or rendering (those are later phases). It is the load-bearing change every other g2-12* phase depends on.

Acceptance (Game 2)

  • LayerIndex(u8) + LayerKind enum (Surface, UndergroundL1, UndergroundL2, UndergroundL3; engine-reserved Sky/Orbital documented but unused) added to mc-core.
  • GameState holds an ordered layers collection of per-layer GridState, all sharing width/height/coordinate origin; surface is index 0.
  • Per-instance MapUnit gains current_layer: LayerIndex; all existing single-layer call sites default to Surface.
  • Save format round-trips per-layer tile state + each unit's current_layer, byte-identical for surface-only (Game 1) saves (additive, #[serde(default)]; no Game-1 save breakage).
  • Back-compat: loading a pre-layer save yields a single Surface layer; cargo test -p mc-save round-trip + default-path tests green.

Source-of-truth rails

  • Rust crate: mc-core (LayerIndex, LayerKind), mc-state (GameState.layers, MapUnit.current_layer), mc-save (serde round-trip).
  • JSON path: n/a (structural).
  • mc-core wrapper: LayerIndex(u8), LayerKind enum — supersedes the LayerIndex stub noted in g2-12.

Out of scope (for any milestone)

  • Single-surface Game 1 gameplay + save format must continue working unchanged.
  • No generation/movement/vision/render here — data model + persistence only.

References

  • public/games/age-of-dwarves/docs/terrain/VERTICAL_LAYERS.md
  • .claude/instructions/scope-game1-vs-game2.md
  • Parent: g2-12 · Unblocks: g2-12b..g2-12h, g2-11