feat(simulation): dialogue pipeline, ContentSlug, and walk-away KG recording

Implement full dialogue selection pipeline (D-028): 4-layer filtering
engine with access tier, situation derivation, trust tier, and weighted
topic+mood scoring via SimRng. Add ContentSlug component for stable
content identity across save/load. Add walk-away KG recording with
IncompleteInteraction events per D-064 three-phase consequences. Bump
protocol to v8 with DialogueResponseEvent. Fixes #305, #427, #452.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-17 17:41:23 +01:00
co-authored by Claude Opus 4.6
parent 695d2ac843
commit 35f55cfa46
9 changed files with 1834 additions and 7 deletions
+8 -1
View File
@@ -167,12 +167,19 @@ impl Plugin for BridgePlugin {
.after(crate::simulation::movement::validate_movement),
crate::simulation::monologue::trigger_monologue
.after(crate::simulation::movement::validate_movement),
crate::simulation::monologue::process_sprint_anomaly_monologue
crate::simulation::monologue::trigger_recognition_monologue
.after(crate::simulation::monologue::trigger_monologue),
crate::simulation::monologue::process_sprint_anomaly_monologue
.after(crate::simulation::monologue::trigger_recognition_monologue),
crate::simulation::dialogue::process_talk_interaction
.after(crate::simulation::input::process_player_input),
crate::simulation::dialogue::process_walk_away
.after(crate::simulation::input::process_player_input),
crate::perception::observer::compute_observer_snapshot
.after(crate::perception::observer::compute_visibility_geometry)
.after(crate::simulation::interaction::compute_nearby_interactions)
.after(crate::simulation::monologue::process_sprint_anomaly_monologue)
.after(crate::simulation::dialogue::process_talk_interaction)
.before(crate::simulation::time::advance_tick),
crate::perception::observation::emit_observation_events
.after(crate::perception::observer::compute_observer_snapshot),
+23 -1
View File
@@ -15,7 +15,7 @@ pub use crate::simulation::time::{DayPhase, TickRate};
/// negotiation is unnecessary. Client should reject snapshots with version !=
/// PROTOCOL_VERSION. New fields use #[serde(default)] only during the migration
/// period, then the default is removed once both sides are updated.
pub const PROTOCOL_VERSION: u8 = 7;
pub const PROTOCOL_VERSION: u8 = 8;
/// The ONLY data structure crossing the client-server boundary (D-020)
/// Contains all information visible to the observer at a given tick.
@@ -26,6 +26,7 @@ pub const PROTOCOL_VERSION: u8 = 7;
/// v5 adds: current_monologue (#414 internal monologue pipeline).
/// v6 adds: player_stance (#449, D-053), player_inventory (#449, D-065).
/// v7 adds: pending_recognitions (#423, D-060 cognitive delay).
/// v8 adds: dialogue_response (#305, D-028 dialogue pipeline).
/// Future fields: ambient sound events, HUD state (D-020 expansion).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ObserverSnapshot {
@@ -62,6 +63,11 @@ pub struct ObserverSnapshot {
/// Empty when no recognitions are pending.
#[serde(default)]
pub pending_recognitions: Vec<PendingRecognitionWire>,
/// Dialogue response from Talk verb interaction (#305, D-028).
/// Present when the player talked to an NPC this tick and a line was selected.
/// Client shows speaker name + dialogue text in a dialogue box.
#[serde(default)]
pub dialogue_response: Option<DialogueResponseEvent>,
}
/// Game time data for client display (D-031)
@@ -300,6 +306,10 @@ pub enum PlayerAction {
UsePerceptionMode(String),
Pause,
Unpause,
/// Player walked away during active dialogue (WASD during conversation, D-064).
/// Client sends this when movement input is detected while dialogue box is visible.
/// Server records incomplete interaction in KG and clears dialogue state.
WalkAway,
/// Set tick rate: Full (1.0), Half (0.5), or Paused (0.0) per D-052
SetTickRate(TickRate),
/// Move one step up the stance ladder (toward Sprint) per D-053
@@ -434,6 +444,18 @@ pub struct MonologueEvent {
pub duration_seconds: f32,
}
/// Dialogue response event sent to the client for display (#305, D-028).
/// Contains the selected line and speaker identity. Client renders a dialogue box.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DialogueResponseEvent {
/// Dialogue line ID (for dedup and cooldown tracking)
pub line_id: String,
/// The dialogue text to display
pub text: String,
/// Wire-format entity identifier of the speaking NPC
pub speaker_entity_id: u64,
}
/// Snapshot buffer resource for staging outgoing ObserverSnapshots
#[derive(Resource, Debug, Default)]
pub struct SnapshotBuffer {