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));
}
}