overlord_event_system/fight/
clock.rs1use std::cmp::Reverse;
18use std::collections::BinaryHeap;
19
20use crate::event::OverlordEvent;
21
22#[derive(Debug, Clone)]
23struct Scheduled {
24 due_tick: u64,
25 seq: u64,
27 event: OverlordEvent,
28}
29
30impl PartialEq for Scheduled {
31 fn eq(&self, other: &Self) -> bool {
32 self.due_tick == other.due_tick && self.seq == other.seq
33 }
34}
35
36impl Eq for Scheduled {}
37
38impl PartialOrd for Scheduled {
39 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
40 Some(self.cmp(other))
41 }
42}
43
44impl Ord for Scheduled {
45 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
46 (self.due_tick, self.seq).cmp(&(other.due_tick, other.seq))
47 }
48}
49
50#[derive(Debug, Clone)]
51struct Heartbeat {
52 event: OverlordEvent,
53 rate_ticks: u64,
54 last_emitted: Option<u64>,
55}
56
57#[derive(Debug, Default, Clone)]
58pub struct FightClock {
59 now: u64,
61 pending: BinaryHeap<Reverse<Scheduled>>,
62 next_seq: u64,
63 heartbeat: Option<Heartbeat>,
64}
65
66impl FightClock {
67 pub fn set_now(&mut self, tick: u64) {
70 self.now = tick;
71 }
72
73 pub fn schedule(&mut self, event: OverlordEvent, delay_ticks: u64) {
75 self.pending.push(Reverse(Scheduled {
76 due_tick: self.now + delay_ticks,
77 seq: self.next_seq,
78 event,
79 }));
80 self.next_seq += 1;
81 }
82
83 pub fn set_heartbeat(&mut self, event: OverlordEvent, rate_ticks: u64) {
86 self.heartbeat = Some(Heartbeat {
87 event,
88 rate_ticks,
89 last_emitted: None,
90 });
91 }
92
93 pub fn clear(&mut self) {
96 self.pending.clear();
97 self.heartbeat = None;
98 }
99
100 pub fn collect_due(&mut self, tick: u64) -> Vec<OverlordEvent> {
103 self.now = tick;
104
105 let mut due = Vec::new();
106 while self
107 .pending
108 .peek()
109 .is_some_and(|Reverse(s)| s.due_tick <= tick)
110 {
111 due.push(self.pending.pop().unwrap().0.event);
112 }
113
114 if let Some(heartbeat) = &mut self.heartbeat
115 && heartbeat
116 .last_emitted
117 .is_none_or(|last| tick.saturating_sub(last) >= heartbeat.rate_ticks)
118 {
119 due.push(heartbeat.event.clone());
120 heartbeat.last_emitted = Some(tick);
121 }
122
123 due
124 }
125}