1use crate::dispatch::DispatchStrategy;
8use crate::events::EventBus;
9use crate::hooks::Phase;
10use crate::ids::GroupId;
11use crate::metrics::Metrics;
12use crate::systems::PhaseContext;
13use std::collections::BTreeMap;
14
15impl super::Simulation {
16 #[must_use]
20 pub fn dispatchers(&self) -> &BTreeMap<GroupId, Box<dyn DispatchStrategy>> {
21 &self.dispatchers
22 }
23
24 pub fn dispatchers_mut(&mut self) -> &mut BTreeMap<GroupId, Box<dyn DispatchStrategy>> {
26 &mut self.dispatchers
27 }
28
29 pub const fn events_mut(&mut self) -> &mut EventBus {
31 &mut self.events
32 }
33
34 pub const fn metrics_mut(&mut self) -> &mut Metrics {
36 &mut self.metrics
37 }
38
39 #[must_use]
41 pub const fn phase_context(&self) -> PhaseContext {
42 PhaseContext {
43 tick: self.tick,
44 dt: self.dt,
45 }
46 }
47
48 pub fn run_advance_transient(&mut self) {
68 self.tick_in_progress = true;
69 self.sync_world_tick();
70 self.hooks
71 .run_before(Phase::AdvanceTransient, &mut self.world);
72 for group in &self.groups {
73 self.hooks
74 .run_before_group(Phase::AdvanceTransient, group.id(), &mut self.world);
75 }
76 let ctx = self.phase_context();
77 crate::systems::advance_transient::run(
78 &mut self.world,
79 &mut self.events,
80 &ctx,
81 &mut self.rider_index,
82 );
83 for group in &self.groups {
84 self.hooks
85 .run_after_group(Phase::AdvanceTransient, group.id(), &mut self.world);
86 }
87 self.hooks
88 .run_after(Phase::AdvanceTransient, &mut self.world);
89 }
90
91 pub fn run_dispatch(&mut self) {
93 self.sync_world_tick();
94 self.hooks.run_before(Phase::Dispatch, &mut self.world);
95 for group in &self.groups {
96 self.hooks
97 .run_before_group(Phase::Dispatch, group.id(), &mut self.world);
98 }
99 let ctx = self.phase_context();
100 crate::systems::dispatch::run(
101 &mut self.world,
102 &mut self.events,
103 &ctx,
104 &self.groups,
105 &mut self.dispatchers,
106 &self.rider_index,
107 &mut self.dispatch_scratch,
108 );
109 for group in &self.groups {
110 self.hooks
111 .run_after_group(Phase::Dispatch, group.id(), &mut self.world);
112 }
113 self.hooks.run_after(Phase::Dispatch, &mut self.world);
114 }
115
116 pub fn run_movement(&mut self) {
118 self.hooks.run_before(Phase::Movement, &mut self.world);
119 for group in &self.groups {
120 self.hooks
121 .run_before_group(Phase::Movement, group.id(), &mut self.world);
122 }
123 let ctx = self.phase_context();
124 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
125 crate::systems::movement::run(
126 &mut self.world,
127 &mut self.events,
128 &ctx,
129 &self.elevator_ids_buf,
130 &mut self.metrics,
131 );
132 for group in &self.groups {
133 self.hooks
134 .run_after_group(Phase::Movement, group.id(), &mut self.world);
135 }
136 self.hooks.run_after(Phase::Movement, &mut self.world);
137 }
138
139 pub fn run_doors(&mut self) {
141 self.hooks.run_before(Phase::Doors, &mut self.world);
142 for group in &self.groups {
143 self.hooks
144 .run_before_group(Phase::Doors, group.id(), &mut self.world);
145 }
146 let ctx = self.phase_context();
147 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
148 crate::systems::doors::run(
149 &mut self.world,
150 &mut self.events,
151 &ctx,
152 &self.groups,
153 &self.elevator_ids_buf,
154 );
155 for group in &self.groups {
156 self.hooks
157 .run_after_group(Phase::Doors, group.id(), &mut self.world);
158 }
159 self.hooks.run_after(Phase::Doors, &mut self.world);
160 }
161
162 pub fn run_loading(&mut self) {
164 self.hooks.run_before(Phase::Loading, &mut self.world);
165 for group in &self.groups {
166 self.hooks
167 .run_before_group(Phase::Loading, group.id(), &mut self.world);
168 }
169 let ctx = self.phase_context();
170 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
171 crate::systems::loading::run(
172 &mut self.world,
173 &mut self.events,
174 &ctx,
175 &self.groups,
176 &self.elevator_ids_buf,
177 &mut self.rider_index,
178 );
179 for group in &self.groups {
180 self.hooks
181 .run_after_group(Phase::Loading, group.id(), &mut self.world);
182 }
183 self.hooks.run_after(Phase::Loading, &mut self.world);
184 }
185
186 pub fn run_advance_queue(&mut self) {
192 self.hooks.run_before(Phase::AdvanceQueue, &mut self.world);
193 for group in &self.groups {
194 self.hooks
195 .run_before_group(Phase::AdvanceQueue, group.id(), &mut self.world);
196 }
197 let ctx = self.phase_context();
198 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
199 crate::systems::advance_queue::run(
200 &mut self.world,
201 &mut self.events,
202 &ctx,
203 &self.groups,
204 &self.elevator_ids_buf,
205 );
206 for group in &self.groups {
207 self.hooks
208 .run_after_group(Phase::AdvanceQueue, group.id(), &mut self.world);
209 }
210 self.hooks.run_after(Phase::AdvanceQueue, &mut self.world);
211 }
212
213 pub fn run_reposition(&mut self) {
221 self.sync_world_tick();
222 self.hooks.run_before(Phase::Reposition, &mut self.world);
223 if !self.repositioners.is_empty() {
224 for group in &self.groups {
226 if self.repositioners.contains_key(&group.id()) {
227 self.hooks
228 .run_before_group(Phase::Reposition, group.id(), &mut self.world);
229 }
230 }
231 let ctx = self.phase_context();
232 crate::systems::reposition::run(
233 &mut self.world,
234 &mut self.events,
235 &ctx,
236 &self.groups,
237 &mut self.repositioners,
238 &mut self.reposition_buf,
239 );
240 for group in &self.groups {
241 if self.repositioners.contains_key(&group.id()) {
242 self.hooks
243 .run_after_group(Phase::Reposition, group.id(), &mut self.world);
244 }
245 }
246 }
247 self.hooks.run_after(Phase::Reposition, &mut self.world);
248 }
249
250 #[cfg(feature = "energy")]
252 fn run_energy(&mut self) {
253 let ctx = self.phase_context();
254 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
255 crate::systems::energy::run(
256 &mut self.world,
257 &mut self.events,
258 &ctx,
259 &self.elevator_ids_buf,
260 );
261 }
262
263 pub fn run_metrics(&mut self) {
265 self.hooks.run_before(Phase::Metrics, &mut self.world);
266 for group in &self.groups {
267 self.hooks
268 .run_before_group(Phase::Metrics, group.id(), &mut self.world);
269 }
270 let ctx = self.phase_context();
271 crate::systems::metrics::run(
272 &mut self.world,
273 &self.events,
274 &mut self.metrics,
275 &ctx,
276 &self.groups,
277 );
278 for group in &self.groups {
279 self.hooks
280 .run_after_group(Phase::Metrics, group.id(), &mut self.world);
281 }
282 self.hooks.run_after(Phase::Metrics, &mut self.world);
283 }
284
285 pub fn advance_tick(&mut self) {
292 self.pending_output.extend(self.events.drain());
293 self.tick += 1;
294 self.tick_in_progress = false;
295 self.sync_world_tick();
299 let retention = self
303 .world
304 .resource::<crate::arrival_log::ArrivalLogRetention>()
305 .copied()
306 .unwrap_or_default()
307 .0;
308 let cutoff = self.tick.saturating_sub(retention);
309 if let Some(log) = self.world.resource_mut::<crate::arrival_log::ArrivalLog>() {
310 log.prune_before(cutoff);
311 }
312 if let Some(log) = self
313 .world
314 .resource_mut::<crate::arrival_log::DestinationLog>()
315 {
316 log.prune_before(cutoff);
317 }
318 }
319
320 fn sync_world_tick(&mut self) {
326 if let Some(ct) = self.world.resource_mut::<crate::arrival_log::CurrentTick>() {
327 ct.0 = self.tick;
328 }
329 }
330
331 pub fn step(&mut self) {
345 self.sync_world_tick();
346 self.world.snapshot_prev_positions();
347 self.run_advance_transient();
348 self.run_dispatch();
349 self.run_reposition();
350 self.run_advance_queue();
351 self.run_movement();
352 self.run_doors();
353 self.run_loading();
354 #[cfg(feature = "energy")]
355 self.run_energy();
356 self.run_metrics();
357 self.advance_tick();
358 }
359
360 pub fn run_until_quiet(&mut self, max_ticks: u64) -> Result<u64, u64> {
390 use crate::components::RiderPhase;
391
392 fn all_quiet(sim: &super::Simulation) -> bool {
393 sim.world().iter_riders().all(|(_, r)| {
394 matches!(
395 r.phase(),
396 RiderPhase::Arrived | RiderPhase::Abandoned | RiderPhase::Resident
397 )
398 })
399 }
400
401 if all_quiet(self) {
402 return Ok(0);
403 }
404 for tick in 1..=max_ticks {
405 self.step();
406 let _ = self.drain_events();
407 if all_quiet(self) {
408 return Ok(tick);
409 }
410 }
411 Err(max_ticks)
412 }
413}