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.elevator_ids_buf,
153 );
154 for group in &self.groups {
155 self.hooks
156 .run_after_group(Phase::Doors, group.id(), &mut self.world);
157 }
158 self.hooks.run_after(Phase::Doors, &mut self.world);
159 }
160
161 pub fn run_loading(&mut self) {
163 self.hooks.run_before(Phase::Loading, &mut self.world);
164 for group in &self.groups {
165 self.hooks
166 .run_before_group(Phase::Loading, group.id(), &mut self.world);
167 }
168 let ctx = self.phase_context();
169 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
170 crate::systems::loading::run(
171 &mut self.world,
172 &mut self.events,
173 &ctx,
174 &self.elevator_ids_buf,
175 &mut self.rider_index,
176 );
177 for group in &self.groups {
178 self.hooks
179 .run_after_group(Phase::Loading, group.id(), &mut self.world);
180 }
181 self.hooks.run_after(Phase::Loading, &mut self.world);
182 }
183
184 pub fn run_advance_queue(&mut self) {
190 self.hooks.run_before(Phase::AdvanceQueue, &mut self.world);
191 for group in &self.groups {
192 self.hooks
193 .run_before_group(Phase::AdvanceQueue, group.id(), &mut self.world);
194 }
195 let ctx = self.phase_context();
196 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
197 crate::systems::advance_queue::run(
198 &mut self.world,
199 &mut self.events,
200 &ctx,
201 &self.elevator_ids_buf,
202 );
203 for group in &self.groups {
204 self.hooks
205 .run_after_group(Phase::AdvanceQueue, group.id(), &mut self.world);
206 }
207 self.hooks.run_after(Phase::AdvanceQueue, &mut self.world);
208 }
209
210 pub fn run_reposition(&mut self) {
218 self.sync_world_tick();
219 self.hooks.run_before(Phase::Reposition, &mut self.world);
220 if !self.repositioners.is_empty() {
221 for group in &self.groups {
223 if self.repositioners.contains_key(&group.id()) {
224 self.hooks
225 .run_before_group(Phase::Reposition, group.id(), &mut self.world);
226 }
227 }
228 let ctx = self.phase_context();
229 crate::systems::reposition::run(
230 &mut self.world,
231 &mut self.events,
232 &ctx,
233 &self.groups,
234 &mut self.repositioners,
235 &mut self.reposition_buf,
236 );
237 for group in &self.groups {
238 if self.repositioners.contains_key(&group.id()) {
239 self.hooks
240 .run_after_group(Phase::Reposition, group.id(), &mut self.world);
241 }
242 }
243 }
244 self.hooks.run_after(Phase::Reposition, &mut self.world);
245 }
246
247 #[cfg(feature = "energy")]
249 fn run_energy(&mut self) {
250 let ctx = self.phase_context();
251 self.world.elevator_ids_into(&mut self.elevator_ids_buf);
252 crate::systems::energy::run(
253 &mut self.world,
254 &mut self.events,
255 &ctx,
256 &self.elevator_ids_buf,
257 );
258 }
259
260 pub fn run_metrics(&mut self) {
262 self.hooks.run_before(Phase::Metrics, &mut self.world);
263 for group in &self.groups {
264 self.hooks
265 .run_before_group(Phase::Metrics, group.id(), &mut self.world);
266 }
267 let ctx = self.phase_context();
268 crate::systems::metrics::run(
269 &mut self.world,
270 &self.events,
271 &mut self.metrics,
272 &ctx,
273 &self.groups,
274 );
275 for group in &self.groups {
276 self.hooks
277 .run_after_group(Phase::Metrics, group.id(), &mut self.world);
278 }
279 self.hooks.run_after(Phase::Metrics, &mut self.world);
280 }
281
282 pub fn advance_tick(&mut self) {
289 self.pending_output.extend(self.events.drain());
290 self.tick += 1;
291 self.tick_in_progress = false;
292 self.sync_world_tick();
296 let retention = self
300 .world
301 .resource::<crate::arrival_log::ArrivalLogRetention>()
302 .copied()
303 .unwrap_or_default()
304 .0;
305 let cutoff = self.tick.saturating_sub(retention);
306 if let Some(log) = self.world.resource_mut::<crate::arrival_log::ArrivalLog>() {
307 log.prune_before(cutoff);
308 }
309 if let Some(log) = self
310 .world
311 .resource_mut::<crate::arrival_log::DestinationLog>()
312 {
313 log.prune_before(cutoff);
314 }
315 }
316
317 fn sync_world_tick(&mut self) {
323 if let Some(ct) = self.world.resource_mut::<crate::arrival_log::CurrentTick>() {
324 ct.0 = self.tick;
325 }
326 }
327
328 pub fn step(&mut self) {
342 self.sync_world_tick();
343 self.world.snapshot_prev_positions();
344 self.run_advance_transient();
345 self.run_dispatch();
346 self.run_reposition();
347 self.run_advance_queue();
348 self.run_movement();
349 self.run_doors();
350 self.run_loading();
351 #[cfg(feature = "energy")]
352 self.run_energy();
353 self.run_metrics();
354 self.advance_tick();
355 }
356
357 pub fn run_until_quiet(&mut self, max_ticks: u64) -> Result<u64, u64> {
387 use crate::components::RiderPhase;
388
389 fn all_quiet(sim: &super::Simulation) -> bool {
390 sim.world().iter_riders().all(|(_, r)| {
391 matches!(
392 r.phase(),
393 RiderPhase::Arrived | RiderPhase::Abandoned | RiderPhase::Resident
394 )
395 })
396 }
397
398 if all_quiet(self) {
399 return Ok(0);
400 }
401 for tick in 1..=max_ticks {
402 self.step();
403 let _ = self.drain_events();
404 if all_quiet(self) {
405 return Ok(tick);
406 }
407 }
408 Err(max_ticks)
409 }
410}