1use super::*;
2use crate::{
3 constants::*,
4 tracks::{ReadyState, TrackHandle, TrackState},
5};
6use std::collections::{BinaryHeap, HashMap};
7use tracing::info;
8
9#[derive(Debug, Default)]
10pub struct EventStore {
17 timed: BinaryHeap<EventData>,
18 untimed: HashMap<UntimedEvent, Vec<EventData>>,
19 local_only: bool,
20}
21
22impl EventStore {
23 #[must_use]
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 #[must_use]
36 pub fn new_local() -> Self {
37 EventStore {
38 local_only: true,
39 ..Default::default()
40 }
41 }
42
43 pub fn add_event(&mut self, mut evt: EventData, now: Duration) {
49 evt.compute_activation(now);
50
51 if self.local_only && evt.event.is_global_only() {
52 return;
53 }
54
55 match evt.event {
56 Event::Core(c) => {
57 self.untimed.entry(c.into()).or_default().push(evt);
58 },
59 Event::Track(t) => {
60 self.untimed.entry(t.into()).or_default().push(evt);
61 },
62 Event::Delayed(_) | Event::Periodic(_, _) => {
63 self.timed.push(evt);
64 },
65 _ => {
66 },
68 }
69 }
70
71 pub(crate) async fn process_timed(&mut self, now: Duration, ctx: EventContext<'_>) {
73 while let Some(evt) = self.timed.peek() {
74 if evt
75 .fire_time
76 .as_ref()
77 .expect("Timed event must have a fire_time.")
78 > &now
79 {
80 break;
81 }
82 let mut evt = self
83 .timed
84 .pop()
85 .expect("Can only succeed due to peek = Some(...).");
86
87 let old_evt_type = evt.event;
88 if let Some(new_evt_type) = evt.action.act(&ctx).await {
89 evt.event = new_evt_type;
90 self.add_event(evt, now);
91 } else if let Event::Periodic(d, _) = old_evt_type {
92 evt.event = Event::Periodic(d, None);
93 self.add_event(evt, now);
94 }
95 }
96 }
97
98 pub(crate) fn timed_event_ready(&self, now: Duration) -> bool {
100 self.timed.peek().is_some_and(|evt| {
101 evt.fire_time
102 .as_ref()
103 .expect("Timed event must have a fire_time.")
104 <= &now
105 })
106 }
107
108 pub(crate) async fn process_untimed(
110 &mut self,
111 now: Duration,
112 untimed_event: UntimedEvent,
113 ctx: EventContext<'_>,
114 ) {
115 let events = self.untimed.remove(&untimed_event);
121 if let Some(mut events) = events {
122 let mut i = 0;
126 while i < events.len() {
127 let evt = &mut events[i];
128 if let Some(new_evt_type) = evt.action.act(&ctx).await {
130 if evt.event == new_evt_type {
131 let mut evt = events.remove(i);
132
133 evt.event = new_evt_type;
134 self.add_event(evt, now);
135 } else {
136 i += 1;
137 }
138 } else {
139 i += 1;
140 };
141 }
142 self.untimed.insert(untimed_event, events);
143 }
144 }
145}
146
147#[derive(Debug, Default)]
148pub(crate) struct GlobalEvents {
149 pub(crate) store: EventStore,
150 pub(crate) time: Duration,
151 pub(crate) awaiting_tick: HashMap<TrackEvent, Vec<usize>>,
152}
153
154impl GlobalEvents {
155 pub(crate) fn add_event(&mut self, evt: EventData) {
156 self.store.add_event(evt, self.time);
157 }
158
159 pub(crate) async fn fire_core_event(&mut self, evt: CoreEvent, ctx: EventContext<'_>) {
160 self.store.process_untimed(self.time, evt.into(), ctx).await;
161 }
162
163 pub(crate) fn fire_track_event(&mut self, evt: TrackEvent, index: usize) {
164 let holder = self.awaiting_tick.entry(evt).or_default();
165
166 holder.push(index);
167 }
168
169 pub(crate) fn remove_handlers(&mut self) {
170 self.store = EventStore::new();
171 }
172
173 pub(crate) async fn tick(
174 &mut self,
175 events: &mut [EventStore],
176 states: &mut [TrackState],
177 handles: &mut [TrackHandle],
178 ) {
179 self.time += TIMESTEP_LENGTH;
181 if self.store.timed_event_ready(self.time) {
182 let global_ctx: Vec<(&TrackState, &TrackHandle)> =
183 states.iter().zip(handles.iter()).collect();
184 self.store
185 .process_timed(self.time, EventContext::Track(&global_ctx[..]))
186 .await;
187 }
188
189 for (i, state) in states.iter_mut().enumerate() {
191 if state.playing.is_playing() && state.ready == ReadyState::Playable {
192 state.step_frame();
193
194 let event_store = events
195 .get_mut(i)
196 .expect("Missing store index for Tick (local timed).");
197 let handle = handles
198 .get_mut(i)
199 .expect("Missing handle index for Tick (local timed).");
200
201 event_store
202 .process_timed(state.play_time, EventContext::Track(&[(state, handle)]))
203 .await;
204 }
205 }
206
207 for (evt, indices) in &self.awaiting_tick {
208 let untimed = (*evt).into();
209
210 if !indices.is_empty() {
211 info!("Firing {:?} for {:?}", evt, indices);
212 }
213
214 for &i in indices {
216 let event_store = events
217 .get_mut(i)
218 .expect("Missing store index for Tick (local untimed).");
219 let handle = handles
220 .get_mut(i)
221 .expect("Missing handle index for Tick (local untimed).");
222 let state = states
223 .get_mut(i)
224 .expect("Missing state index for Tick (local untimed).");
225
226 event_store
227 .process_untimed(
228 state.position,
229 untimed,
230 EventContext::Track(&[(state, handle)]),
231 )
232 .await;
233 }
234
235 if self.store.untimed.contains_key(&untimed) && !indices.is_empty() {
237 let global_ctx: Vec<(&TrackState, &TrackHandle)> = indices
238 .iter()
239 .map(|i| {
240 (
241 states
242 .get(*i)
243 .expect("Missing state index for Tick (global untimed)"),
244 handles
245 .get(*i)
246 .expect("Missing handle index for Tick (global untimed)"),
247 )
248 })
249 .collect();
250
251 self.store
252 .process_untimed(self.time, untimed, EventContext::Track(&global_ctx[..]))
253 .await;
254 }
255 }
256
257 for indices in self.awaiting_tick.values_mut() {
259 indices.clear();
260 }
261 }
262}