//! Economy phase plugin — tâtonnement simulation tick and IPC query serving. //! //! All systems run in [`TickPhase::Economy`]. Intra-phase ordering: //! - tick_economy_simulation → serve_econ_state_query (query reads fresh signals) //! //! T-970 (D-226 layer 1): `tick_economy_simulation` is individually gated with //! `sim_not_paused` so it freezes while the sim is paused — but //! `serve_econ_state_query` stays unconditioned so the paused-allowed //! `EconStateQuery` (input.rs) keeps being served. `TickPhase::Economy` itself //! is deliberately NOT set-gated in `tick_phases.rs` for exactly this reason. //! `.after()` ordering still holds when the upstream system is skipped by its //! own run condition — a run condition only prevents a system from running, //! it doesn't relax the ordering edge for the passes where both do run. use bevy_app::prelude::*; use bevy_ecs::schedule::IntoScheduleConfigs; use crate::simulation::time::sim_not_paused; use crate::tick_phases::TickPhase; pub struct EconomyPlugin { /// World seed from `StartupMessage` (#826). Passed to `try_load_economy` so the /// tâtonnement simulation is seeded deterministically from the client's world seed. pub seed: u64, } impl Plugin for EconomyPlugin { fn build(&self, app: &mut App) { // Economy simulation (#821, D-031) — loaded once at startup, no-op when DB absent. // Seed comes from StartupMessage.world_seed, threaded via SimulationPlugin (#826). if let Some((econ_sim, econ_state)) = super::economy::try_load_economy(self.seed) { app.insert_resource(econ_sim).insert_resource(econ_state); } // EconQueryBuffer: always registered so EconStateQuery PlayerActions are accepted // even when the economy DB is absent (queries just produce no response). app.init_resource::() .add_systems( Update, ( super::economy::tick_economy_simulation.run_if(sim_not_paused), super::economy::serve_econ_state_query .after(super::economy::tick_economy_simulation), ) .in_set(TickPhase::Economy), ); } }