feat(simulation): protocol v14 — POI list, examine result, player knowledge wire types
Add three new ObserverSnapshot fields for client Sprint 18 tickets: poi_list (Vec<PoiWire>) for minimap #151, examine_result (Option<ExamineResultWire>) for #174, player_knowledge (Option<PlayerKnowledgeWire>) for journal #264. POI list populated live from KG-discovered PointOfInterest components. KG dump serializes entity/fact knowledge with confidence, source, and state. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -308,6 +308,9 @@ mod tests {
|
||||
follow_state: None,
|
||||
sound_events: vec![],
|
||||
rng_seed: None,
|
||||
poi_list: vec![],
|
||||
examine_result: None,
|
||||
player_knowledge: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,6 +441,9 @@ mod tests {
|
||||
follow_state: None,
|
||||
sound_events: vec![],
|
||||
rng_seed: None,
|
||||
poi_list: vec![],
|
||||
examine_result: None,
|
||||
player_knowledge: None,
|
||||
};
|
||||
let text = format_snapshot_text(&snap);
|
||||
assert!(text.contains("Tick 0"));
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
use bevy_ecs::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::knowledge::types::{EntityVisibility, KnowledgeConfidence, RelationshipState};
|
||||
pub use crate::knowledge::types::{
|
||||
EntityVisibility, KnowledgeConfidence, KnowledgeState, RelationshipState,
|
||||
};
|
||||
pub use crate::simulation::time::{DayPhase, TickRate};
|
||||
|
||||
/// Wire protocol version for ObserverSnapshot.
|
||||
@@ -15,7 +17,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 = 13;
|
||||
pub const PROTOCOL_VERSION: u8 = 14;
|
||||
|
||||
/// The ONLY data structure crossing the client-server boundary (D-020)
|
||||
/// Contains all information visible to the observer at a given tick.
|
||||
@@ -34,6 +36,9 @@ pub const PROTOCOL_VERSION: u8 = 13;
|
||||
/// v12 adds: conversation_events, conversation_ended (#247, D-078 NPC-to-NPC conversations).
|
||||
/// v13 adds: tell_state on VisibleEntity (#90, D-024 tell system — for future client use),
|
||||
/// follow_state (#241, follow mechanic HUD state).
|
||||
/// v14 adds: poi_list (#151, discovered POIs for minimap rendering),
|
||||
/// examine_result (#174, character-filtered observation text from Examine verb),
|
||||
/// player_knowledge (#264, partial KG dump for journal/knowledge panel).
|
||||
/// Future fields: ambient sound events, HUD state (D-020 expansion).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ObserverSnapshot {
|
||||
@@ -110,6 +115,22 @@ pub struct ObserverSnapshot {
|
||||
/// None when the RNG resource is unavailable (should not occur in practice).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub rng_seed: Option<u64>,
|
||||
/// Discovered POIs for minimap rendering (#151, D-013).
|
||||
/// Contains all POIs the observer has discovered (fact in KG).
|
||||
/// Client renders nearby POIs as dots, distant POIs as directional arrows.
|
||||
/// Empty when no POIs have been discovered.
|
||||
#[serde(default)]
|
||||
pub poi_list: Vec<PoiWire>,
|
||||
/// Character-filtered observation text from Examine verb (#174, #242).
|
||||
/// Present when an examine interaction completed this tick.
|
||||
/// Client displays as non-interactive overlay, auto-dismisses after 4-6 seconds.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub examine_result: Option<ExamineResultWire>,
|
||||
/// Partial knowledge graph dump for journal/knowledge panel (#264, D-041).
|
||||
/// Updated periodically (not every tick — only when KG changes).
|
||||
/// Client renders as a read-only journal grouped by entity.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub player_knowledge: Option<PlayerKnowledgeWire>,
|
||||
}
|
||||
|
||||
/// Game time data for client display (D-031)
|
||||
@@ -536,6 +557,82 @@ pub struct DialogueResponseEvent {
|
||||
pub speaker_name: String,
|
||||
}
|
||||
|
||||
/// A discovered POI crossing the wire for minimap rendering (#151).
|
||||
/// Derived from PointOfInterest component + KG fact lookup.
|
||||
/// Client converts position to player-relative vector for minimap display.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PoiWire {
|
||||
/// POI identifier (matches poi_id in PointOfInterest component).
|
||||
pub poi_id: String,
|
||||
/// Display name for minimap label.
|
||||
pub name: String,
|
||||
/// World position in simulation tile coordinates.
|
||||
/// Client converts to player-relative vector for compass placement.
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub z: i32,
|
||||
/// Category for icon/color selection on minimap.
|
||||
pub category: crate::simulation::poi::PoiCategory,
|
||||
}
|
||||
|
||||
/// Character-filtered observation text from Examine verb (#174, #242).
|
||||
/// The server runs the examine through the observer's KG to produce
|
||||
/// text appropriate to what the character knows/sees.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ExamineResultWire {
|
||||
/// Wire-format entity ID of the examined entity.
|
||||
pub entity_id: u64,
|
||||
/// Character-filtered observation text.
|
||||
pub text: String,
|
||||
/// Observer's confidence level about this entity at time of examine.
|
||||
pub confidence: KnowledgeConfidence,
|
||||
}
|
||||
|
||||
/// Partial knowledge graph dump for the journal panel (#264, D-041).
|
||||
/// Sent when KG state changes. Contains entity knowledge and fact knowledge
|
||||
/// that the observer has accumulated.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlayerKnowledgeWire {
|
||||
/// Known entities with their knowledge metadata.
|
||||
pub entities: Vec<KnownEntityWire>,
|
||||
/// Known facts (non-entity knowledge: POIs, events, abstract info).
|
||||
pub facts: Vec<KnownFactWire>,
|
||||
}
|
||||
|
||||
/// A single entity knowledge entry for the journal wire format (#264).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct KnownEntityWire {
|
||||
/// Wire-format entity ID.
|
||||
pub entity_id: u64,
|
||||
/// Display name (from known_attributes if available, else "Unknown").
|
||||
pub name: String,
|
||||
/// Confidence level (Suspects / KnowsOf / KnowsDetails / Direct).
|
||||
pub confidence: KnowledgeConfidence,
|
||||
/// How the knowledge was acquired.
|
||||
pub source: String,
|
||||
/// Logical state (Active / Contradicted / Stale).
|
||||
pub state: KnowledgeState,
|
||||
/// Relationship assessment for color rendering.
|
||||
pub relationship: RelationshipState,
|
||||
/// Last tick this entity was observed.
|
||||
pub last_observed_tick: u64,
|
||||
}
|
||||
|
||||
/// A single fact knowledge entry for the journal wire format (#264).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct KnownFactWire {
|
||||
/// Fact identifier (e.g. "poi.docking_bay_7", "contraband.ring_exists").
|
||||
pub fact_id: String,
|
||||
/// Confidence level.
|
||||
pub confidence: KnowledgeConfidence,
|
||||
/// How the fact was acquired.
|
||||
pub source: String,
|
||||
/// Logical state.
|
||||
pub state: KnowledgeState,
|
||||
/// Tick when this fact was learned.
|
||||
pub acquired_tick: u64,
|
||||
}
|
||||
|
||||
/// Snapshot buffer resource for staging outgoing ObserverSnapshots
|
||||
#[derive(Resource, Debug, Default)]
|
||||
pub struct SnapshotBuffer {
|
||||
|
||||
Reference in New Issue
Block a user