use crate::{executor, sys};
impl sys::sGaugeDrawData {
pub fn width(&self) -> usize {
self.winWidth as usize
}
pub fn height(&self) -> usize {
self.winHeight as usize
}
pub fn delta_time(&self) -> std::time::Duration {
std::time::Duration::from_secs_f64(self.dt)
}
}
use crate::sim_connect::{SimConnect, SimConnectRecv};
pub use msfs_derive::{gauge, standalone_module};
#[derive(Debug)]
pub enum MSFSEvent<'a> {
PostInstall,
PreInitialize,
PostInitialize,
PreUpdate,
PostUpdate,
PreDraw(&'a sys::sGaugeDrawData),
PostDraw(&'a sys::sGaugeDrawData),
PreKill,
Mouse { x: f32, y: f32, flags: u32 },
SimConnect(SimConnectRecv<'a>),
}
pub struct Gauge {
executor: *mut GaugeExecutor,
rx: futures::channel::mpsc::Receiver<MSFSEvent<'static>>,
}
impl Gauge {
pub fn open_simconnect<'a>(
&self,
name: &str,
) -> Result<std::pin::Pin<Box<crate::sim_connect::SimConnect<'a>>>, Box<dyn std::error::Error>>
{
let executor = self.executor;
let sim = crate::sim_connect::SimConnect::open(name, move |_sim, recv| {
let executor = unsafe { &mut *executor };
let recv =
unsafe { std::mem::transmute::<SimConnectRecv<'_>, SimConnectRecv<'static>>(recv) };
executor
.executor
.send(Some(MSFSEvent::SimConnect(recv)))
.unwrap();
})?;
Ok(sim)
}
#[cfg(any(target_arch = "wasm32", doc))]
pub fn create_nanovg(&self) -> Option<crate::nvg::Context> {
crate::nvg::Context::create(unsafe { (*self.executor).fs_ctx.unwrap() })
}
pub fn next_event(&mut self) -> impl futures::Future<Output = Option<MSFSEvent<'_>>> + '_ {
use futures::stream::StreamExt;
async move { self.rx.next().await }
}
}
#[doc(hidden)]
pub struct GaugeExecutor {
pub fs_ctx: Option<sys::FsContext>,
pub executor: executor::Executor<Gauge, MSFSEvent<'static>>,
}
#[doc(hidden)]
impl GaugeExecutor {
pub fn handle_gauge(
&mut self,
ctx: sys::FsContext,
service_id: std::os::raw::c_int,
p_data: *mut std::ffi::c_void,
) -> bool {
match service_id as u32 {
sys::PANEL_SERVICE_PRE_INSTALL => {
let executor = self as *mut GaugeExecutor;
self.fs_ctx = Some(ctx);
self.executor
.start(Box::new(move |rx| Gauge { executor, rx }))
.is_ok()
}
sys::PANEL_SERVICE_POST_KILL => self.executor.send(None).is_ok(),
service_id => {
if let Some(data) = match service_id {
sys::PANEL_SERVICE_POST_INSTALL => Some(MSFSEvent::PostInstall),
sys::PANEL_SERVICE_PRE_INITIALIZE => Some(MSFSEvent::PreInitialize),
sys::PANEL_SERVICE_POST_INITIALIZE => Some(MSFSEvent::PostInitialize),
sys::PANEL_SERVICE_PRE_UPDATE => Some(MSFSEvent::PreUpdate),
sys::PANEL_SERVICE_POST_UPDATE => Some(MSFSEvent::PostUpdate),
sys::PANEL_SERVICE_PRE_DRAW => Some(MSFSEvent::PreDraw(unsafe {
&*(p_data as *const sys::sGaugeDrawData)
})),
sys::PANEL_SERVICE_POST_DRAW => Some(MSFSEvent::PostDraw(unsafe {
&*(p_data as *const sys::sGaugeDrawData)
})),
sys::PANEL_SERVICE_PRE_KILL => Some(MSFSEvent::PreKill),
_ => None,
} {
self.executor.send(Some(data)).is_ok()
} else {
true
}
}
}
}
pub fn handle_mouse(&mut self, x: f32, y: f32, flags: u32) {
self.executor
.send(Some(MSFSEvent::Mouse { x, y, flags }))
.unwrap();
}
}
pub struct StandaloneModule {
executor: *mut StandaloneModuleExecutor,
rx: futures::channel::mpsc::Receiver<SimConnectRecv<'static>>,
}
impl StandaloneModule {
pub fn open_simconnect<'a>(
&self,
name: &str,
) -> Result<std::pin::Pin<Box<SimConnect<'a>>>, Box<dyn std::error::Error>> {
let executor = self.executor;
let sim = SimConnect::open(name, move |_sim, recv| {
let executor = unsafe { &mut *executor };
let recv =
unsafe { std::mem::transmute::<SimConnectRecv<'_>, SimConnectRecv<'static>>(recv) };
executor.executor.send(Some(recv)).unwrap();
})?;
Ok(sim)
}
pub fn next_event(&mut self) -> impl futures::Future<Output = Option<SimConnectRecv<'_>>> + '_ {
use futures::stream::StreamExt;
async move { self.rx.next().await }
}
}
#[doc(hidden)]
pub struct StandaloneModuleExecutor {
pub executor: executor::Executor<StandaloneModule, SimConnectRecv<'static>>,
}
#[doc(hidden)]
impl StandaloneModuleExecutor {
fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let executor = self as *mut StandaloneModuleExecutor;
self.executor
.start(Box::new(move |rx| StandaloneModule { executor, rx }))
}
pub fn handle_init(&mut self) {
self.start().unwrap();
}
fn end(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.executor.send(None)
}
pub fn handle_deinit(&mut self) {
self.end().unwrap();
}
}