feat(simulation): add proximity detection and interaction verbs
Implement compute_nearby_interactions system that detects entities within close (≤2) and mid (≤5) Manhattan distance, computes available verbs per D-060 spec. NPCs get Talk+Observe at close range, Observe-only at mid range; PersonOfInterest flips priority. Objects get Examine. Results populate nearby_interactions[] on ObserverSnapshot v4. Bump protocol version 3→4. Implements #404. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,7 +102,8 @@ pub fn generate_snapshot(
|
||||
day: time.day(),
|
||||
time_of_day: time.time_of_day_minutes(),
|
||||
day_phase: time.day_phase(),
|
||||
paused: time.paused,
|
||||
paused: time.paused(),
|
||||
tick_rate: time.tick_rate,
|
||||
};
|
||||
|
||||
tracing::trace!(
|
||||
@@ -111,12 +112,13 @@ pub fn generate_snapshot(
|
||||
visible.len()
|
||||
);
|
||||
buffer.snapshot = Some(ObserverSnapshot {
|
||||
version: 3,
|
||||
version: 4,
|
||||
tick: time.tick,
|
||||
game_time,
|
||||
player_facing: FacingDirection::default(),
|
||||
entities: visible,
|
||||
visible_tiles: Vec::new(), // Empty until #112 adds LOS filtering
|
||||
nearby_interactions: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,18 +6,19 @@ use bevy_ecs::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use crate::knowledge::types::{EntityVisibility, KnowledgeConfidence, RelationshipState};
|
||||
pub use crate::simulation::time::DayPhase;
|
||||
pub use crate::simulation::time::{DayPhase, TickRate};
|
||||
|
||||
/// The ONLY data structure crossing the client-server boundary (D-020)
|
||||
/// Contains all information visible to the observer at a given tick.
|
||||
///
|
||||
/// v2 adds: game_time, player_facing, visible_tiles, visibility sectors.
|
||||
/// v3 adds: relationship (D-033 entity color), observation (Visible/Remembered).
|
||||
/// v4 adds: nearby_interactions (D-060, #404 proximity + verbs[]).
|
||||
/// Future fields: ambient sound events, internal monologue triggers,
|
||||
/// HUD state (D-020 expansion).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ObserverSnapshot {
|
||||
/// Protocol version for forward compatibility. Current: 3.
|
||||
/// Protocol version for forward compatibility. Current: 4.
|
||||
pub version: u8,
|
||||
/// Simulation tick when this snapshot was produced
|
||||
pub tick: u64,
|
||||
@@ -29,6 +30,10 @@ pub struct ObserverSnapshot {
|
||||
pub entities: Vec<VisibleEntity>,
|
||||
/// Tiles visible to the observer for fog rendering
|
||||
pub visible_tiles: Vec<VisibleTile>,
|
||||
/// Entities within interaction range with available verbs (D-060, #404).
|
||||
/// Sorted by distance (nearest first). v0.1 client reads verbs[0] on the nearest entity.
|
||||
#[serde(default)]
|
||||
pub nearby_interactions: Vec<NearbyInteraction>,
|
||||
}
|
||||
|
||||
/// Game time data for client display (D-031)
|
||||
@@ -41,8 +46,11 @@ pub struct GameTime {
|
||||
pub time_of_day: u64,
|
||||
/// Current day phase (Morning/Afternoon/Evening/Night)
|
||||
pub day_phase: DayPhase,
|
||||
/// Whether simulation is paused
|
||||
/// Whether simulation is paused (tick_rate == Paused)
|
||||
pub paused: bool,
|
||||
/// Current tick rate state (D-052)
|
||||
#[serde(default)]
|
||||
pub tick_rate: TickRate,
|
||||
}
|
||||
|
||||
/// 8-directional facing direction, matching movement system.
|
||||
@@ -136,6 +144,45 @@ pub enum PlayerAction {
|
||||
UsePerceptionMode(String),
|
||||
Pause,
|
||||
Unpause,
|
||||
/// Set tick rate: Full (1.0), Half (0.5), or Paused (0.0) per D-052
|
||||
SetTickRate(TickRate),
|
||||
}
|
||||
|
||||
/// Available interaction verbs for a nearby entity (D-060, #404)
|
||||
/// Embedded in ObserverSnapshot.nearby_interactions.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct NearbyInteraction {
|
||||
/// Wire-format entity identifier
|
||||
pub entity_id: u64,
|
||||
/// Entity type for client-side verb display
|
||||
pub entity_type: EntityKind,
|
||||
/// Manhattan distance from player
|
||||
pub distance: f32,
|
||||
/// Available verbs sorted by priority (index 0 = highest priority)
|
||||
pub verbs: Vec<VerbOption>,
|
||||
}
|
||||
|
||||
/// A single available verb on a nearby entity
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VerbOption {
|
||||
/// Verb type
|
||||
pub kind: VerbKind,
|
||||
/// Display label for the context prompt (e.g. "Talk", "Observe", "Examine")
|
||||
pub label: String,
|
||||
/// Priority rank (lower = higher priority). v0.1 client reads only priority 1.
|
||||
pub priority: u8,
|
||||
/// Whether this verb is currently available (false = greyed out in v0.2)
|
||||
pub available: bool,
|
||||
}
|
||||
|
||||
/// Verb types for the interaction system (D-060)
|
||||
/// Only active verbs appear in verbs[]. Passive (Look, Overhear) and
|
||||
/// reactive (Monologue) verbs fire independently.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum VerbKind {
|
||||
ExamineObject,
|
||||
ExamineNpc,
|
||||
Talk,
|
||||
}
|
||||
|
||||
/// Snapshot buffer resource for staging outgoing ObserverSnapshots
|
||||
|
||||
Reference in New Issue
Block a user