fix(simulation): address PR #42 review — 8 items from Hoshe and Tyre
1. Sound producers: document empty v0.1 pipeline explicitly (critical) 2. Routine tests: add ActiveSim to 3 tests that passed trivially 3. Rename _observer_pos → observer_pos (used at line 191) 4. Add FactionOnly positive test case (matching faction_id) 5. Fix stale doc comment "Current: 9" → 10 in ObserverSnapshot 6. Remove orphaned SimulationTier/LastInteraction/ScopeTag types 7. Add tracing::warn on FactionOnly non-numeric parse failure 8. Document Medium-range occlusion gap as TODO in audible_at 9. Insert SoundEventQueue in observer test setup_world Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -83,7 +83,9 @@ impl SoundEvent {
|
||||
}
|
||||
|
||||
/// Whether this sound is audible at `listener_pos`.
|
||||
/// Simple tile-distance check; occlusion is a future concern (D-018 note).
|
||||
/// Simple tile-distance check — no wall/obstruction occlusion.
|
||||
/// TODO: Medium-range sounds should be attenuated or blocked by walls
|
||||
/// per D-018. Requires LOS integration (backlog — not in v0.1 scope).
|
||||
pub fn audible_at(&self, listener_pos: &TilePosition) -> bool {
|
||||
let ceil = Self::max_range_tiles(self.range);
|
||||
let dx = (self.x.floor() as i32).abs_diff(listener_pos.x);
|
||||
@@ -157,6 +159,13 @@ impl SoundEventQueue {
|
||||
/// Runs each tick after movement/monologue/dialogue systems have fired.
|
||||
/// Removes the emitter component after draining. Ordering: after movement,
|
||||
/// before `compute_observer_snapshot`.
|
||||
///
|
||||
/// NOTE: v0.1 has no sound producers — no system currently inserts
|
||||
/// SoundEventEmitter components. The pipeline (emitter → queue → snapshot →
|
||||
/// client bridge) is fully wired but produces zero events at runtime.
|
||||
/// Sound producers (Footstep on movement, Voice on dialogue) are backlog
|
||||
/// scope and will be added when the client audio bus routing (#125) is
|
||||
/// integrated. See D-018 for the sound model specification.
|
||||
pub fn collect_sound_events(
|
||||
mut commands: Commands,
|
||||
mut queue: ResMut<SoundEventQueue>,
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::simulation::movement::{PlayerCharacter, TilePosition};
|
||||
|
||||
// --- Tier radius constants (D-026) ---
|
||||
@@ -131,68 +129,11 @@ pub fn update_tier_markers(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum SimulationTier {
|
||||
Active,
|
||||
Background,
|
||||
StateSaved,
|
||||
Ungenerated,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Clone)]
|
||||
pub struct LastInteraction {
|
||||
pub tick: u64,
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Clone)]
|
||||
pub struct ScopeTag {
|
||||
pub tags: Vec<ScopeKind>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum ScopeKind {
|
||||
Neighborhood,
|
||||
ActiveQuest,
|
||||
Colleague,
|
||||
KnownContact,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bevy_ecs::world::World;
|
||||
|
||||
// --- SimulationTier enum tests ---
|
||||
|
||||
#[test]
|
||||
fn tier_can_be_added_and_queried() {
|
||||
let mut world = World::new();
|
||||
let entity = world.spawn(SimulationTier::Active).id();
|
||||
assert_eq!(
|
||||
*world.get::<SimulationTier>(entity).unwrap(),
|
||||
SimulationTier::Active
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tier_can_transition() {
|
||||
let mut world = World::new();
|
||||
let entity = world.spawn(SimulationTier::Active).id();
|
||||
world.entity_mut(entity).insert(SimulationTier::Background);
|
||||
assert_eq!(
|
||||
*world.get::<SimulationTier>(entity).unwrap(),
|
||||
SimulationTier::Background
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_tier_variants_are_distinct() {
|
||||
assert_ne!(SimulationTier::Active, SimulationTier::Background);
|
||||
assert_ne!(SimulationTier::Background, SimulationTier::StateSaved);
|
||||
assert_ne!(SimulationTier::StateSaved, SimulationTier::Ungenerated);
|
||||
assert_ne!(SimulationTier::Active, SimulationTier::Ungenerated);
|
||||
}
|
||||
|
||||
// --- Marker component query correctness (D-026, #94) ---
|
||||
// These tests verify that With<ActiveSim> / With<BackgroundSim> / With<StateSaved>
|
||||
// filter correctly — the core guarantee that behavior systems only run for the
|
||||
@@ -338,57 +279,6 @@ mod tests {
|
||||
assert!(world.get::<ActiveSim>(entity).is_none());
|
||||
}
|
||||
|
||||
// --- LastInteraction and ScopeTag ---
|
||||
|
||||
#[test]
|
||||
fn last_interaction_records_tick() {
|
||||
let mut world = World::new();
|
||||
let entity = world.spawn(LastInteraction { tick: 42 }).id();
|
||||
|
||||
let interaction = world.get::<LastInteraction>(entity).unwrap();
|
||||
assert_eq!(interaction.tick, 42);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_interaction_tick_can_be_updated() {
|
||||
let mut world = World::new();
|
||||
let entity = world.spawn(LastInteraction { tick: 1 }).id();
|
||||
|
||||
world.entity_mut(entity).insert(LastInteraction { tick: 100 });
|
||||
|
||||
let interaction = world.get::<LastInteraction>(entity).unwrap();
|
||||
assert_eq!(interaction.tick, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scope_tag_neighborhood_kind() {
|
||||
let mut world = World::new();
|
||||
let entity = world
|
||||
.spawn(ScopeTag {
|
||||
tags: vec![ScopeKind::Neighborhood],
|
||||
})
|
||||
.id();
|
||||
|
||||
let tag = world.get::<ScopeTag>(entity).unwrap();
|
||||
assert!(tag.tags.contains(&ScopeKind::Neighborhood));
|
||||
assert!(!tag.tags.contains(&ScopeKind::ActiveQuest));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scope_tag_multiple_kinds() {
|
||||
let entity = ScopeTag {
|
||||
tags: vec![
|
||||
ScopeKind::Neighborhood,
|
||||
ScopeKind::Colleague,
|
||||
ScopeKind::KnownContact,
|
||||
],
|
||||
};
|
||||
assert_eq!(entity.tags.len(), 3);
|
||||
assert!(entity.tags.contains(&ScopeKind::Colleague));
|
||||
assert!(entity.tags.contains(&ScopeKind::KnownContact));
|
||||
assert!(!entity.tags.contains(&ScopeKind::ActiveQuest));
|
||||
}
|
||||
|
||||
// --- TierPlugin smoke test ---
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user