1use crate::{executor, sys};
2
3impl sys::sGaugeDrawData {
4 pub fn width(&self) -> usize {
6 self.winWidth as usize
7 }
8
9 pub fn height(&self) -> usize {
11 self.winHeight as usize
12 }
13
14 pub fn delta_time(&self) -> std::time::Duration {
16 std::time::Duration::from_secs_f64(self.dt)
17 }
18}
19
20use crate::sim_connect::{SimConnect, SimConnectRecv};
21pub use msfs_derive::{gauge, standalone_module};
22
23#[derive(Debug)]
25pub enum MSFSEvent<'a> {
26 PostInstall,
27 PreInitialize,
28 PostInitialize,
29 PreUpdate,
30 PostUpdate,
31 PreDraw(&'a sys::sGaugeDrawData),
32 PostDraw(&'a sys::sGaugeDrawData),
33 PreKill,
34 Mouse { x: f32, y: f32, flags: u32 },
35 SimConnect(SimConnectRecv<'a>),
36}
37
38pub unsafe fn wrap_executor<E, T>(executor: *mut E, handle: impl FnOnce(&mut E) -> T) -> T {
43 unsafe { handle(&mut *executor) }
44}
45
46pub struct Gauge {
48 executor: *mut GaugeExecutor,
49 rx: futures::channel::mpsc::Receiver<MSFSEvent<'static>>,
50}
51
52impl Gauge {
53 pub fn open_simconnect<'a>(
55 &self,
56 name: &str,
57 ) -> Result<std::pin::Pin<Box<crate::sim_connect::SimConnect<'a>>>, Box<dyn std::error::Error>>
58 {
59 let executor = self.executor;
60 let sim = crate::sim_connect::SimConnect::open(name, move |_sim, recv| {
61 let executor = unsafe { &mut *executor };
62 let recv =
63 unsafe { std::mem::transmute::<SimConnectRecv<'_>, SimConnectRecv<'static>>(recv) };
64 executor
65 .executor
66 .send(Some(MSFSEvent::SimConnect(recv)))
67 .unwrap();
68 })?;
69 Ok(sim)
70 }
71
72 #[cfg(any(target_arch = "wasm32", doc))]
74 pub fn create_nanovg(&self) -> Option<crate::nvg::Context> {
75 crate::nvg::Context::create(unsafe { (*self.executor).fs_ctx.unwrap() })
76 }
77
78 pub fn next_event(&mut self) -> impl futures::Future<Output = Option<MSFSEvent<'_>>> + '_ {
80 use futures::stream::StreamExt;
81 async move { self.rx.next().await }
82 }
83}
84
85#[doc(hidden)]
86pub struct GaugeExecutor {
87 pub fs_ctx: Option<sys::FsContext>,
88 pub executor: executor::Executor<Gauge, MSFSEvent<'static>>,
89}
90
91#[doc(hidden)]
92impl GaugeExecutor {
93 pub fn handle_gauge(
94 &mut self,
95 ctx: sys::FsContext,
96 service_id: std::os::raw::c_int,
97 p_data: *mut std::ffi::c_void,
98 ) -> bool {
99 match service_id as u32 {
100 sys::PANEL_SERVICE_PRE_INSTALL => {
101 let executor = self as *mut GaugeExecutor;
102 self.fs_ctx = Some(ctx);
103 self.executor
104 .start(Box::new(move |rx| Gauge { executor, rx }))
105 .is_ok()
106 }
107 sys::PANEL_SERVICE_POST_KILL => self.executor.send(None).is_ok(),
108 service_id => {
109 if let Some(data) = match service_id {
110 sys::PANEL_SERVICE_POST_INSTALL => Some(MSFSEvent::PostInstall),
111 sys::PANEL_SERVICE_PRE_INITIALIZE => Some(MSFSEvent::PreInitialize),
112 sys::PANEL_SERVICE_POST_INITIALIZE => Some(MSFSEvent::PostInitialize),
113 sys::PANEL_SERVICE_PRE_UPDATE => Some(MSFSEvent::PreUpdate),
114 sys::PANEL_SERVICE_POST_UPDATE => Some(MSFSEvent::PostUpdate),
115 sys::PANEL_SERVICE_PRE_DRAW => Some(MSFSEvent::PreDraw(unsafe {
116 &*(p_data as *const sys::sGaugeDrawData)
117 })),
118 sys::PANEL_SERVICE_POST_DRAW => Some(MSFSEvent::PostDraw(unsafe {
119 &*(p_data as *const sys::sGaugeDrawData)
120 })),
121 sys::PANEL_SERVICE_PRE_KILL => Some(MSFSEvent::PreKill),
122 _ => None,
123 } {
124 self.executor.send(Some(data)).is_ok()
125 } else {
126 true
127 }
128 }
129 }
130 }
131
132 pub fn handle_mouse(&mut self, x: f32, y: f32, flags: u32) {
133 self.executor
134 .send(Some(MSFSEvent::Mouse { x, y, flags }))
135 .unwrap();
136 }
137}
138
139pub struct StandaloneModule {
140 executor: *mut StandaloneModuleExecutor,
141 rx: futures::channel::mpsc::Receiver<SimConnectRecv<'static>>,
142}
143
144impl StandaloneModule {
145 pub fn open_simconnect<'a>(
147 &self,
148 name: &str,
149 ) -> Result<std::pin::Pin<Box<SimConnect<'a>>>, Box<dyn std::error::Error>> {
150 let executor = self.executor;
151 let sim = SimConnect::open(name, move |_sim, recv| {
152 let executor = unsafe { &mut *executor };
153 let recv =
154 unsafe { std::mem::transmute::<SimConnectRecv<'_>, SimConnectRecv<'static>>(recv) };
155 executor.executor.send(Some(recv)).unwrap();
156 })?;
157 Ok(sim)
158 }
159
160 pub fn next_event(&mut self) -> impl futures::Future<Output = Option<SimConnectRecv<'_>>> + '_ {
162 use futures::stream::StreamExt;
163 async move { self.rx.next().await }
164 }
165}
166
167#[doc(hidden)]
168pub struct StandaloneModuleExecutor {
169 pub executor: executor::Executor<StandaloneModule, SimConnectRecv<'static>>,
170}
171
172#[doc(hidden)]
173impl StandaloneModuleExecutor {
174 fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
175 let executor = self as *mut StandaloneModuleExecutor;
176 self.executor
177 .start(Box::new(move |rx| StandaloneModule { executor, rx }))
178 }
179
180 pub fn handle_init(&mut self) {
181 self.start().unwrap();
182 }
183
184 fn end(&mut self) -> Result<(), Box<dyn std::error::Error>> {
185 self.executor.send(None)
186 }
187
188 pub fn handle_deinit(&mut self) {
189 self.end().unwrap();
190 }
191}