feat(simulation): integrate observer visibility query (#112)

Replace unfiltered generate_snapshot with compute_observer_snapshot
that combines shadowcasting + vision cone to send only visible
entities and tiles. Enforces information asymmetry (D-011): NPCs
behind walls or in the blind spot are excluded from the snapshot.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-12 00:21:07 +01:00
co-authored by Claude Opus 4.6
parent f760624967
commit e205b38938
5 changed files with 381 additions and 3 deletions
+19 -3
View File
@@ -59,7 +59,9 @@ impl BridgeResource {
}
}
/// Generate ObserverSnapshot from ECS state
/// Generate ObserverSnapshot v2 from ECS state.
/// Pre-visibility version: sends ALL entities (no LOS filtering yet).
/// Will be replaced by perception::observer::compute_observer_snapshot in #112.
pub fn generate_snapshot(
time: Res<crate::simulation::time::SimulationTime>,
entities: Query<(
@@ -86,16 +88,29 @@ pub fn generate_snapshot(
y,
z,
kind,
visibility: VisibilitySector::Forward,
});
}
let game_time = GameTime {
day: time.day(),
time_of_day: time.time_of_day_minutes(),
day_phase: time.day_phase(),
paused: time.paused,
};
tracing::trace!(
"generate_snapshot: tick={}, entities={}",
time.tick,
visible.len()
);
buffer.snapshot = Some(ObserverSnapshot {
version: 2,
tick: time.tick,
game_time,
player_facing: FacingDirection::default(),
entities: visible,
visible_tiles: Vec::new(), // Empty until #112 adds LOS filtering
});
}
@@ -159,10 +174,11 @@ impl Plugin for BridgePlugin {
Update,
(
receive_bridge_inputs.before(crate::simulation::input::process_player_input),
generate_snapshot
crate::perception::observer::compute_observer_snapshot
.after(crate::simulation::movement::validate_movement)
.before(crate::simulation::time::advance_tick),
send_bridge_snapshot.after(generate_snapshot),
send_bridge_snapshot
.after(crate::perception::observer::compute_observer_snapshot),
),
);
tracing::debug!("BridgePlugin initialized");