bevy_buttplug 0.1.0

simple Buttplug integration with bevy
Documentation
use bevy::time::FixedTimestep;
use bevy::{ecs::component, prelude::*};
use bevy_tokio_tasks::*;
use buttplug::client::{ButtplugClient, ButtplugClientDevice, ScalarValueCommand};
use buttplug::util::in_process_client;
use std::sync::{mpsc::*, Arc};
pub struct VibePlugin;

#[derive(Component, Deref, DerefMut, Clone)]
struct VibeClient(pub Arc<ButtplugClient>);
pub enum VibeEvent {
    Scan(bool),
    Devices,
    Vibe(u32, f32),
    Stop(u32),
}
#[derive(Debug)]
pub enum VibeResponse {
    Devices(Vec<Arc<ButtplugClientDevice>>),
}

impl Plugin for VibePlugin {
    fn build(&self, app: &mut App) {
        app.add_plugin(bevy_tokio_tasks::TokioTasksPlugin::default())
            .add_event::<VibeEvent>()
            .add_event::<VibeResponse>()
            .add_startup_system(start_server)
            .add_system(scan)
            .add_system(poll);
    }
}
fn start_server(mut cmds: Commands, rt: ResMut<TokioTasksRuntime>) {
    rt.spawn_background_task::<_, Result<(), ()>, _>(|mut ctx| async move {
        let client = in_process_client("client", false).await;
        ctx.run_on_main_thread(|ctx| {
            ctx.world.spawn(VibeClient(Arc::new(client)));
        })
        .await;
        Ok(())
    });
}
fn poll(mut er: EventReader<VibeEvent>, rt: ResMut<TokioTasksRuntime>) {
    for e in er.iter() {
        match e {
            VibeEvent::Scan(state) => {
                let state = state.clone();
                rt.spawn_background_task::<_, Result<(), ()>, _>(move |mut ctx| async move {
                    let c = ctx
                        .run_on_main_thread(move |ctx| {
                            let mut c = ctx.world.query::<&VibeClient>();
                            let c = c.get_single(ctx.world).unwrap().to_owned();
                            Box::new(Arc::new(c))
                        })
                        .await;
                    if state {
                        info!("Started Scanning for devices");
                        c.start_scanning().await;
                    } else {
                        info!("Stopped Scanning for devices");
                        c.stop_scanning().await;
                    }
                    Ok(())
                });
            }
            VibeEvent::Devices => {
                rt.spawn_background_task::<_, Result<(), ()>, _>(|mut ctx| async move {
                    let c = ctx
                        .run_on_main_thread(move |ctx| {
                            let mut c = ctx.world.query::<&VibeClient>();
                            let c = c.get_single(ctx.world).unwrap().to_owned();
                            ctx.world.send_event(VibeResponse::Devices(c.devices()));
                        })
                        .await;
                    Ok(())
                });
            }
            VibeEvent::Vibe(id, force) => {
                let id = id.clone();
                let force = force.clone();
                rt.spawn_background_task::<_, Result<(), ()>, _>(move |mut ctx| async move {
                    let c = ctx
                        .run_on_main_thread(move |ctx| {
                            let mut c = ctx.world.query::<&VibeClient>();
                            let c = c.get_single(ctx.world).unwrap().to_owned();
                            Box::new(Arc::new(c))
                        })
                        .await;
                    for device in c.devices().into_iter() {
                        if !device.index().eq(&id) {
                            continue;
                        }
                        device.vibrate(&ScalarValueCommand::ScalarValue(force.into())).await;
                    }
                    Ok(())
                });
            }
            VibeEvent::Stop(id) => {
                let id = id.clone();
                rt.spawn_background_task::<_, Result<(), ()>, _>(move |mut ctx| async move{
                    let c = ctx
                        .run_on_main_thread(move |ctx| {
                            let mut c = ctx.world.query::<&VibeClient>();
                            let c = c.get_single(ctx.world).unwrap().to_owned();
                            Box::new(Arc::new(c))
                        })
                        .await;
                    for device in c.devices().into_iter() {
                        if !device.index().eq(&id) {
                            continue;
                        }
                        device.stop().await;
                    }
                        Ok(())
                });
            }
            _ => todo!(),
        }
    }
}

fn scan(
    input: Res<Input<KeyCode>>,
    rt: ResMut<TokioTasksRuntime>,
    mut ew: EventWriter<VibeEvent>,
    mut er: EventReader<VibeResponse>,
) {
    if input.just_pressed(KeyCode::T) {
        ew.send(VibeEvent::Scan(true));
    }
    if input.just_pressed(KeyCode::Y) {
        ew.send(VibeEvent::Scan(false));
    }
    if input.just_pressed(KeyCode::V) {
        ew.send(VibeEvent::Vibe(0, 0.25));
    } else if input.just_released(KeyCode::V){
        ew.send(VibeEvent::Stop(0));
    }
}