diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 7849bc1c80430..e0e111cb4d027 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -1,6 +1,11 @@ -use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; +use crate::{ + converter::{convert_axis, convert_button, convert_gamepad_id}, + Gilrs, +}; use bevy_ecs::event::EventWriter; -use bevy_ecs::system::{NonSend, NonSendMut, Res, ResMut}; +#[cfg(target_arch = "wasm32")] +use bevy_ecs::system::NonSendMut; +use bevy_ecs::system::{Res, ResMut}; use bevy_input::gamepad::{ GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent, GamepadSettings, @@ -8,13 +13,14 @@ use bevy_input::gamepad::{ use bevy_input::gamepad::{GamepadEvent, GamepadInfo}; use bevy_input::prelude::{GamepadAxis, GamepadButton}; use bevy_input::Axis; -use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; +use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter}; pub fn gilrs_event_startup_system( - gilrs: NonSend, + #[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut, + #[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut, mut connection_events: EventWriter, ) { - for (id, gamepad) in gilrs.gamepads() { + for (id, gamepad) in gilrs.0.get().gamepads() { let info = GamepadInfo { name: gamepad.name().into(), }; @@ -27,16 +33,15 @@ pub fn gilrs_event_startup_system( } pub fn gilrs_event_system( - mut gilrs: NonSendMut, + #[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut, + #[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut, mut events: EventWriter, mut gamepad_buttons: ResMut>, gamepad_axis: Res>, gamepad_settings: Res, ) { - while let Some(gilrs_event) = gilrs - .next_event() - .filter_ev(&axis_dpad_to_button, &mut gilrs) - { + let gilrs = gilrs.0.get(); + while let Some(gilrs_event) = gilrs.next_event().filter_ev(&axis_dpad_to_button, gilrs) { gilrs.update(&gilrs_event); let gamepad = convert_gamepad_id(gilrs_event.id); diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index b48256b8db826..dad8efe744a05 100644 --- a/crates/bevy_gilrs/src/lib.rs +++ b/crates/bevy_gilrs/src/lib.rs @@ -10,11 +10,14 @@ mod rumble; use bevy_app::{App, Plugin, PostUpdate, PreStartup, PreUpdate}; use bevy_ecs::prelude::*; use bevy_input::InputSystem; -use bevy_utils::tracing::error; +use bevy_utils::{synccell::SyncCell, tracing::error}; use gilrs::GilrsBuilder; use gilrs_system::{gilrs_event_startup_system, gilrs_event_system}; use rumble::{play_gilrs_rumble, RunningRumbleEffects}; +#[cfg_attr(not(target_arch = "wasm32"), derive(Resource))] +pub(crate) struct Gilrs(pub SyncCell); + /// Plugin that provides gamepad handling to an [`App`]. #[derive(Default)] pub struct GilrsPlugin; @@ -31,8 +34,12 @@ impl Plugin for GilrsPlugin { .build() { Ok(gilrs) => { - app.insert_non_send_resource(gilrs) - .init_non_send_resource::() + #[cfg(target_arch = "wasm32")] + app.insert_non_send_resource(Gilrs(SyncCell::new(gilrs))); + #[cfg(not(target_arch = "wasm32"))] + app.insert_resource(Gilrs(SyncCell::new(gilrs))); + + app.init_resource::() .add_systems(PreStartup, gilrs_event_startup_system) .add_systems(PreUpdate, gilrs_event_system.before(InputSystem)) .add_systems(PostUpdate, play_gilrs_rumble.in_set(RumbleSystem)); diff --git a/crates/bevy_gilrs/src/rumble.rs b/crates/bevy_gilrs/src/rumble.rs index 2b1eb68aedbf2..c982a52ce2fa5 100644 --- a/crates/bevy_gilrs/src/rumble.rs +++ b/crates/bevy_gilrs/src/rumble.rs @@ -1,15 +1,15 @@ //! Handle user specified rumble request events. -use bevy_ecs::{ - prelude::{EventReader, Res}, - system::NonSendMut, -}; +use crate::Gilrs; +use bevy_ecs::prelude::{EventReader, Res, ResMut, Resource}; +#[cfg(target_arch = "wasm32")] +use bevy_ecs::system::NonSendMut; use bevy_input::gamepad::{GamepadRumbleIntensity, GamepadRumbleRequest}; use bevy_log::{debug, warn}; use bevy_time::{Real, Time}; -use bevy_utils::{Duration, HashMap}; +use bevy_utils::{synccell::SyncCell, Duration, HashMap}; use gilrs::{ ff::{self, BaseEffect, BaseEffectType, Repeat, Replay}, - GamepadId, Gilrs, + GamepadId, }; use thiserror::Error; @@ -23,7 +23,7 @@ struct RunningRumble { /// /// Dropping it will cause the effect to stop #[allow(dead_code)] - effect: ff::Effect, + effect: SyncCell, } #[derive(Error, Debug)] @@ -35,7 +35,7 @@ enum RumbleError { } /// Contains the gilrs rumble effects that are currently running for each gamepad -#[derive(Default)] +#[derive(Default, Resource)] pub(crate) struct RunningRumbleEffects { /// If multiple rumbles are running at the same time, their resulting rumble /// will be the saturated sum of their strengths up until [`u16::MAX`] @@ -80,7 +80,7 @@ fn get_base_effects( fn handle_rumble_request( running_rumbles: &mut RunningRumbleEffects, - gilrs: &mut Gilrs, + gilrs: &mut gilrs::Gilrs, rumble: GamepadRumbleRequest, current_time: Duration, ) -> Result<(), RumbleError> { @@ -113,7 +113,10 @@ fn handle_rumble_request( let gamepad_rumbles = running_rumbles.rumbles.entry(gamepad_id).or_default(); let deadline = current_time + duration; - gamepad_rumbles.push(RunningRumble { deadline, effect }); + gamepad_rumbles.push(RunningRumble { + deadline, + effect: SyncCell::new(effect), + }); } } @@ -121,10 +124,12 @@ fn handle_rumble_request( } pub(crate) fn play_gilrs_rumble( time: Res>, - mut gilrs: NonSendMut, + #[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut, + #[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut, mut requests: EventReader, - mut running_rumbles: NonSendMut, + mut running_rumbles: ResMut, ) { + let gilrs = gilrs.0.get(); let current_time = time.elapsed(); // Remove outdated rumble effects. for rumbles in running_rumbles.rumbles.values_mut() { @@ -138,7 +143,7 @@ pub(crate) fn play_gilrs_rumble( // Add new effects. for rumble in requests.read().cloned() { let gamepad = rumble.gamepad(); - match handle_rumble_request(&mut running_rumbles, &mut gilrs, rumble, current_time) { + match handle_rumble_request(&mut running_rumbles, gilrs, rumble, current_time) { Ok(()) => {} Err(RumbleError::GilrsError(err)) => { if let ff::Error::FfNotSupported(_) = err {