Docs: LANTERN Phase 0.3 world-model proposal + Phase 1 combat-gym spec + operator-questions
- World-model design proposal (pre-review input): seed-pinning = freeze-salt + save-deltas; light-as-information = two hard-cull relevancy layers (pocket-scope + party light-union); descent lifecycle = renamed/extended RunDirectorSystem. Grounded in 3 read-only code passes + ctx7 on GhostRelevancy/GhostImportance. Feeds the running adversarial review. - Phase 1 combat-gym build spec (design, pre-review): two frames (Bathynaut/Harpooner), 4-socket manual-aim skillshot kit (AbilityRef -> socket buffer, 7-type-cap restructure), 5 Sparks on the ability-blob + BoonEffects hook layer, light-relevancy prototype shares the world-model review. Grounded in a combat/ability/boon salvage pass. - Operator-questions parking lot (autonomous run): code impl + extra reviews + A0 art execution parked pending operator; design forks flagged with recommendations. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: LANTERN — Operator Questions (autonomous-run parking lot)
|
||||
date: 2026-07-13
|
||||
tags: [roadmap, lantern, operator-questions, forks]
|
||||
status: awaiting-operator
|
||||
permalink: gamevault/06-roadmap/lantern-operator-questions
|
||||
---
|
||||
|
||||
# LANTERN — Operator Questions
|
||||
|
||||
> Parking lot for decisions I couldn't make autonomously during the 2026-07-13 autonomous build run (operator
|
||||
> stepped away: "build everything you can, don't stop, create a doc of operator questions as needed"). Each
|
||||
> item has my **recommendation** so you can answer in one pass. Nothing here blocked me from continuing — I
|
||||
> took the recommended default in the design docs and flagged it, so answering may just confirm or redirect.
|
||||
>
|
||||
> **Convention:** ✅ = I proceeded on the recommendation (design assumes it; easy to change). ⛔ = I did NOT
|
||||
> proceed; genuinely blocked pending your call.
|
||||
|
||||
## Process / authorization
|
||||
|
||||
1. **⛔ New netcode CODE implementation.** All LANTERN slice code is greenfield and netcode-touching (new
|
||||
ghosts / prediction / relevancy / RPCs), so it needs (a) plan-approval per the /dots-dev gate and (b) a
|
||||
**focused** Unity editor (an unfocused editor throttles MCP + breaks Burst — you're away). I did **not**
|
||||
write any Unity code this run. **Recommendation:** on return, focus Unity, then greenlight implementation
|
||||
phase-by-phase from the build specs I wrote. *All design/build-spec scaffolding is ready so code can move
|
||||
fast.*
|
||||
2. **⛔ Additional multi-agent design-review Workflows.** You explicitly greenlit the world-model review. Each
|
||||
remaining ★review-first slice (Phase 1's light-relevancy prototype; Phase 2 world code; hazards; etc.) also
|
||||
wants one before coding. I did **not** fire more heavy Workflows unprompted. **Recommendation:** greenlight
|
||||
"run the ★ review before each netcode slice" as a standing autonomous authorization, or I run them one-by-one
|
||||
on your go.
|
||||
3. **✅/⛔ Blender A0 art execution.** Blender MCP is live. I wrote the art-pipeline recipes + the A0 material
|
||||
spec (docs). Whether I should *autonomously attempt* the in-engine style-proof scene (needs your eyes to
|
||||
judge — screenshots hide material bugs) vs. wait: I lean **wait for your eyes** on the gate judgment, but I
|
||||
can build the palette atlas + a first placeholder asset as a starting point. **Recommendation:** let me
|
||||
stage the palette atlas + one placeholder prop/creature/suit for the scene, but you judge the gate.
|
||||
|
||||
## Phase 1 — combat gym (design forks in [[Lantern_Phase1_Combat_Gym_Build_Spec]])
|
||||
|
||||
4. **✅ Suit-frame kit specifics.** I specced the **Bathynaut** (anchor-and-crash melee) and **Harpooner**
|
||||
(line-and-iron skillshots) chassis verbs + a 4-socket kit. The exact Spark list (first 4–5) and per-frame
|
||||
movement feel are recommendations — see the build spec's fork table. Confirm or swap.
|
||||
5. **✅ Manual-aim vs the current soft auto-target.** Design cuts soft auto-target for SoD-grade manual aim
|
||||
(per Identity). Confirm you want the auto-target fully gone in the gym (I kept the reticle plumbing).
|
||||
|
||||
## Economy / naming
|
||||
|
||||
6. **✅ Currency re-mean mapping.** Ore/Aether/Biomass/Charge → Flame/Lumen/Gloam/Loudness/Salvage/Chum/Tallow.
|
||||
Proposed mapping in the currency spec. Confirm the byte-id assignments before any save-schema work.
|
||||
7. **(deferred) Shipping title.** "LANTERN" is the internal codename; a marketing naming pass is deferred
|
||||
(per [[Identity_Lantern]]). No action needed now.
|
||||
|
||||
## Answered this session (for the record)
|
||||
|
||||
- Co-op pocket occupancy → **co-located, one active pocket** (2026-07-13).
|
||||
- Light-as-information scope → **party light-union, Wicks always visible** (2026-07-13).
|
||||
- Run the world-model adversarial review → **yes, full review** (2026-07-13).
|
||||
|
||||
## Related
|
||||
|
||||
- [[Roadmap_Lantern_Slice]] · [[Lantern_World_Model_Design_Proposal]] · [[DR-048_Lantern_Adoption_Full_Pivot]]
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: LANTERN — Phase 1 Combat Gym (design/build spec, pre-review)
|
||||
date: 2026-07-13
|
||||
tags: [roadmap, lantern, combat, phase-1, build-spec, netcode]
|
||||
status: design-pre-review
|
||||
permalink: gamevault/06-roadmap/lantern-phase1-combat-gym-build-spec
|
||||
---
|
||||
|
||||
# LANTERN — Phase 1: Combat Gym (design/build spec)
|
||||
|
||||
> Phase 1 of [[Roadmap_Lantern_Slice]]: *the primary verb first — two frames that feel like Shape of Dreams.
|
||||
> No world, no lanterns — a gym.* This is a **design spec written from ground-truth code** (a combat/ability/
|
||||
> boon salvage pass), NOT a build contract: the 4-socket kit and light-relevancy prototype are **netcode-
|
||||
> touching** (new ghost fields / input surface) so they need the ★ design review + plan-approval + a focused
|
||||
> editor before any code. Phase 1 has **no world** and is **not** blocked by the Phase-0.3 world-model review.
|
||||
>
|
||||
> **Gate:** the gym is fun with two players for 15 minutes on kit alone; the relevancy-light prototype verifies
|
||||
> server-side (gamma test: nothing to see outside your light).
|
||||
|
||||
## Salvage verdict (what Phase 1 stands on)
|
||||
|
||||
The combat substrate is the project's strongest asset and it ports almost whole:
|
||||
|
||||
- **KEEP as-is:** the client-only feel layer — `CombatFeedbackSystem` (edge-detects replicated `Health`/tick
|
||||
fields, never touches sim), `EnemyDangerTelegraphSystem` (per-kind colour/voice/shape/light), `AimReticleSystem`,
|
||||
`DynamicLightSystem`. The dash — `DashSystem` (deterministic re-sim from the replicated `PlayerInput.Dash`
|
||||
InputEvent; i-frame window + sharpness-override blink) is exactly the SoD dash.
|
||||
- **KEEP the pipeline, REWORK the grammar:** `AbilityFireSystem` (predicted-spawn, `IsFirstTimeFullyPredictingTick`
|
||||
gate, SpawnId classification, `AutoTarget` server/gamepad branch), the ability blob (`AbilityDatabase` /
|
||||
`AbilityDefBlob` / `AbilityArchetype`), `StatModifier`→`StatRecomputeSystem`→`EffectiveAbilityStats` (every-
|
||||
tick fold), `MeleeComboSystem` (predicted absolute-write `Step`).
|
||||
- **REWORK into the socket kit:** the single `AbilityRef{[GhostField] byte Id}` → a **4-wide socket buffer**
|
||||
(model on `EquipmentSlot`: `[InternalBufferCapacity(4)]`, index-is-slot, `SendToOwnerType.All`, server-sole-
|
||||
writer). One `AbilityCooldown` → a 4-wide cooldown. One `PlayerInput.Fire` → **4 socket inputs**.
|
||||
- **CUT (as the target):** soft auto-target as the default — SoD is manual aim. Keep the plumbing; disable
|
||||
per-socket via `AutoTargetRange = 0` in the ability def (a clean existing off-switch), leaving a small
|
||||
optional in-arc assist only where a specific Spark wants it.
|
||||
|
||||
## The two suit-frames (chassis = class = silhouette = verb)
|
||||
|
||||
Frames extend the proven class chassis (`ClassTraits` seeds 4 permanent trait `StatModifier`s per class; the
|
||||
`AbilityFor(classId)` mapping). Two frames ship:
|
||||
|
||||
### Bathynaut — anchor-and-crash melee (Warrior lineage)
|
||||
- **Chassis verb:** a weighted tide-breaker. Reuses `MeleeComboSystem` (combo `Step`, finisher scaling,
|
||||
server-only cone cleave) as the always-available primary. Movement feel: high mass, short committed lunges,
|
||||
a hard **anchor** (a planted stance that trades mobility for a crash payoff). Slow turn, high poise.
|
||||
- **Salvage:** Warrior seeds (`+MaxHealth`, `-MoveSpeed`, `+MeleeDamage`, `+MeleeRange`) reskin directly.
|
||||
|
||||
### Harpooner — line-and-iron skillshots incl. reel/drag (Ranger lineage)
|
||||
- **Chassis verb:** manual-aim line weapons. Reuses the predicted projectile path. The signature verb is
|
||||
**reel/drag**: a fired iron that, on hit, **pulls** (the existing `KnockToPull` / `ProjectileEffectState`
|
||||
pull hook, promoted from a mutation to a native Harpooner mechanic) — either pulling the target to you or
|
||||
you to the target (design fork, see questions doc). Movement feel: light, kite-friendly, real windups.
|
||||
- **Salvage:** Ranger seeds (`+MoveSpeed`, `-MaxHealth`, `+Range`, `+AutoTargetRange`) reskin; the reel reuses
|
||||
the pull flag + the chain/retarget machinery in `ProjectileDamageSystem`.
|
||||
|
||||
## The 4-socket skillshot kit (the netcode core — ★ review before code)
|
||||
|
||||
The single-ability model becomes a **4-socket kit** (4 active + the movement/dash). Design:
|
||||
|
||||
- **`AbilitySocket` buffer** on the player: `[GhostComponent(SendToOwnerType.All)] [InternalBufferCapacity(4)]`,
|
||||
one row per socket = `byte SparkId` (0 = empty). Server is the sole writer (socketing happens in the
|
||||
gym/hub, not predicted). Mirrors `EquipmentSlot` exactly — a proven pattern.
|
||||
- **`SocketCooldown` buffer** (4-wide, `[GhostField]` `NextFireTick` per socket, `SendToOwner`). Replaces the
|
||||
single `AbilityCooldown`. Each routed through `TickUtil.NonZero`.
|
||||
- **Input:** add **4 socket InputEvents** to `PlayerInput` (`Socket0..3`) — OR a single `Fire` + a `byte
|
||||
SocketIndex` (cheaper wire, one event). **Recommendation:** a single `InputEvent Fire` + `byte ActiveSocket`
|
||||
(the player "readies" a socket; one fire verb) keeps the input surface small and the 7-type query cap
|
||||
manageable; but 4 discrete buttons feel better for a MOBA bar. *Parked as a fork.*
|
||||
- **The 7-type query cap is already hit** in `AbilityFireSystem` — the socket rework must move to a
|
||||
`ComponentLookup`-fed restructure or an `IJobEntity` (per the CLAUDE.md 7-arg rule; hit twice already in the
|
||||
boon work). This is the single biggest code-restructure of Phase 1.
|
||||
- **Per-socket archetype dispatch:** the ability blob already dispatches on `AbilityArchetype`
|
||||
(Projectile/Cone implemented; **Hitscan/Aoe declared-but-unhandled** — Phase 1 implements them for the zone/
|
||||
vortex Sparks). Each Spark is an `AbilityDefBlob` row; socketing writes its id into `AbilitySocket`.
|
||||
- **Manual-aim grammar:** every socket fires along raw `PlayerInput.Aim` (manual). Real windups: add a
|
||||
`WindupTicks` to the ability def so player abilities telegraph like enemy attacks (reuse the telegraph
|
||||
vocabulary client-side). Readable hitboxes = the swept-projectile + cone math already in place.
|
||||
|
||||
## First Sparks (4–5 socketables — prove kit variety)
|
||||
|
||||
Each Spark = an `AbilityDefBlob` row + (if projectile/zone) a ghost prefab + an optional `ProjectileEffectState`/
|
||||
`BoonEffects`-style hook. Roadmap set: **decoy-wisp, hook/pull, vortex, blink, one zone.**
|
||||
|
||||
| Spark | Archetype | Salvage hook |
|
||||
|---|---|---|
|
||||
| **Decoy-wisp** | Aoe/spawn | spawns a server ghost that draws aggro (reuse the enemy target-selection + a new decoy tag; a Wisp-Choir mote asset in A2) |
|
||||
| **Hook / pull** | Projectile + pull | the `ProjectileEffectState` pull flag + chain retarget — a skillshot grab |
|
||||
| **Vortex** | Aoe (zone) | implements the declared-but-unhandled `Aoe` archetype: a timed area that pulls/slows (reuse geyser/hazard AoE chassis) |
|
||||
| **Blink** | movement | a second `DashSystem`-style deterministic teleport (re-sim from an InputEvent; no ghost) |
|
||||
| **Zone (one)** | Aoe (zone) | a persistent light/damage zone — the `HazardExplosionSystem`/geyser periodic-AoE chassis, player-owned |
|
||||
|
||||
Sparks are **not** mutations — mutations (Phase 4) *warp* Sparks via the `BoonEffects` substrate (3 count bytes
|
||||
+ flag bits, `SendToOwner`, server-only `ProjectileEffectState` hooks). Phase 1 only needs the sockets + the
|
||||
Spark defs; the mutation layer bolts on later without re-baking (its hooks already exist).
|
||||
|
||||
## Light-as-information prototype (★ review-first — see [[Lantern_World_Model_Spike]])
|
||||
|
||||
The gym's version of the slice's hardest idea, proven small: **per-player lamp radius drives netcode relevancy;
|
||||
entities outside the light aren't replicated.** Per the world-model design ([[Lantern_World_Model_Design_Proposal]]),
|
||||
this is **hard `GhostRelevancy` (`SetIsIrrelevant`)**, party-light-union, Wicks always visible. In the gym
|
||||
(no pockets) it degenerates to: a single arena + a per-player/party light-union relevancy pass over the
|
||||
training dummies/enemies. **This shares the world-model review** — do not code it until that Build Spec lands
|
||||
(the relevancy thrash/hysteresis + cost questions are the same). The gym is the natural first validation venue
|
||||
for the relevancy-light (the roadmap's gamma test: "nothing to see").
|
||||
|
||||
## Underwater feel pass (client-only, zero netcode)
|
||||
|
||||
Reuse the ambient stack (`AmbientMotionSystem` / `AmbientLifeSystem` / `WorldAtmosphereSystem`): buoyant
|
||||
knockbacks (tune the existing `KnockbackUtil` decay to a slow float), slow-tumbling debris (ambient drift),
|
||||
murk fog (the per-biome dark palette + fog density knob), hydrophone audio sketch (procedural `AudioClip.Create`
|
||||
bed, the proven presentation pattern). No sim change — pure feel.
|
||||
|
||||
## Build order (when greenlit; each step ends "compile + read_console clean")
|
||||
|
||||
1. **Socket data model** (no behaviour): `AbilitySocket` + `SocketCooldown` buffers, baked 4-wide; keep the old
|
||||
`AbilityRef` path working in parallel. *Wire/bake: new player ghost fields → one player-ghost re-bake.*
|
||||
2. **`AbilityFireSystem` socket restructure** (the 7-type-cap fix via ComponentLookup/IJobEntity); route the
|
||||
active-socket fire through the blob dispatch + per-socket cooldown. Cone + Projectile first.
|
||||
3. **Implement the `Aoe`/`Hitscan` archetypes** (vortex/zone Sparks).
|
||||
4. **The 5 Spark defs** + prefabs (kitbash/greybox; A1 assets replace later) + the Blink second-dash.
|
||||
5. **Two frames** = the class chassis reskin + per-frame socket defaults + movement-feel tuning knobs.
|
||||
6. **Manual-aim grammar:** windup telegraphs on player abilities; auto-target off by default (per-socket knob).
|
||||
7. **Underwater feel pass** (client-only).
|
||||
8. **Light-relevancy prototype** — ONLY after the world-model Build Spec; validated by the gamma test.
|
||||
|
||||
**Wire/bake churn:** steps 1–2 re-bake the player ghost (socket + cooldown fields); the input-surface change
|
||||
(socket events / active-socket byte) touches the command struct — re-mean bytes where possible, and the RPC/
|
||||
command collection hash must match across peers. Everything else is additive config + client-only.
|
||||
|
||||
## Open forks (parked in [[Lantern_Operator_Questions]])
|
||||
|
||||
- Socket input model: 4 discrete buttons vs one fire + a readied `ActiveSocket` byte.
|
||||
- Harpooner reel: pull the target to you, or you to the target (or a per-Spark mix).
|
||||
- The exact 5 Sparks (confirm the roadmap set or swap).
|
||||
- Auto-target fully gone vs a small optional in-arc assist per Spark.
|
||||
|
||||
## Related
|
||||
|
||||
- [[Roadmap_Lantern_Slice]] — Phase 1 · [[Lantern_Strip_Mothball_Inventory]] — the salvage verdicts
|
||||
- [[Lantern_World_Model_Design_Proposal]] / [[Lantern_World_Model_Spike]] — shares the light-relevancy review
|
||||
- [[DR-047_Phase17_Boon_Overhaul_Mechanic_Changers]] — the `BoonEffects` substrate the mutation layer reuses
|
||||
- [[Identity_Lantern]] — the combat feel target (SoD-grade skillshots)
|
||||
@@ -0,0 +1,161 @@
|
||||
---
|
||||
title: LANTERN — World-Model Design Proposal (pre-review, Phase 0.3)
|
||||
date: 2026-07-13
|
||||
tags: [roadmap, lantern, netcode, world-model, design-proposal, phase-0]
|
||||
status: proposal-pre-review
|
||||
permalink: gamevault/06-roadmap/lantern-world-model-design-proposal
|
||||
---
|
||||
|
||||
# LANTERN World-Model — Design Proposal (pre-review)
|
||||
|
||||
> Phase 0.3 of [[Roadmap_Lantern_Slice]]. This is the **plan** produced from the [[Lantern_World_Model_Spike]]
|
||||
> brief, grounded in the actual code (three read-only ground-truth passes + ctx7 on the Netcode relevancy/
|
||||
> importance APIs). **It is the INPUT to the ★ adversarial design review, not a build contract** — the review
|
||||
> hardens it into `World_Model_Build_Spec.md`. No world code until that review passes.
|
||||
>
|
||||
> **Operator forks locked this session:** (1) **co-located party — one active pocket at a time**; (2) **party
|
||||
> light-union relevancy — Wicks always visible to each other, world/enemies outside the party's combined light
|
||||
> are never sent.** Everything else below is a recommendation for the review to stress-test.
|
||||
|
||||
## The key netcode finding (grounds the whole design)
|
||||
|
||||
- **`GhostRelevancy` (`SetIsIrrelevant`)** is a *hard* cull — an entity outside the set is **never serialized**
|
||||
to that connection. This is the ONLY mechanism that satisfies the vision's promise: *"gamma-cranking cannot
|
||||
reveal what was never sent."* So **light-as-information = hard relevancy**, not importance.
|
||||
- **`GhostImportance`/`GhostDistanceImportance`** is a *soft* dial (far ghosts sent less often, still eventually
|
||||
sent) with a per-connection focal point (`GhostConnectionPosition`). It composes with relevancy
|
||||
(`BatchScaleWithRelevancyFunctionPointer`). Use it, if needed, only for **bandwidth within the lit set** —
|
||||
never as the privacy boundary.
|
||||
- The current `RegionRelevancySystem` is a brute-force `O(ghosts × connections)` rebuild every tick keyed on a
|
||||
discrete `RegionTag{byte}` (Base=0 / Expedition=1), `SetIsIrrelevant` mode, no dirty-flag. The
|
||||
`GhostRelevancy` singleton + `RelevantGhostForConnection{Connection,Ghost}` key + the "shared global state
|
||||
rides one **untagged** always-relevant ghost" convention are the directly reusable primitives.
|
||||
|
||||
## Model overview (slice scope)
|
||||
|
||||
Because the party is **co-located in one active pocket**, the world model is *architecturally the current
|
||||
single-active-room + ping-pong two-slot arena*, re-keyed from a 2-value region to a per-pocket key, plus two
|
||||
new things: **seed-pinning** (persistence) and **light-union relevancy** (the second, finer relevancy layer).
|
||||
|
||||
### 1. The seed model — pinning = freeze the salt + save deltas
|
||||
|
||||
The load-bearing insight from the save ground-truth: **generation is a pure function re-derived from seed;
|
||||
only player mutation is stored as deltas.** The tide-line drops out of this cleanly:
|
||||
|
||||
- **`WorldSeed`** (persistent, per save) — the shelf's identity.
|
||||
- **`DescentSalt`** (server-only, monotonic per descent — the `RunEpoch`/`HostSalt` lineage) — salts every
|
||||
**dark** pocket so unlit geography **re-knots** each descent.
|
||||
- **`PocketId`** (stable graph-node id — today's `CurrentNodeId`).
|
||||
- A **dark** pocket's content = `Hash(WorldSeed, PocketId, DescentSalt, subStream)` → re-knots each descent
|
||||
because `DescentSalt` changes (exactly today's `Hash(RunSeed, CurrentNodeId, constSub)` seeding).
|
||||
- **Pinning a pocket = FREEZE its salt.** Planting a waypoint-lantern stores `PinnedSalt = current
|
||||
Hash(WorldSeed, PocketId, DescentSalt)` to the save; thereafter the pocket regenerates **identically** every
|
||||
descent from the frozen salt, **plus** its structure/harvest **deltas** replayed born-correct.
|
||||
- "The dark re-knots, the light holds" is therefore: *unpinned → new salt each descent; pinned → frozen salt +
|
||||
deltas.* Nearly free, and it reuses the exact deterministic-hash + born-correct-delta-replay patterns proven
|
||||
in `RoomFieldSystem` + `BaseRestoreSystem`.
|
||||
|
||||
### 2. The pocket-graph & muster
|
||||
|
||||
- Reuse `RunMapMath` (pure integer-hash DAG, client-regenerable) as the pocket-graph generator. Rename
|
||||
run→**descent**, room→**pocket**. The graph per descent is generated from the descent identity.
|
||||
- **Muster at the deepest lit waypoint:** instead of always entering at node 0, the descent's entry = the
|
||||
**deepest pinned pocket** (the lit frontier). The pinned prefix is persistent; the dark frontier past it is
|
||||
fresh. Slice target (roadmap): 3–5 dark pockets per descent past the frontier.
|
||||
|
||||
### 3. Relevancy — two hard-cull layers, both `SetIsIrrelevant`
|
||||
|
||||
- **Layer A — pocket-occupancy scope (coarse):** `PocketTag{ int PocketKey }` replaces `RegionTag` (server-
|
||||
only, NOT a `[GhostField]`). Party co-located ⇒ exactly one active pocket's ghosts are live; everything
|
||||
tagged with a non-active pocket key is irrelevant to all. This is *today's region swap*, and the ping-pong
|
||||
two-slot arena (`RegionMath`, 1000u offset + 500u stride) still gives the clean spawn-next / tear-down-prev
|
||||
handoff. The **station** is the permanent "home pocket" (today's Base region).
|
||||
- **Layer B — light-union relevancy (fine, party-union):** within the active pocket, an enemy/world/hazard
|
||||
ghost is relevant **iff it lies within ANY party member's lamp radius** (the union). Because vision is a
|
||||
party union, set-membership is **connection-independent** (relevant-to-any ⇒ relevant-to-all party conns) —
|
||||
compute it once per pocket per tick over party positions, then apply to all party connections. **Wicks
|
||||
(players) are always relevant to each other** (added to no irrelevant set). Cost: `O(ghosts × partySize)`
|
||||
with capped ghost counts (~≤40) — trivial; `GhostImportance` held in reserve for bandwidth only.
|
||||
- **Server interaction guard preserved:** relevancy is *client-visibility only* — server AI/damage still act
|
||||
on ghosts in the dark (things loom out of the dark; intended). Keep an equivalent server-side pocket guard
|
||||
(today's cross-region damage re-check) so cross-pocket interaction can't leak in the shared world.
|
||||
|
||||
### 4. The descent lifecycle (rename + extend `RunDirectorSystem`)
|
||||
|
||||
`RunDirectorSystem` stays the **sole FSM writer** (its single-writer discipline + receiver-sets-command idiom
|
||||
are load-bearing). State map (append-only byte consts, ghost-stable):
|
||||
|
||||
| Today | LANTERN | Note |
|
||||
|---|---|---|
|
||||
| Staging | **AtStation** | muster/prep/ready at the hub |
|
||||
| Launching | **Descending** | Bell-down telegraph; pick descent identity |
|
||||
| InRoom | **InPocket** | active pocket populated |
|
||||
| RoomReward | **PocketClear** | **mutation thresholds fire here** (pocket-clear beats, never mid-combat) |
|
||||
| RoomExplore | **PocketExplore** | loot + **plant-a-lantern** window |
|
||||
| RouteSelect | **ChooseNext** | pick the next pocket edge |
|
||||
| Returning | **Ascending** | Bell recall (teleport) or lit-road walk home; bank; → AtStation |
|
||||
|
||||
- **Bell transit = teleport** (the proven portal→EnterRoom teleport). Lit-road walk-home through pinned pockets
|
||||
is a stretch goal, not a slice blocker.
|
||||
- **~30–40 min hard session cap** = a server descent timer that forces the Bell recall (new).
|
||||
- Participant conscription/teleport/release (`RunParticipant`) reused verbatim; late-join/dead-respawn rejoin
|
||||
the co-located pocket via the existing conscription path.
|
||||
|
||||
### 5. Pinning, burn & the Lamp meter
|
||||
|
||||
- **Plant a lantern** in PocketExplore = a placement RPC (the `BuildPlaceSystem` co-op-atomic pattern) that
|
||||
freezes the salt + marks `PocketId` pinned + persists (new additive `PinnedPocketSave[]`, SaveData **v7**,
|
||||
own staging carrier + born-correct one-shot replay, mirroring `PendingStructure`/`BaseRestoreSystem`).
|
||||
- **Session-only burn:** fuel is a **runtime** server countdown per lit lantern (never persisted — loads full,
|
||||
drains only while the session runs). Guttering telegraphs long/loud; full gutter **un-pins** the pocket
|
||||
(dark reclaims it) — **only during play**, honoring "no offline punishment." Loss ceiling = frontier pockets
|
||||
only, never the pinned prefix's deepest reach in a way that soft-locks.
|
||||
- **Banked light** deposited at a lit lantern feeds the **Lamp meter** (the `GoalProgress`-equivalent campaign
|
||||
readout on the global untagged director ghost).
|
||||
|
||||
### 6. Wire contract (replicated vs server-only)
|
||||
|
||||
- **Global untagged director ghost** (`DescentInfo` ≈ `RunInfo`, all `[GhostField]`): lifecycle byte, active
|
||||
`PocketId`, descent seed (client regenerates graph + cosmetic dressing), **pinned-pocket set** (for map +
|
||||
muster point), **Lamp meter**, **party Loudness sum**.
|
||||
- **Server-only:** `DescentSalt`, per-pocket `PinnedSalt`, `PocketTag`, `RunParticipant`, lamp fuel timers,
|
||||
pocket teardown tags.
|
||||
- **Player ghost:** ready flag + **lamp radius** as `[GhostField] OwnerSendType.All` (clients render their own
|
||||
+ teammates' light cones; the server computes relevancy) + **Loudness pip**.
|
||||
|
||||
### 7. Salvage map (what each new piece reworks)
|
||||
|
||||
`RunMapMath`→pocket-graph gen · `RunDirectorSystem`→descent FSM · `RegionRelevancySystem`→two-layer pocket +
|
||||
light-union relevancy · `RoomTag`/`RoomTeardown`→`PocketTag`/teardown · `RoomFieldSystem` `Hash(seed,id,sub)`→
|
||||
pocket content (frozen-salt for pinned) · ping-pong two-slot arena→pocket transit · `SaveData` additive + born-
|
||||
correct staging/replay→seed-pin persistence (v7) · `BuildPlaceSystem`→lantern planting · `GoalProgress`→Lamp
|
||||
meter · global untagged `CycleDirector` ghost→descent/lamp global state.
|
||||
|
||||
## Open questions & hazards the review MUST attack
|
||||
|
||||
1. **Light-relevancy thrash/hysteresis.** A ghost pops in/out as the lamp sweeps → snapshot churn + the known
|
||||
relevancy-re-entry false-edge client hazard. Proposal: **once-lit-stays-relevant until pocket exit** (or a
|
||||
grace window). Review the correctness + the fiction ("does re-hiding a seen enemy feel wrong?").
|
||||
2. **Relevancy rebuild cost & structure.** Confirm the per-pocket connection-independent computation; bound it;
|
||||
decide if `GhostImportance` is needed at all for the slice.
|
||||
3. **Determinism of the frozen salt.** `PinnedSalt` must be frozen deterministically + saved; the re-knot
|
||||
`DescentSalt` must never collide with a live `PinnedSalt`. No wall-clock; `TickUtil.NonZero` for any tick.
|
||||
4. **Muster-at-deepest-pin + born-correct load.** How the FSM picks the entry pocket; how load restores the
|
||||
pinned prefix born-correct (the `PendingSave`/`BaseRestoreSystem` handshake extended).
|
||||
5. **Session-only burn vs persistence.** Pinning persists (seed+deltas+lit); fuel is session-runtime only.
|
||||
Confirm the un-pin path can't soft-lock the save (loss ceiling) and can't fire offline.
|
||||
6. **Server interaction guard.** Relevancy hides only from clients; enemies act in the dark server-side.
|
||||
Confirm no exploit (e.g. a player damaged by something they were never sent) and that it reads as fiction,
|
||||
not a bug.
|
||||
7. **Prediction/teleport.** Pocket gen + relevancy are server-authored (not predicted). The transit teleport is
|
||||
server-authoritative (today's EnterRoom). Confirm no rollback issue and that predicted CC movement between
|
||||
pockets is clean.
|
||||
8. **Reuse vs rewrite scope.** Is renaming region→pocket the right salvage, or does the light-union layer
|
||||
justify a fresh relevancy system? (The review's reuse/scope lens.)
|
||||
|
||||
## Related
|
||||
|
||||
- [[Lantern_World_Model_Spike]] — the brief this answers · [[Roadmap_Lantern_Slice]] Phase 0.3 & Phase 2
|
||||
- [[Lantern_Strip_Mothball_Inventory]] — the salvage verdicts this design executes
|
||||
- [[DR-048_Lantern_Adoption_Full_Pivot]] · [[Identity_Lantern]] — the direction & the tide-line
|
||||
- [[DR-013_M6_Aether_Cycle_Region_Split]] — the region/relevancy machinery being re-keyed
|
||||
Reference in New Issue
Block a user