NEO-96: formalize NPC runtime telemetry hook sites
Replace NEO-93 placeholder comments with full telegraph_fired and npc_state_transition E9.M1 anchors in NpcRuntimeOperations; document in server README and E5.M2 module alignment.pull/135/head
parent
dedd9a9c18
commit
5e1e37423f
|
|
@ -91,6 +91,8 @@ The **first shipped three-archetype NPC spine** under `content/npc-behaviors/*.j
|
|||
|
||||
**Session player combat HP (NEO-95):** **`IPlayerCombatHealthStore`** + **`NpcAttackOperations.TryResolveTelegraphComplete`** in `server/NeonSprawl.Server/Game/Combat/` — telegraph complete applies catalog **`attackDamage`** to aggro holder; **`GET /game/players/{id}/combat-health`** read model for client HUD. Plan: [NEO-95 implementation plan](../../plans/NEO-95-implementation-plan.md); [server README — Session player combat HP (NEO-95)](../../../server/README.md#session-player-combat-hp-neo-95); Bruno `bruno/neon-sprawl-server/combat-health/`.
|
||||
|
||||
**NPC runtime telemetry hooks (NEO-96):** comment-only **`telegraph_fired`** + **`npc_state_transition`** hook sites in **`NpcRuntimeOperations.AdvanceAll`** (`TODO(E9.M1)`; no ingest). Plan: [NEO-96 implementation plan](../../plans/NEO-96-implementation-plan.md); [server README — NPC runtime telemetry hooks (NEO-96)](../../../server/README.md#npc-runtime-telemetry-hooks-neo-96).
|
||||
|
||||
**NPC behavior definitions HTTP (NEO-90):** **`GET /game/world/npc-behavior-definitions`** — versioned read-only projection (`schemaVersion` **1**, **`npcBehaviors`**) backed by **`INpcBehaviorDefinitionRegistry`**. Plan: [NEO-90 implementation plan](../../plans/NEO-90-implementation-plan.md); [server README — NPC behavior definitions (NEO-90)](../../../server/README.md#npc-behavior-definitions-neo-90); Bruno `bruno/neon-sprawl-server/npc-behavior-definitions/`.
|
||||
|
||||
## Risks and telemetry
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -322,8 +322,10 @@ Working backlog for **Epic 5 — Slice 2** ([NPC archetypes and telegraphs](../d
|
|||
|
||||
**Acceptance criteria**
|
||||
|
||||
- [ ] Hook names match [epic_05 Slice 2](../decomposition/epics/epic_05_pve_combat.md#slice-2---npc-archetypes-and-telegraphs) vocabulary.
|
||||
- [ ] No runtime behavior change beyond comments.
|
||||
- [x] Hook names match [epic_05 Slice 2](../decomposition/epics/epic_05_pve_combat.md#slice-2---npc-archetypes-and-telegraphs) vocabulary.
|
||||
- [x] No runtime behavior change beyond comments.
|
||||
|
||||
**Landed ([NEO-96](https://linear.app/neon-sprawl/issue/NEO-96)):** comment-only **`telegraph_fired`** + **`npc_state_transition`** hook sites in **`NpcRuntimeOperations`**; plan [NEO-96-implementation-plan.md](NEO-96-implementation-plan.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -45,9 +45,16 @@
|
|||
|
||||
## Acceptance criteria checklist
|
||||
|
||||
- [ ] **`TODO(E9.M1)`** markers present at **`telegraph_fired`** and **`npc_state_transition`** hook sites in NPC runtime path.
|
||||
- [ ] Hook names match [epic_05 Slice 2](../decomposition/epics/epic_05_pve_combat.md#slice-2---npc-archetypes-and-telegraphs) vocabulary (`telegraph_fired`, `npc_state_transition`).
|
||||
- [ ] No runtime behavior change beyond comments / doc cross-links.
|
||||
- [x] **`TODO(E9.M1)`** markers present at **`telegraph_fired`** and **`npc_state_transition`** hook sites in NPC runtime path.
|
||||
- [x] Hook names match [epic_05 Slice 2](../decomposition/epics/epic_05_pve_combat.md#slice-2---npc-archetypes-and-telegraphs) vocabulary (`telegraph_fired`, `npc_state_transition`).
|
||||
- [x] No runtime behavior change beyond comments / doc cross-links.
|
||||
|
||||
## Implementation reconciliation (shipped)
|
||||
|
||||
- NEO-93 `(NEO-96)` stub comments replaced with full NEO-84-style hook blocks in **`NpcRuntimeOperations.AdvanceAll`**.
|
||||
- **`telegraph_fired`** at aggro→telegraph and recover→telegraph entries; **`npc_state_transition`** on every state commit including holder clear → idle.
|
||||
- **`server/README.md`**, **E5_M2** module doc, **E5M2** backlog, and alignment register updated.
|
||||
- No new tests (comment-only); existing NPC runtime tests unchanged.
|
||||
|
||||
## Technical approach
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,11 @@ using NeonSprawl.Server.Game.Combat;
|
|||
|
||||
namespace NeonSprawl.Server.Game.Npc;
|
||||
|
||||
/// <summary>Deterministic prototype NPC behavior state machine + lazy tick advance (NEO-93).</summary>
|
||||
/// <summary>
|
||||
/// Deterministic prototype NPC behavior state machine + lazy tick advance (NEO-93).
|
||||
/// NEO-96 telemetry hook sites: state transition commits and telegraph starts in <see cref="AdvanceAll"/>
|
||||
/// (<c>telegraph_fired</c>, <c>npc_state_transition</c>).
|
||||
/// </summary>
|
||||
public static class NpcRuntimeOperations
|
||||
{
|
||||
/// <summary>Default per-advance simulation cap (seconds) for lazy poll ticks.</summary>
|
||||
|
|
@ -114,6 +118,10 @@ public static class NpcRuntimeOperations
|
|||
if (snapshot.BehaviorState != NpcBehaviorState.Idle || snapshot.ActiveTelegraph is not null)
|
||||
{
|
||||
WriteIdle(runtimeStore, npcInstanceId);
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — holder cleared or fixture reset (any → idle).
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState, toState (idle),
|
||||
// phaseStartedUtc, optional aggroHolderPlayerId (previous holder when known).
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -127,7 +135,10 @@ public static class NpcRuntimeOperations
|
|||
NpcBehaviorState.Aggro,
|
||||
windowStart,
|
||||
activeTelegraph: null);
|
||||
// telemetry: npc_state_transition (NEO-96)
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — idle → aggro when aggro holder is set.
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState (idle), toState (aggro),
|
||||
// phaseStartedUtc, aggroHolderPlayerId.
|
||||
if (!runtimeStore.TryGet(npcInstanceId, out snapshot))
|
||||
{
|
||||
return;
|
||||
|
|
@ -139,7 +150,16 @@ public static class NpcRuntimeOperations
|
|||
{
|
||||
if (!TryHasAggroHolder(npcInstanceId, threatStore, out aggroHolderPlayerId))
|
||||
{
|
||||
if (!runtimeStore.TryGet(npcInstanceId, out snapshot))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
WriteIdle(runtimeStore, npcInstanceId);
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — holder cleared mid-cycle (any → idle).
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState, toState (idle),
|
||||
// phaseStartedUtc, optional aggroHolderPlayerId (previous holder).
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +190,14 @@ public static class NpcRuntimeOperations
|
|||
NpcBehaviorState.TelegraphWindup,
|
||||
cursor,
|
||||
telegraph);
|
||||
// telemetry: npc_state_transition (NEO-96)
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — aggro → telegraph_windup.
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState (aggro),
|
||||
// toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId.
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` ---
|
||||
// TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle).
|
||||
// Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind,
|
||||
// aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds.
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +222,10 @@ public static class NpcRuntimeOperations
|
|||
NpcBehaviorState.Recover,
|
||||
cursor,
|
||||
activeTelegraph: null);
|
||||
// telemetry: telegraph_fired / npc_state_transition (NEO-96); logical attack_execute → recover
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — telegraph_windup → recover (logical attack_execute instant).
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState (telegraph_windup),
|
||||
// toState (recover), phaseStartedUtc, aggroHolderPlayerId, telegraphId (completed windup).
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -213,7 +243,10 @@ public static class NpcRuntimeOperations
|
|||
NpcBehaviorState.Recover,
|
||||
cursor,
|
||||
activeTelegraph: null);
|
||||
// telemetry: npc_state_transition (NEO-96)
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — attack_execute → recover (defensive visible phase).
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState (attack_execute),
|
||||
// toState (recover), phaseStartedUtc, aggroHolderPlayerId.
|
||||
break;
|
||||
|
||||
case NpcBehaviorState.Recover:
|
||||
|
|
@ -232,7 +265,14 @@ public static class NpcRuntimeOperations
|
|||
NpcBehaviorState.TelegraphWindup,
|
||||
cursor,
|
||||
telegraph);
|
||||
// telemetry: npc_state_transition (NEO-96)
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `npc_state_transition` ---
|
||||
// TODO(E9.M1): catalog emit — recover → telegraph_windup.
|
||||
// Planned payload fields: npcInstanceId, behaviorDefId, fromState (recover),
|
||||
// toState (telegraph_windup), phaseStartedUtc, aggroHolderPlayerId, telegraphId.
|
||||
// --- Telemetry hook site (NEO-96): future E9.M1 catalog event `telegraph_fired` ---
|
||||
// TODO(E9.M1): catalog emit — once per telegraph start (each windup cycle).
|
||||
// Planned payload fields: npcInstanceId, telegraphId, behaviorDefId, archetypeKind,
|
||||
// aggroHolderPlayerId, windupStartedUtc, telegraphWindupSeconds.
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,6 +188,10 @@ Per-NPC behavior states live in **`Game/Npc/`** as **`INpcRuntimeStateStore`** +
|
|||
|
||||
Plan: [NEO-93 implementation plan](../../docs/plans/NEO-93-implementation-plan.md).
|
||||
|
||||
### NPC runtime telemetry hooks (NEO-96)
|
||||
|
||||
Comment-only hook sites in **`NpcRuntimeOperations.AdvanceAll`** for future E9.M1 catalog events — **`telegraph_fired`** at each **`telegraph_windup`** entry (aggro→telegraph and recover→telegraph); **`npc_state_transition`** on every committed state change (including holder clear → **`idle`**). **`TODO(E9.M1)`** — no production ingest. Snapshot GET invokes **`AdvanceAll`** before read (no duplicate API-layer hooks). Plan: [NEO-96 implementation plan](../../docs/plans/NEO-96-implementation-plan.md).
|
||||
|
||||
## NPC runtime snapshot (NEO-94)
|
||||
|
||||
**`GET /game/world/npc-runtime-snapshot`** returns a versioned JSON body (`schemaVersion` **1**, **`serverTimeUtc`**, **`npcInstances`**) backed by **`INpcRuntimeStateStore`** + **`IThreatStateStore`** after **`NpcRuntimeOperations.AdvanceAll`** (lazy tick, **5.0 s** delta cap). Each row includes **`npcInstanceId`**, **`behaviorDefId`**, **`state`** (stable snake_case), **`aggroHolderPlayerId`**, and optional nested **`activeTelegraph`** during **`telegraph_windup`**. All three **`PrototypeNpcRegistry`** instances are always returned in ascending **`npcInstanceId`** order. Plan: [NEO-94 implementation plan](../../docs/plans/NEO-94-implementation-plan.md); Bruno: `bruno/neon-sprawl-server/npc-runtime-snapshot/`.
|
||||
|
|
|
|||
Loading…
Reference in New Issue