refactor(simulation): replace ad-hoc system ordering with TickPhase pipeline (#843)
10-phase linear pipeline: PreInput → Input → Movement → Simulation → Economy → Storyteller → Snapshot → PostSnapshot → Knowledge → TickAdvance. Each system assigned to exactly one phase via .in_set(TickPhase::X). Cross-phase .after()/.before() eliminated — only intra-phase ordering remains. Prevents schedule cycles by construction. SimulationPlugin refactored into sub-plugins by domain: - InputPlugin (player actions, interactions, dialogue dispatch) - MovementPlugin (pathfinding, movement validation, spatial indexing) - SocialPlugin (conversations, sound, voice enrichment, follow state) - EconomyPlugin (tâtonnement tick, IPC query serving) - TimePlugin (chunk streaming, news ticker, tick advancement) All other plugins (NPC, Knowledge, Perception, Storyteller, Settings, Bridge) updated to use TickPhase assignments instead of cross-plugin ordering constraints. BridgePlugin trimmed to bridge I/O concerns only. Part A of #843. Parts B (multi-threaded executor) and C (background workers) follow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+44
-35
@@ -213,31 +213,36 @@ pub struct BridgePlugin;
|
||||
|
||||
impl Plugin for BridgePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
use crate::tick_phases::TickPhase;
|
||||
|
||||
app.init_resource::<SnapshotBuffer>()
|
||||
.init_resource::<ServerRunning>()
|
||||
.init_resource::<HandshakeState>()
|
||||
.init_resource::<SimErrorBuffer>()
|
||||
.init_resource::<debug::DebugCommandBuffer>()
|
||||
.init_resource::<DebugEnabled>()
|
||||
.init_resource::<crate::perception::query::VisibilityGeometry>()
|
||||
.init_resource::<crate::perception::query::ActivePerceptionMode>()
|
||||
// Bridge I/O — PreInput (receive) and PostSnapshot (send)
|
||||
.add_systems(
|
||||
Update,
|
||||
receive_bridge_inputs.in_set(TickPhase::PreInput),
|
||||
)
|
||||
.add_systems(
|
||||
Update,
|
||||
send_bridge_snapshot.in_set(TickPhase::PostSnapshot),
|
||||
)
|
||||
// Debug commands — Snapshot phase
|
||||
.add_systems(
|
||||
Update,
|
||||
debug::handle_debug_commands
|
||||
.in_set(TickPhase::Snapshot),
|
||||
)
|
||||
// Monologue chain — Simulation phase, strict intra-phase sequence.
|
||||
// trigger_event_monologue must run after conversations + sound (also Simulation).
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
receive_bridge_inputs.before(crate::simulation::input::process_player_input),
|
||||
debug::handle_debug_commands
|
||||
.after(crate::simulation::input::process_player_input)
|
||||
// Note: NOT ordered after tick_economy_simulation — that creates a
|
||||
// schedule cycle (debug → observer → advance_tick → econ → debug).
|
||||
// GetEconState reads from EconStateResource which may be one tick
|
||||
// stale on economy-tick boundaries. Acceptable for debug tooling.
|
||||
.before(crate::perception::observer::compute_observer_snapshot),
|
||||
crate::perception::observer::compute_visibility_geometry
|
||||
.after(crate::simulation::movement::validate_movement),
|
||||
crate::simulation::interaction::compute_nearby_interactions
|
||||
.after(crate::simulation::movement::validate_movement),
|
||||
crate::simulation::monologue::trigger_monologue
|
||||
.after(crate::simulation::movement::validate_movement),
|
||||
crate::simulation::monologue::trigger_monologue,
|
||||
crate::simulation::monologue::trigger_recognition_monologue
|
||||
.after(crate::simulation::monologue::trigger_monologue)
|
||||
.after(crate::perception::anomaly::detect_anomalies),
|
||||
@@ -248,29 +253,33 @@ impl Plugin for BridgePlugin {
|
||||
.after(crate::simulation::sound::collect_sound_events)
|
||||
.after(crate::simulation::conversation::run_npc_conversations)
|
||||
.after(crate::simulation::dialogue::process_walk_away),
|
||||
// Contradiction monologue fires from queue populated by prior tick's
|
||||
// process_knowledge_events (which runs after the snapshot).
|
||||
crate::simulation::monologue::process_contradiction_monologue
|
||||
.after(crate::simulation::monologue::trigger_event_monologue),
|
||||
crate::simulation::follow::update_follow_state
|
||||
.after(crate::perception::observer::compute_visibility_geometry)
|
||||
.after(crate::simulation::movement::validate_movement)
|
||||
.before(crate::perception::observer::compute_observer_snapshot),
|
||||
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_contradiction_monologue)
|
||||
.after(crate::simulation::dialogue::process_talk_interaction)
|
||||
.after(crate::simulation::dialogue::process_confrontation_response)
|
||||
.after(crate::simulation::dialogue::process_dialogue_response)
|
||||
.before(crate::simulation::time::advance_tick),
|
||||
crate::perception::observation::emit_observation_events
|
||||
.after(crate::perception::observer::compute_observer_snapshot)
|
||||
.before(crate::simulation::time::advance_tick),
|
||||
send_bridge_snapshot
|
||||
.after(crate::perception::observer::compute_observer_snapshot),
|
||||
),
|
||||
)
|
||||
.in_set(TickPhase::Simulation),
|
||||
)
|
||||
// Observation systems — Simulation phase (reads positions, feeds snapshot)
|
||||
.add_systems(
|
||||
Update,
|
||||
(
|
||||
crate::perception::observer::compute_visibility_geometry,
|
||||
crate::simulation::interaction::compute_nearby_interactions,
|
||||
)
|
||||
.in_set(TickPhase::Simulation),
|
||||
)
|
||||
// Observer snapshot assembly — Snapshot phase
|
||||
.add_systems(
|
||||
Update,
|
||||
crate::perception::observer::compute_observer_snapshot
|
||||
.in_set(TickPhase::Snapshot),
|
||||
)
|
||||
// Post-snapshot: emit observation events
|
||||
.add_systems(
|
||||
Update,
|
||||
crate::perception::observation::emit_observation_events
|
||||
.in_set(TickPhase::PostSnapshot),
|
||||
);
|
||||
|
||||
tracing::debug!("BridgePlugin initialized");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user