classicube_helpers/
tick.rs1use std::{
2 cell::{Cell, RefCell},
3 rc::{Rc, Weak},
4};
5
6use classicube_sys::{ScheduledTask, ScheduledTask_Add};
7
8use crate::callback_handler::CallbackHandler;
9
10thread_local!(
11 static CALLBACK_REGISTERED: Cell<bool> = const { Cell::new(false) };
12);
13
14thread_local!(
15 static TICK_CALLBACK_HANDLERS: RefCell<Vec<Weak<RefCell<CallbackHandler<TickEvent>>>>> =
16 const { RefCell::new(Vec::new()) };
17);
18
19#[derive(Debug)]
20pub struct TickEvent {
21 pub task: *mut ScheduledTask,
22}
23
24pub struct TickEventHandler {
25 callback_handler: Rc<RefCell<CallbackHandler<TickEvent>>>,
26}
27
28impl TickEventHandler {
29 #[must_use]
30 pub fn new() -> Self {
31 Self {
32 callback_handler: Rc::new(RefCell::new(CallbackHandler::new())),
33 }
34 }
35
36 pub fn on<F>(&mut self, callback: F)
37 where
38 F: FnMut(&TickEvent),
39 F: 'static,
40 {
41 self.callback_handler.borrow_mut().on(callback);
42
43 unsafe {
44 self.register_listener();
45 }
46 }
47
48 fn check_register_detour() {
49 if !CALLBACK_REGISTERED.get() {
50 CALLBACK_REGISTERED.set(true);
51
52 unsafe {
53 ScheduledTask_Add(0.0, Some(Self::hook));
55 }
56 }
57 }
58
59 unsafe fn register_listener(&mut self) {
60 Self::check_register_detour();
61
62 let weak = Rc::downgrade(&self.callback_handler);
63
64 TICK_CALLBACK_HANDLERS.with(|callback_handlers| {
65 for callback_handler in &*callback_handlers.borrow() {
66 if callback_handler.ptr_eq(&weak) {
67 return;
69 }
70 }
71
72 callback_handlers.borrow_mut().push(weak);
73 });
74 }
75
76 unsafe fn unregister_listener(&mut self) {
77 _ = TICK_CALLBACK_HANDLERS.try_with(|callback_handlers| {
78 let mut callback_handlers = callback_handlers.borrow_mut();
79
80 let my_weak = Rc::downgrade(&self.callback_handler);
81
82 let mut i = 0;
83 while i != callback_handlers.len() {
84 if callback_handlers[i].ptr_eq(&my_weak) {
86 callback_handlers.remove(i);
87 } else {
88 i += 1;
89 }
90 }
91 });
92 }
93
94 extern "C" fn hook(task: *mut ScheduledTask) {
95 let task = unsafe { &mut *task };
96 task.accumulator = -0.0001;
98
99 TICK_CALLBACK_HANDLERS.with(|callback_handlers| {
100 let callback_handlers = callback_handlers.borrow_mut();
101 for weak_callback_handler in &*callback_handlers {
102 if let Some(callback_handler) = weak_callback_handler.upgrade() {
103 callback_handler
104 .borrow_mut()
105 .handle_event(&TickEvent { task });
106 }
107 }
108 });
109 }
110}
111
112impl Drop for TickEventHandler {
113 fn drop(&mut self) {
114 unsafe {
115 self.unregister_listener();
116 }
117 }
118}
119
120impl Default for TickEventHandler {
121 fn default() -> Self {
122 Self::new()
123 }
124}