mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +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::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<Gilrs>,
|
||||
#[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut<Gilrs>,
|
||||
#[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut<Gilrs>,
|
||||
mut connection_events: EventWriter<GamepadConnectionEvent>,
|
||||
) {
|
||||
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<Gilrs>,
|
||||
#[cfg(target_arch = "wasm32")] mut gilrs: NonSendMut<Gilrs>,
|
||||
#[cfg(not(target_arch = "wasm32"))] mut gilrs: ResMut<Gilrs>,
|
||||
mut events: EventWriter<GamepadEvent>,
|
||||
mut gamepad_buttons: ResMut<Axis<GamepadButton>>,
|
||||
gamepad_axis: Res<Axis<GamepadAxis>>,
|
||||
gamepad_settings: Res<GamepadSettings>,
|
||||
) {
|
||||
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);
|
||||
|
|
|
@ -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<gilrs::Gilrs>);
|
||||
|
||||
/// 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::<RunningRumbleEffects>()
|
||||
#[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::<RunningRumbleEffects>()
|
||||
.add_systems(PreStartup, gilrs_event_startup_system)
|
||||
.add_systems(PreUpdate, gilrs_event_system.before(InputSystem))
|
||||
.add_systems(PostUpdate, play_gilrs_rumble.in_set(RumbleSystem));
|
||||
|
|
|
@ -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<ff::Effect>,
|
||||
}
|
||||
|
||||
#[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<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 running_rumbles: NonSendMut<RunningRumbleEffects>,
|
||||
mut running_rumbles: ResMut<RunningRumbleEffects>,
|
||||
) {
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue