mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 22:20:20 +00:00
Make Gilrs a normal resource on non-Wasm targets (#12092)
# Objective Partially address #888. Gilrs is initialized on a separate thread, and thus conditionally implements `Send`, and all platforms other than Wasm. This means the `NonSend` resource constraint is likely too conservative. ## Solution Relax the requirement, and conditionally derive Resource on a wrapper around it, using `SyncCell` to satisfy the `Sync` requirement on it.
This commit is contained in:
parent
ad5d790e9e
commit
3a1b9b98e4
3 changed files with 43 additions and 26 deletions
|
@ -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::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::{
|
use bevy_input::gamepad::{
|
||||||
GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent,
|
GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent,
|
||||||
GamepadSettings,
|
GamepadSettings,
|
||||||
|
@ -8,13 +13,14 @@ use bevy_input::gamepad::{
|
||||||
use bevy_input::gamepad::{GamepadEvent, GamepadInfo};
|
use bevy_input::gamepad::{GamepadEvent, GamepadInfo};
|
||||||
use bevy_input::prelude::{GamepadAxis, GamepadButton};
|
use bevy_input::prelude::{GamepadAxis, GamepadButton};
|
||||||
use bevy_input::Axis;
|
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(
|
pub fn gilrs_event_startup_system(
|
||||||
gilrs: NonSend<Gilrs>,
|
#[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut<Gilrs>,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut<Gilrs>,
|
||||||
mut connection_events: EventWriter<GamepadConnectionEvent>,
|
mut connection_events: EventWriter<GamepadConnectionEvent>,
|
||||||
) {
|
) {
|
||||||
for (id, gamepad) in gilrs.gamepads() {
|
for (id, gamepad) in gilrs.0.get().gamepads() {
|
||||||
let info = GamepadInfo {
|
let info = GamepadInfo {
|
||||||
name: gamepad.name().into(),
|
name: gamepad.name().into(),
|
||||||
};
|
};
|
||||||
|
@ -27,16 +33,15 @@ pub fn gilrs_event_startup_system(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gilrs_event_system(
|
pub fn gilrs_event_system(
|
||||||
mut gilrs: NonSendMut<Gilrs>,
|
#[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut<Gilrs>,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut<Gilrs>,
|
||||||
mut events: EventWriter<GamepadEvent>,
|
mut events: EventWriter<GamepadEvent>,
|
||||||
mut gamepad_buttons: ResMut<Axis<GamepadButton>>,
|
mut gamepad_buttons: ResMut<Axis<GamepadButton>>,
|
||||||
gamepad_axis: Res<Axis<GamepadAxis>>,
|
gamepad_axis: Res<Axis<GamepadAxis>>,
|
||||||
gamepad_settings: Res<GamepadSettings>,
|
gamepad_settings: Res<GamepadSettings>,
|
||||||
) {
|
) {
|
||||||
while let Some(gilrs_event) = gilrs
|
let gilrs = gilrs.0.get();
|
||||||
.next_event()
|
while let Some(gilrs_event) = gilrs.next_event().filter_ev(&axis_dpad_to_button, gilrs) {
|
||||||
.filter_ev(&axis_dpad_to_button, &mut gilrs)
|
|
||||||
{
|
|
||||||
gilrs.update(&gilrs_event);
|
gilrs.update(&gilrs_event);
|
||||||
|
|
||||||
let gamepad = convert_gamepad_id(gilrs_event.id);
|
let gamepad = convert_gamepad_id(gilrs_event.id);
|
||||||
|
|
|
@ -10,11 +10,14 @@ mod rumble;
|
||||||
use bevy_app::{App, Plugin, PostUpdate, PreStartup, PreUpdate};
|
use bevy_app::{App, Plugin, PostUpdate, PreStartup, PreUpdate};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_input::InputSystem;
|
use bevy_input::InputSystem;
|
||||||
use bevy_utils::tracing::error;
|
use bevy_utils::{synccell::SyncCell, tracing::error};
|
||||||
use gilrs::GilrsBuilder;
|
use gilrs::GilrsBuilder;
|
||||||
use gilrs_system::{gilrs_event_startup_system, gilrs_event_system};
|
use gilrs_system::{gilrs_event_startup_system, gilrs_event_system};
|
||||||
use rumble::{play_gilrs_rumble, RunningRumbleEffects};
|
use rumble::{play_gilrs_rumble, RunningRumbleEffects};
|
||||||
|
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), derive(Resource))]
|
||||||
|
pub(crate) struct Gilrs(pub SyncCell<gilrs::Gilrs>);
|
||||||
|
|
||||||
/// Plugin that provides gamepad handling to an [`App`].
|
/// Plugin that provides gamepad handling to an [`App`].
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct GilrsPlugin;
|
pub struct GilrsPlugin;
|
||||||
|
@ -31,8 +34,12 @@ impl Plugin for GilrsPlugin {
|
||||||
.build()
|
.build()
|
||||||
{
|
{
|
||||||
Ok(gilrs) => {
|
Ok(gilrs) => {
|
||||||
app.insert_non_send_resource(gilrs)
|
#[cfg(target_arch = "wasm32")]
|
||||||
.init_non_send_resource::<RunningRumbleEffects>()
|
app.insert_non_send_resource(Gilrs(SyncCell::new(gilrs)));
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
app.insert_resource(Gilrs(SyncCell::new(gilrs)));
|
||||||
|
|
||||||
|
app.init_resource::<RunningRumbleEffects>()
|
||||||
.add_systems(PreStartup, gilrs_event_startup_system)
|
.add_systems(PreStartup, gilrs_event_startup_system)
|
||||||
.add_systems(PreUpdate, gilrs_event_system.before(InputSystem))
|
.add_systems(PreUpdate, gilrs_event_system.before(InputSystem))
|
||||||
.add_systems(PostUpdate, play_gilrs_rumble.in_set(RumbleSystem));
|
.add_systems(PostUpdate, play_gilrs_rumble.in_set(RumbleSystem));
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
//! Handle user specified rumble request events.
|
//! Handle user specified rumble request events.
|
||||||
use bevy_ecs::{
|
use crate::Gilrs;
|
||||||
prelude::{EventReader, Res},
|
use bevy_ecs::prelude::{EventReader, Res, ResMut, Resource};
|
||||||
system::NonSendMut,
|
#[cfg(target_arch = "wasm32")]
|
||||||
};
|
use bevy_ecs::system::NonSendMut;
|
||||||
use bevy_input::gamepad::{GamepadRumbleIntensity, GamepadRumbleRequest};
|
use bevy_input::gamepad::{GamepadRumbleIntensity, GamepadRumbleRequest};
|
||||||
use bevy_log::{debug, warn};
|
use bevy_log::{debug, warn};
|
||||||
use bevy_time::{Real, Time};
|
use bevy_time::{Real, Time};
|
||||||
use bevy_utils::{Duration, HashMap};
|
use bevy_utils::{synccell::SyncCell, Duration, HashMap};
|
||||||
use gilrs::{
|
use gilrs::{
|
||||||
ff::{self, BaseEffect, BaseEffectType, Repeat, Replay},
|
ff::{self, BaseEffect, BaseEffectType, Repeat, Replay},
|
||||||
GamepadId, Gilrs,
|
GamepadId,
|
||||||
};
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ struct RunningRumble {
|
||||||
///
|
///
|
||||||
/// Dropping it will cause the effect to stop
|
/// Dropping it will cause the effect to stop
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
effect: ff::Effect,
|
effect: SyncCell<ff::Effect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
@ -35,7 +35,7 @@ enum RumbleError {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Contains the gilrs rumble effects that are currently running for each gamepad
|
/// Contains the gilrs rumble effects that are currently running for each gamepad
|
||||||
#[derive(Default)]
|
#[derive(Default, Resource)]
|
||||||
pub(crate) struct RunningRumbleEffects {
|
pub(crate) struct RunningRumbleEffects {
|
||||||
/// If multiple rumbles are running at the same time, their resulting rumble
|
/// If multiple rumbles are running at the same time, their resulting rumble
|
||||||
/// will be the saturated sum of their strengths up until [`u16::MAX`]
|
/// will be the saturated sum of their strengths up until [`u16::MAX`]
|
||||||
|
@ -80,7 +80,7 @@ fn get_base_effects(
|
||||||
|
|
||||||
fn handle_rumble_request(
|
fn handle_rumble_request(
|
||||||
running_rumbles: &mut RunningRumbleEffects,
|
running_rumbles: &mut RunningRumbleEffects,
|
||||||
gilrs: &mut Gilrs,
|
gilrs: &mut gilrs::Gilrs,
|
||||||
rumble: GamepadRumbleRequest,
|
rumble: GamepadRumbleRequest,
|
||||||
current_time: Duration,
|
current_time: Duration,
|
||||||
) -> Result<(), RumbleError> {
|
) -> Result<(), RumbleError> {
|
||||||
|
@ -113,7 +113,10 @@ fn handle_rumble_request(
|
||||||
|
|
||||||
let gamepad_rumbles = running_rumbles.rumbles.entry(gamepad_id).or_default();
|
let gamepad_rumbles = running_rumbles.rumbles.entry(gamepad_id).or_default();
|
||||||
let deadline = current_time + duration;
|
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(
|
pub(crate) fn play_gilrs_rumble(
|
||||||
time: Res<Time<Real>>,
|
time: Res<Time<Real>>,
|
||||||
mut gilrs: NonSendMut<Gilrs>,
|
#[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut<Gilrs>,
|
||||||
|
#[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut<Gilrs>,
|
||||||
mut requests: EventReader<GamepadRumbleRequest>,
|
mut requests: EventReader<GamepadRumbleRequest>,
|
||||||
mut running_rumbles: NonSendMut<RunningRumbleEffects>,
|
mut running_rumbles: ResMut<RunningRumbleEffects>,
|
||||||
) {
|
) {
|
||||||
|
let gilrs = gilrs.0.get();
|
||||||
let current_time = time.elapsed();
|
let current_time = time.elapsed();
|
||||||
// Remove outdated rumble effects.
|
// Remove outdated rumble effects.
|
||||||
for rumbles in running_rumbles.rumbles.values_mut() {
|
for rumbles in running_rumbles.rumbles.values_mut() {
|
||||||
|
@ -138,7 +143,7 @@ pub(crate) fn play_gilrs_rumble(
|
||||||
// Add new effects.
|
// Add new effects.
|
||||||
for rumble in requests.read().cloned() {
|
for rumble in requests.read().cloned() {
|
||||||
let gamepad = rumble.gamepad();
|
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(()) => {}
|
Ok(()) => {}
|
||||||
Err(RumbleError::GilrsError(err)) => {
|
Err(RumbleError::GilrsError(err)) => {
|
||||||
if let ff::Error::FfNotSupported(_) = err {
|
if let ff::Error::FfNotSupported(_) = err {
|
||||||
|
|
Loading…
Reference in a new issue