2023-08-23 12:44:49 +00:00
|
|
|
//! The gamepad input functionality.
|
|
|
|
|
2023-12-06 20:32:34 +00:00
|
|
|
use crate::{Axis, ButtonInput, ButtonState};
|
2023-06-06 14:44:32 +00:00
|
|
|
use bevy_ecs::event::{Event, EventReader, EventWriter};
|
2022-12-11 18:22:09 +00:00
|
|
|
use bevy_ecs::{
|
2023-01-11 15:41:54 +00:00
|
|
|
change_detection::DetectChangesMut,
|
2022-12-11 18:22:09 +00:00
|
|
|
system::{Res, ResMut, Resource},
|
|
|
|
};
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
|
2023-04-24 15:28:53 +00:00
|
|
|
use bevy_utils::Duration;
|
2022-10-24 14:33:50 +00:00
|
|
|
use bevy_utils::{tracing::info, HashMap};
|
2022-10-17 14:38:55 +00:00
|
|
|
use thiserror::Error;
|
|
|
|
|
|
|
|
/// Errors that occur when setting axis settings for gamepad input.
|
|
|
|
#[derive(Error, Debug, PartialEq)]
|
|
|
|
pub enum AxisSettingsError {
|
|
|
|
/// The given parameter `livezone_lowerbound` was not in range -1.0..=0.0.
|
|
|
|
#[error("invalid livezone_lowerbound {0}, expected value [-1.0..=0.0]")]
|
|
|
|
LiveZoneLowerBoundOutOfRange(f32),
|
|
|
|
/// The given parameter `deadzone_lowerbound` was not in range -1.0..=0.0.
|
|
|
|
#[error("invalid deadzone_lowerbound {0}, expected value [-1.0..=0.0]")]
|
|
|
|
DeadZoneLowerBoundOutOfRange(f32),
|
|
|
|
/// The given parameter `deadzone_lowerbound` was not in range -1.0..=0.0.
|
|
|
|
#[error("invalid deadzone_upperbound {0}, expected value [0.0..=1.0]")]
|
|
|
|
DeadZoneUpperBoundOutOfRange(f32),
|
|
|
|
/// The given parameter `deadzone_lowerbound` was not in range -1.0..=0.0.
|
|
|
|
#[error("invalid livezone_upperbound {0}, expected value [0.0..=1.0]")]
|
|
|
|
LiveZoneUpperBoundOutOfRange(f32),
|
|
|
|
/// Parameter `livezone_lowerbound` was not less than or equal to parameter `deadzone_lowerbound`.
|
|
|
|
#[error("invalid parameter values livezone_lowerbound {} deadzone_lowerbound {}, expected livezone_lowerbound <= deadzone_lowerbound", .livezone_lowerbound, .deadzone_lowerbound)]
|
|
|
|
LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `livezone_lowerbound` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
livezone_lowerbound: f32,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `deadzone_lowerbound` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
deadzone_lowerbound: f32,
|
|
|
|
},
|
|
|
|
/// Parameter `deadzone_upperbound` was not less than or equal to parameter `livezone_upperbound`.
|
|
|
|
#[error("invalid parameter values livezone_upperbound {} deadzone_upperbound {}, expected deadzone_upperbound <= livezone_upperbound", .livezone_upperbound, .deadzone_upperbound)]
|
|
|
|
DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `livezone_upperbound` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
livezone_upperbound: f32,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `deadzone_upperbound` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
deadzone_upperbound: f32,
|
|
|
|
},
|
|
|
|
/// The given parameter was not in range 0.0..=2.0.
|
|
|
|
#[error("invalid threshold {0}, expected 0.0 <= threshold <= 2.0")]
|
|
|
|
Threshold(f32),
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Errors that occur when setting button settings for gamepad input.
|
|
|
|
#[derive(Error, Debug, PartialEq)]
|
|
|
|
pub enum ButtonSettingsError {
|
2022-11-12 22:59:49 +00:00
|
|
|
/// The given parameter was not in range 0.0..=1.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
#[error("invalid release_threshold {0}, expected value [0.0..=1.0]")]
|
|
|
|
ReleaseThresholdOutOfRange(f32),
|
2022-11-12 22:59:49 +00:00
|
|
|
/// The given parameter was not in range 0.0..=1.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
#[error("invalid press_threshold {0}, expected [0.0..=1.0]")]
|
|
|
|
PressThresholdOutOfRange(f32),
|
|
|
|
/// Parameter `release_threshold` was not less than or equal to `press_threshold`.
|
|
|
|
#[error("invalid parameter values release_threshold {} press_threshold {}, expected release_threshold <= press_threshold", .release_threshold, .press_threshold)]
|
|
|
|
ReleaseThresholdGreaterThanPressThreshold {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `press_threshold` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
press_threshold: f32,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the `release_threshold` parameter.
|
2022-10-17 14:38:55 +00:00
|
|
|
release_threshold: f32,
|
|
|
|
},
|
|
|
|
}
|
2020-10-21 17:27:00 +00:00
|
|
|
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg(feature = "serialize")]
|
|
|
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// A gamepad with an associated `ID`.
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
|
|
|
/// The primary way to access the individual connected gamepads is done through the [`Gamepads`]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// `bevy` resource. It is also used inside of [`GamepadConnectionEvent`]s to correspond a gamepad
|
|
|
|
/// with a connection event.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
|
|
|
/// ## Note
|
|
|
|
///
|
|
|
|
/// The `ID` of a gamepad is fixed until the gamepad disconnects or the app is restarted.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect)]
|
|
|
|
#[reflect(Debug, Hash, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2022-05-02 13:20:55 +00:00
|
|
|
pub struct Gamepad {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The `ID` of the gamepad.
|
2022-05-02 13:20:55 +00:00
|
|
|
pub id: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Gamepad {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Creates a new [`Gamepad`].
|
2022-05-02 13:20:55 +00:00
|
|
|
pub fn new(id: usize) -> Self {
|
|
|
|
Self { id }
|
|
|
|
}
|
|
|
|
}
|
2020-09-18 21:43:47 +00:00
|
|
|
|
2023-04-23 17:28:36 +00:00
|
|
|
/// Metadata associated with a [`Gamepad`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2022-10-24 14:33:50 +00:00
|
|
|
pub struct GamepadInfo {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The name of the gamepad.
|
|
|
|
///
|
|
|
|
/// This name is generally defined by the OS.
|
|
|
|
///
|
|
|
|
/// For example on Windows the name may be "HID-compliant game controller".
|
2022-10-24 14:33:50 +00:00
|
|
|
pub name: String,
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// A collection of connected [`Gamepad`]s.
|
2021-12-08 20:28:08 +00:00
|
|
|
///
|
2022-08-05 02:28:07 +00:00
|
|
|
/// ## Usage
|
|
|
|
///
|
|
|
|
/// It is stored in a `bevy` resource which tracks all of the currently connected [`Gamepad`]s.
|
|
|
|
///
|
|
|
|
/// ## Updating
|
|
|
|
///
|
|
|
|
/// The [`Gamepad`]s are registered and deregistered in the [`gamepad_connection_system`]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// whenever a [`GamepadConnectionEvent`] is received.
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource, Default, Debug)]
|
2021-12-08 20:28:08 +00:00
|
|
|
pub struct Gamepads {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The collection of the connected [`Gamepad`]s.
|
2022-10-24 14:33:50 +00:00
|
|
|
gamepads: HashMap<Gamepad, GamepadInfo>,
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Gamepads {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns `true` if the `gamepad` is connected.
|
2022-09-03 20:08:54 +00:00
|
|
|
pub fn contains(&self, gamepad: Gamepad) -> bool {
|
2022-10-24 14:33:50 +00:00
|
|
|
self.gamepads.contains_key(&gamepad)
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 20:08:54 +00:00
|
|
|
/// Returns an iterator over registered [`Gamepad`]s in an arbitrary order.
|
|
|
|
pub fn iter(&self) -> impl Iterator<Item = Gamepad> + '_ {
|
2022-10-24 14:33:50 +00:00
|
|
|
self.gamepads.keys().copied()
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The name of the gamepad if this one is connected.
|
2022-10-24 14:33:50 +00:00
|
|
|
pub fn name(&self, gamepad: Gamepad) -> Option<&str> {
|
|
|
|
self.gamepads.get(&gamepad).map(|g| g.name.as_str())
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 20:08:54 +00:00
|
|
|
/// Registers the `gamepad`, marking it as connected.
|
2022-10-24 14:33:50 +00:00
|
|
|
fn register(&mut self, gamepad: Gamepad, info: GamepadInfo) {
|
|
|
|
self.gamepads.insert(gamepad, info);
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
|
2022-09-03 20:08:54 +00:00
|
|
|
/// Deregisters the `gamepad`, marking it as disconnected.
|
|
|
|
fn deregister(&mut self, gamepad: Gamepad) {
|
|
|
|
self.gamepads.remove(&gamepad);
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// A type of a [`GamepadButton`].
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
|
|
|
/// This is used to determine which button has changed its value when receiving a
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// [`GamepadButtonChangedEvent`]. It is also used in the [`GamepadButton`]
|
2023-12-06 20:32:34 +00:00
|
|
|
/// which in turn is used to create the [`ButtonInput<GamepadButton>`] or
|
2022-08-05 02:28:07 +00:00
|
|
|
/// [`Axis<GamepadButton>`] `bevy` resources.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect)]
|
|
|
|
#[reflect(Debug, Hash, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2020-09-18 21:43:47 +00:00
|
|
|
pub enum GamepadButtonType {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The bottom action button of the action pad (i.e. PS: Cross, Xbox: A).
|
2020-09-18 21:43:47 +00:00
|
|
|
South,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The right action button of the action pad (i.e. PS: Circle, Xbox: B).
|
2020-09-18 21:43:47 +00:00
|
|
|
East,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The upper action button of the action pad (i.e. PS: Triangle, Xbox: Y).
|
2020-09-18 21:43:47 +00:00
|
|
|
North,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The left action button of the action pad (i.e. PS: Square, Xbox: X).
|
2020-09-18 21:43:47 +00:00
|
|
|
West,
|
2022-08-05 02:28:07 +00:00
|
|
|
|
|
|
|
/// The C button.
|
2020-09-18 21:43:47 +00:00
|
|
|
C,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The Z button.
|
2020-09-18 21:43:47 +00:00
|
|
|
Z,
|
2022-08-05 02:28:07 +00:00
|
|
|
|
|
|
|
/// The first left trigger.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftTrigger,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The second left trigger.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftTrigger2,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The first right trigger.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightTrigger,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The second right trigger.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightTrigger2,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The select button.
|
2020-09-18 21:43:47 +00:00
|
|
|
Select,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The start button.
|
2020-09-18 21:43:47 +00:00
|
|
|
Start,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The mode button.
|
2020-09-18 21:43:47 +00:00
|
|
|
Mode,
|
2022-08-05 02:28:07 +00:00
|
|
|
|
|
|
|
/// The left thumb stick button.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftThumb,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The right thumb stick button.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightThumb,
|
2022-08-05 02:28:07 +00:00
|
|
|
|
|
|
|
/// The up button of the D-Pad.
|
2020-09-18 21:43:47 +00:00
|
|
|
DPadUp,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The down button of the D-Pad.
|
2020-09-18 21:43:47 +00:00
|
|
|
DPadDown,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The left button of the D-Pad.
|
2020-09-18 21:43:47 +00:00
|
|
|
DPadLeft,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The right button of the D-Pad.
|
2020-09-18 21:43:47 +00:00
|
|
|
DPadRight,
|
2022-09-02 02:16:18 +00:00
|
|
|
|
|
|
|
/// Miscellaneous buttons, considered non-standard (i.e. Extra buttons on a flight stick that do not have a gamepad equivalent).
|
|
|
|
Other(u8),
|
2020-09-18 21:43:47 +00:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// A button of a [`Gamepad`].
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
2023-12-06 20:32:34 +00:00
|
|
|
/// It is used as the generic `T` value of an [`ButtonInput`] and [`Axis`] to create `bevy` resources. These
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// resources store the data of the buttons of a gamepad and can be accessed inside of a system.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
|
|
|
/// ## Updating
|
|
|
|
///
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// The gamepad button resources are updated inside of the [`gamepad_button_event_system`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect)]
|
|
|
|
#[reflect(Debug, Hash, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2022-05-02 13:20:55 +00:00
|
|
|
pub struct GamepadButton {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The gamepad on which the button is located on.
|
2022-05-02 13:20:55 +00:00
|
|
|
pub gamepad: Gamepad,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The type of the button.
|
2022-05-02 13:20:55 +00:00
|
|
|
pub button_type: GamepadButtonType,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadButton {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Creates a new [`GamepadButton`].
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{GamepadButton, GamepadButtonType, Gamepad};
|
|
|
|
/// #
|
|
|
|
/// let gamepad_button = GamepadButton::new(
|
|
|
|
/// Gamepad::new(1),
|
|
|
|
/// GamepadButtonType::South,
|
|
|
|
/// );
|
|
|
|
/// ```
|
2022-05-02 13:20:55 +00:00
|
|
|
pub fn new(gamepad: Gamepad, button_type: GamepadButtonType) -> Self {
|
|
|
|
Self {
|
|
|
|
gamepad,
|
|
|
|
button_type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-18 21:43:47 +00:00
|
|
|
|
2023-08-20 20:31:27 +00:00
|
|
|
/// A gamepad button input event.
|
|
|
|
#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub struct GamepadButtonInput {
|
|
|
|
/// The gamepad button assigned to the event.
|
|
|
|
pub button: GamepadButton,
|
|
|
|
/// The pressed state of the button.
|
|
|
|
pub state: ButtonState,
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// A type of a [`GamepadAxis`].
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
|
|
|
/// This is used to determine which axis has changed its value when receiving a
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// [`GamepadAxisChangedEvent`]. It is also used in the [`GamepadAxis`]
|
2022-08-05 02:28:07 +00:00
|
|
|
/// which in turn is used to create the [`Axis<GamepadAxis>`] `bevy` resource.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect)]
|
|
|
|
#[reflect(Debug, Hash, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2020-09-18 21:43:47 +00:00
|
|
|
pub enum GamepadAxisType {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The horizontal value of the left stick.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftStickX,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The vertical value of the left stick.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftStickY,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The value of the left `Z` button.
|
2020-09-18 21:43:47 +00:00
|
|
|
LeftZ,
|
2022-08-05 02:28:07 +00:00
|
|
|
|
|
|
|
/// The horizontal value of the right stick.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightStickX,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The vertical value of the right stick.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightStickY,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The value of the right `Z` button.
|
2020-09-18 21:43:47 +00:00
|
|
|
RightZ,
|
2022-09-02 02:16:18 +00:00
|
|
|
|
|
|
|
/// Non-standard support for other axis types (i.e. HOTAS sliders, potentiometers, etc).
|
|
|
|
Other(u8),
|
2020-09-18 21:43:47 +00:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// An axis of a [`Gamepad`].
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// It is used as the generic `T` value of an [`Axis`] to create `bevy` resources. These
|
|
|
|
/// resources store the data of the axes of a gamepad and can be accessed inside of a system.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
|
|
|
/// ## Updating
|
|
|
|
///
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// The gamepad axes resources are updated inside of the [`gamepad_axis_event_system`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect)]
|
|
|
|
#[reflect(Debug, Hash, PartialEq)]
|
2022-10-26 19:52:20 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
2022-05-02 13:20:55 +00:00
|
|
|
pub struct GamepadAxis {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The gamepad on which the axis is located on.
|
2022-05-02 13:20:55 +00:00
|
|
|
pub gamepad: Gamepad,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The type of the axis.
|
2022-05-02 13:20:55 +00:00
|
|
|
pub axis_type: GamepadAxisType,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadAxis {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Creates a new [`GamepadAxis`].
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{GamepadAxis, GamepadAxisType, Gamepad};
|
|
|
|
/// #
|
|
|
|
/// let gamepad_axis = GamepadAxis::new(
|
|
|
|
/// Gamepad::new(1),
|
|
|
|
/// GamepadAxisType::LeftStickX,
|
|
|
|
/// );
|
|
|
|
/// ```
|
2022-05-02 13:20:55 +00:00
|
|
|
pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType) -> Self {
|
|
|
|
Self { gamepad, axis_type }
|
|
|
|
}
|
|
|
|
}
|
2020-10-21 17:27:00 +00:00
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Settings for all [`Gamepad`]s.
|
|
|
|
///
|
|
|
|
/// ## Usage
|
|
|
|
///
|
|
|
|
/// It is used to create a `bevy` resource that stores the settings of every [`GamepadButton`] and
|
|
|
|
/// [`GamepadAxis`]. If no user defined [`ButtonSettings`], [`AxisSettings`], or [`ButtonAxisSettings`]
|
|
|
|
/// are defined, the default settings of each are used as a fallback accordingly.
|
|
|
|
///
|
|
|
|
/// ## Note
|
|
|
|
///
|
2023-01-29 20:11:46 +00:00
|
|
|
/// The [`GamepadSettings`] are used inside of `bevy_gilrs` to determine when raw gamepad events from `gilrs`,
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// should register as a [`GamepadEvent`]. Events that don't meet the change thresholds defined in [`GamepadSettings`]
|
|
|
|
/// will not register. To modify these settings, mutate the corresponding resource.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Resource, Default, Debug, Reflect)]
|
|
|
|
#[reflect(Debug, Default)]
|
2020-10-21 22:56:07 +00:00
|
|
|
pub struct GamepadSettings {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The default button settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub default_button_settings: ButtonSettings,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The default axis settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub default_axis_settings: AxisSettings,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The default button axis settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub default_button_axis_settings: ButtonAxisSettings,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The user defined button settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub button_settings: HashMap<GamepadButton, ButtonSettings>,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The user defined axis settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub axis_settings: HashMap<GamepadAxis, AxisSettings>,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The user defined button axis settings.
|
2020-10-21 22:56:07 +00:00
|
|
|
pub button_axis_settings: HashMap<GamepadButton, ButtonAxisSettings>,
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl GamepadSettings {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns the [`ButtonSettings`] of the `button`.
|
|
|
|
///
|
|
|
|
/// If no user defined [`ButtonSettings`] are specified the default [`ButtonSettings`] get returned.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadButton, Gamepad, GamepadButtonType};
|
|
|
|
/// #
|
|
|
|
/// # let settings = GamepadSettings::default();
|
|
|
|
/// let button = GamepadButton::new(Gamepad::new(1), GamepadButtonType::South);
|
|
|
|
/// let button_settings = settings.get_button_settings(button);
|
|
|
|
/// ```
|
2020-10-21 22:56:07 +00:00
|
|
|
pub fn get_button_settings(&self, button: GamepadButton) -> &ButtonSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
self.button_settings
|
|
|
|
.get(&button)
|
2020-10-21 22:56:07 +00:00
|
|
|
.unwrap_or(&self.default_button_settings)
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns the [`AxisSettings`] of the `axis`.
|
|
|
|
///
|
|
|
|
/// If no user defined [`AxisSettings`] are specified the default [`AxisSettings`] get returned.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadAxis, Gamepad, GamepadAxisType};
|
|
|
|
/// #
|
|
|
|
/// # let settings = GamepadSettings::default();
|
|
|
|
/// let axis = GamepadAxis::new(Gamepad::new(1), GamepadAxisType::LeftStickX);
|
|
|
|
/// let axis_settings = settings.get_axis_settings(axis);
|
|
|
|
/// ```
|
2020-10-21 22:56:07 +00:00
|
|
|
pub fn get_axis_settings(&self, axis: GamepadAxis) -> &AxisSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
self.axis_settings
|
|
|
|
.get(&axis)
|
2020-10-21 22:56:07 +00:00
|
|
|
.unwrap_or(&self.default_axis_settings)
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns the [`ButtonAxisSettings`] of the `button`.
|
|
|
|
///
|
|
|
|
/// If no user defined [`ButtonAxisSettings`] are specified the default [`ButtonAxisSettings`] get returned.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{GamepadSettings, GamepadButton, Gamepad, GamepadButtonType};
|
|
|
|
/// #
|
|
|
|
/// # let settings = GamepadSettings::default();
|
|
|
|
/// let button = GamepadButton::new(Gamepad::new(1), GamepadButtonType::South);
|
|
|
|
/// let button_axis_settings = settings.get_button_axis_settings(button);
|
|
|
|
/// ```
|
2020-10-21 22:56:07 +00:00
|
|
|
pub fn get_button_axis_settings(&self, button: GamepadButton) -> &ButtonAxisSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
self.button_axis_settings
|
|
|
|
.get(&button)
|
2020-10-21 22:56:07 +00:00
|
|
|
.unwrap_or(&self.default_button_axis_settings)
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-17 14:38:55 +00:00
|
|
|
/// Manages settings for gamepad buttons.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// It is used inside of [`GamepadSettings`] to define the threshold for a gamepad button
|
|
|
|
/// to be considered pressed or released. A button is considered pressed if the `press_threshold`
|
|
|
|
/// value is surpassed and released if the `release_threshold` value is undercut.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// Allowed values: `0.0 <= ``release_threshold`` <= ``press_threshold`` <= 1.0`
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Clone, Reflect)]
|
|
|
|
#[reflect(Debug, Default)]
|
2020-10-21 22:56:07 +00:00
|
|
|
pub struct ButtonSettings {
|
2022-10-17 14:38:55 +00:00
|
|
|
press_threshold: f32,
|
|
|
|
release_threshold: f32,
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl Default for ButtonSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
fn default() -> Self {
|
2020-10-21 22:56:07 +00:00
|
|
|
ButtonSettings {
|
2022-10-17 14:38:55 +00:00
|
|
|
press_threshold: 0.75,
|
|
|
|
release_threshold: 0.65,
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl ButtonSettings {
|
2022-10-17 14:38:55 +00:00
|
|
|
/// Creates a new [`ButtonSettings`] instance.
|
|
|
|
///
|
|
|
|
/// # Parameters
|
|
|
|
///
|
|
|
|
/// + `press_threshold` is the button input value above which the button is considered pressed.
|
|
|
|
/// + `release_threshold` is the button input value below which the button is considered released.
|
|
|
|
///
|
|
|
|
/// Restrictions:
|
|
|
|
/// + `0.0 <= ``release_threshold`` <= ``press_threshold`` <= 1.0`
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the restrictions are not met, returns one of
|
|
|
|
/// `GamepadSettingsError::ButtonReleaseThresholdOutOfRange`,
|
|
|
|
/// `GamepadSettingsError::ButtonPressThresholdOutOfRange`, or
|
|
|
|
/// `GamepadSettingsError::ButtonReleaseThresholdGreaterThanPressThreshold`.
|
|
|
|
pub fn new(
|
|
|
|
press_threshold: f32,
|
|
|
|
release_threshold: f32,
|
|
|
|
) -> Result<ButtonSettings, ButtonSettingsError> {
|
|
|
|
if !(0.0..=1.0).contains(&release_threshold) {
|
|
|
|
Err(ButtonSettingsError::ReleaseThresholdOutOfRange(
|
|
|
|
release_threshold,
|
|
|
|
))
|
|
|
|
} else if !(0.0..=1.0).contains(&press_threshold) {
|
|
|
|
Err(ButtonSettingsError::PressThresholdOutOfRange(
|
|
|
|
press_threshold,
|
|
|
|
))
|
|
|
|
} else if release_threshold > press_threshold {
|
|
|
|
Err(
|
|
|
|
ButtonSettingsError::ReleaseThresholdGreaterThanPressThreshold {
|
|
|
|
press_threshold,
|
|
|
|
release_threshold,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
Ok(ButtonSettings {
|
|
|
|
press_threshold,
|
|
|
|
release_threshold,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns `true` if the button is pressed.
|
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// A button is considered pressed if the `value` passed is greater than or equal to the press threshold.
|
2023-11-15 14:29:33 +00:00
|
|
|
pub fn is_pressed(&self, value: f32) -> bool {
|
2022-10-17 14:38:55 +00:00
|
|
|
value >= self.press_threshold
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Returns `true` if the button is released.
|
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// A button is considered released if the `value` passed is lower than or equal to the release threshold.
|
2023-11-15 14:29:33 +00:00
|
|
|
pub fn is_released(&self, value: f32) -> bool {
|
2022-10-17 14:38:55 +00:00
|
|
|
value <= self.release_threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the button input threshold above which the button is considered pressed.
|
|
|
|
pub fn press_threshold(&self) -> f32 {
|
|
|
|
self.press_threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the button input threshold above which the button is considered pressed.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is outside the range [release threshold..=1.0], returns either
|
|
|
|
/// `GamepadSettingsError::ButtonPressThresholdOutOfRange` or
|
|
|
|
/// `GamepadSettingsError::ButtonReleaseThresholdGreaterThanPressThreshold`.
|
|
|
|
pub fn try_set_press_threshold(&mut self, value: f32) -> Result<(), ButtonSettingsError> {
|
|
|
|
if (self.release_threshold..=1.0).contains(&value) {
|
|
|
|
self.press_threshold = value;
|
|
|
|
Ok(())
|
|
|
|
} else if !(0.0..1.0).contains(&value) {
|
|
|
|
Err(ButtonSettingsError::PressThresholdOutOfRange(value))
|
|
|
|
} else {
|
|
|
|
Err(
|
|
|
|
ButtonSettingsError::ReleaseThresholdGreaterThanPressThreshold {
|
|
|
|
press_threshold: value,
|
|
|
|
release_threshold: self.release_threshold,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the button input threshold above which the button is considered pressed.
|
|
|
|
/// If the value passed is outside the range [release threshold..=1.0], the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of the press threshold.
|
|
|
|
pub fn set_press_threshold(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_press_threshold(value).ok();
|
|
|
|
self.press_threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the button input threshold below which the button is considered released.
|
|
|
|
pub fn release_threshold(&self) -> f32 {
|
|
|
|
self.release_threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the button input threshold below which the button is considered released.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is outside the range [0.0..=press threshold], returns
|
|
|
|
/// `ButtonSettingsError::ReleaseThresholdOutOfRange` or
|
|
|
|
/// `ButtonSettingsError::ReleaseThresholdGreaterThanPressThreshold`.
|
|
|
|
pub fn try_set_release_threshold(&mut self, value: f32) -> Result<(), ButtonSettingsError> {
|
|
|
|
if (0.0..=self.press_threshold).contains(&value) {
|
|
|
|
self.release_threshold = value;
|
|
|
|
Ok(())
|
|
|
|
} else if !(0.0..1.0).contains(&value) {
|
|
|
|
Err(ButtonSettingsError::ReleaseThresholdOutOfRange(value))
|
|
|
|
} else {
|
|
|
|
Err(
|
|
|
|
ButtonSettingsError::ReleaseThresholdGreaterThanPressThreshold {
|
|
|
|
press_threshold: self.press_threshold,
|
|
|
|
release_threshold: value,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the button input threshold below which the button is considered released. If the
|
|
|
|
/// value passed is outside the range [0.0..=press threshold], the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of the release threshold.
|
|
|
|
pub fn set_release_threshold(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_release_threshold(value).ok();
|
|
|
|
self.release_threshold
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Settings for a [`GamepadAxis`].
|
|
|
|
///
|
|
|
|
/// It is used inside of the [`GamepadSettings`] to define the sensitivity range and
|
|
|
|
/// threshold for an axis.
|
2022-10-17 14:38:55 +00:00
|
|
|
/// Values that are higher than `livezone_upperbound` will be rounded up to 1.0.
|
|
|
|
/// Values that are lower than `livezone_lowerbound` will be rounded down to -1.0.
|
|
|
|
/// Values that are in-between `deadzone_lowerbound` and `deadzone_upperbound` will be rounded
|
|
|
|
/// to 0.0.
|
|
|
|
/// Otherwise, values will not be rounded.
|
2021-12-18 20:00:18 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// The valid range is `[-1.0, 1.0]`.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Clone, Reflect, PartialEq)]
|
|
|
|
#[reflect(Debug, Default)]
|
2020-10-21 22:56:07 +00:00
|
|
|
pub struct AxisSettings {
|
2023-05-03 19:36:31 +00:00
|
|
|
/// Values that are higher than `livezone_upperbound` will be rounded up to 1.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
livezone_upperbound: f32,
|
|
|
|
/// Positive values that are less than `deadzone_upperbound` will be rounded down to 0.0.
|
|
|
|
deadzone_upperbound: f32,
|
|
|
|
/// Negative values that are greater than `deadzone_lowerbound` will be rounded up to 0.0.
|
|
|
|
deadzone_lowerbound: f32,
|
|
|
|
/// Values that are lower than `livezone_lowerbound` will be rounded down to -1.0.
|
|
|
|
livezone_lowerbound: f32,
|
|
|
|
/// `threshold` defines the minimum difference between old and new values to apply the changes.
|
|
|
|
threshold: f32,
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl Default for AxisSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
fn default() -> Self {
|
2020-10-21 22:56:07 +00:00
|
|
|
AxisSettings {
|
2023-10-12 17:58:32 +00:00
|
|
|
livezone_upperbound: 1.0,
|
2022-10-17 14:38:55 +00:00
|
|
|
deadzone_upperbound: 0.05,
|
|
|
|
deadzone_lowerbound: -0.05,
|
2023-10-12 17:58:32 +00:00
|
|
|
livezone_lowerbound: -1.0,
|
2020-10-21 17:27:00 +00:00
|
|
|
threshold: 0.01,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl AxisSettings {
|
2023-01-16 18:13:04 +00:00
|
|
|
/// Creates a new [`AxisSettings`] instance.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// # Arguments
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// + `livezone_lowerbound` - the value below which inputs will be rounded down to -1.0.
|
|
|
|
/// + `deadzone_lowerbound` - the value above which negative inputs will be rounded up to 0.0.
|
|
|
|
/// + `deadzone_upperbound` - the value below which positive inputs will be rounded down to 0.0.
|
|
|
|
/// + `livezone_upperbound` - the value above which inputs will be rounded up to 1.0.
|
|
|
|
/// + `threshold` - the minimum value by which input must change before the change is registered.
|
|
|
|
///
|
|
|
|
/// Restrictions:
|
2023-01-16 18:13:04 +00:00
|
|
|
///
|
|
|
|
/// + `-1.0 <= livezone_lowerbound <= deadzone_lowerbound <= 0.0`
|
|
|
|
/// + `0.0 <= deadzone_upperbound <= livezone_upperbound <= 1.0`
|
|
|
|
/// + `0.0 <= threshold <= 2.0`
|
2022-10-17 14:38:55 +00:00
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
2023-04-23 17:28:36 +00:00
|
|
|
/// Returns an [`AxisSettingsError`] if any restrictions on the zone values are not met.
|
|
|
|
/// If the zone restrictions are met, but the `threshold` value restrictions are not met,
|
|
|
|
/// returns [`AxisSettingsError::Threshold`].
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn new(
|
|
|
|
livezone_lowerbound: f32,
|
|
|
|
deadzone_lowerbound: f32,
|
|
|
|
deadzone_upperbound: f32,
|
|
|
|
livezone_upperbound: f32,
|
|
|
|
threshold: f32,
|
|
|
|
) -> Result<AxisSettings, AxisSettingsError> {
|
|
|
|
if !(-1.0..=0.0).contains(&livezone_lowerbound) {
|
|
|
|
Err(AxisSettingsError::LiveZoneLowerBoundOutOfRange(
|
|
|
|
livezone_lowerbound,
|
|
|
|
))
|
|
|
|
} else if !(-1.0..=0.0).contains(&deadzone_lowerbound) {
|
|
|
|
Err(AxisSettingsError::DeadZoneLowerBoundOutOfRange(
|
|
|
|
deadzone_lowerbound,
|
|
|
|
))
|
2023-01-16 18:13:04 +00:00
|
|
|
} else if !(0.0..=1.0).contains(&deadzone_upperbound) {
|
2022-10-17 14:38:55 +00:00
|
|
|
Err(AxisSettingsError::DeadZoneUpperBoundOutOfRange(
|
|
|
|
deadzone_upperbound,
|
|
|
|
))
|
2023-01-16 18:13:04 +00:00
|
|
|
} else if !(0.0..=1.0).contains(&livezone_upperbound) {
|
2022-10-17 14:38:55 +00:00
|
|
|
Err(AxisSettingsError::LiveZoneUpperBoundOutOfRange(
|
|
|
|
livezone_upperbound,
|
|
|
|
))
|
|
|
|
} else if livezone_lowerbound > deadzone_lowerbound {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
|
|
|
livezone_lowerbound,
|
|
|
|
deadzone_lowerbound,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else if deadzone_upperbound > livezone_upperbound {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
|
|
|
livezone_upperbound,
|
|
|
|
deadzone_upperbound,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else if !(0.0..=2.0).contains(&threshold) {
|
|
|
|
Err(AxisSettingsError::Threshold(threshold))
|
2021-01-07 20:35:40 +00:00
|
|
|
} else {
|
2022-10-17 14:38:55 +00:00
|
|
|
Ok(Self {
|
|
|
|
livezone_lowerbound,
|
|
|
|
deadzone_lowerbound,
|
|
|
|
deadzone_upperbound,
|
|
|
|
livezone_upperbound,
|
|
|
|
threshold,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the value above which inputs will be rounded up to 1.0.
|
|
|
|
pub fn livezone_upperbound(&self) -> f32 {
|
|
|
|
self.livezone_upperbound
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the value above which inputs will be rounded up to 1.0.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is less than the dead zone upper bound,
|
|
|
|
/// returns `AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound`.
|
2023-01-06 00:43:30 +00:00
|
|
|
/// If the value passed is not in range [0.0..=1.0], returns `AxisSettingsError::LiveZoneUpperBoundOutOfRange`.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn try_set_livezone_upperbound(&mut self, value: f32) -> Result<(), AxisSettingsError> {
|
|
|
|
if !(0.0..=1.0).contains(&value) {
|
|
|
|
Err(AxisSettingsError::LiveZoneUpperBoundOutOfRange(value))
|
|
|
|
} else if value < self.deadzone_upperbound {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
|
|
|
livezone_upperbound: value,
|
|
|
|
deadzone_upperbound: self.deadzone_upperbound,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
self.livezone_upperbound = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the value above which inputs will be rounded up to 1.0.
|
2023-05-04 23:23:45 +00:00
|
|
|
/// If the value passed is negative or less than `deadzone_upperbound`,
|
2022-10-17 14:38:55 +00:00
|
|
|
/// the value will not be changed.
|
2023-05-04 23:23:45 +00:00
|
|
|
///
|
2022-10-17 14:38:55 +00:00
|
|
|
/// Returns the new value of `livezone_upperbound`.
|
|
|
|
pub fn set_livezone_upperbound(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_livezone_upperbound(value).ok();
|
|
|
|
self.livezone_upperbound
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the value below which positive inputs will be rounded down to 0.0.
|
|
|
|
pub fn deadzone_upperbound(&self) -> f32 {
|
|
|
|
self.deadzone_upperbound
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the value below which positive inputs will be rounded down to 0.0.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is greater than the live zone upper bound,
|
|
|
|
/// returns `AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound`.
|
2023-01-06 00:43:30 +00:00
|
|
|
/// If the value passed is not in range [0.0..=1.0], returns `AxisSettingsError::DeadZoneUpperBoundOutOfRange`.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn try_set_deadzone_upperbound(&mut self, value: f32) -> Result<(), AxisSettingsError> {
|
|
|
|
if !(0.0..=1.0).contains(&value) {
|
|
|
|
Err(AxisSettingsError::DeadZoneUpperBoundOutOfRange(value))
|
|
|
|
} else if self.livezone_upperbound < value {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
|
|
|
livezone_upperbound: self.livezone_upperbound,
|
|
|
|
deadzone_upperbound: value,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
self.deadzone_upperbound = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the value below which positive inputs will be rounded down to 0.0.
|
|
|
|
/// If the value passed is negative or greater than `livezone_upperbound`,
|
|
|
|
/// the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of `deadzone_upperbound`.
|
|
|
|
pub fn set_deadzone_upperbound(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_deadzone_upperbound(value).ok();
|
|
|
|
self.deadzone_upperbound
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Get the value below which negative inputs will be rounded down to -1.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn livezone_lowerbound(&self) -> f32 {
|
|
|
|
self.livezone_lowerbound
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Try to set the value below which negative inputs will be rounded down to -1.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is less than the dead zone lower bound,
|
|
|
|
/// returns `AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound`.
|
2023-01-06 00:43:30 +00:00
|
|
|
/// If the value passed is not in range [-1.0..=0.0], returns `AxisSettingsError::LiveZoneLowerBoundOutOfRange`.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn try_set_livezone_lowerbound(&mut self, value: f32) -> Result<(), AxisSettingsError> {
|
|
|
|
if !(-1.0..=0.0).contains(&value) {
|
|
|
|
Err(AxisSettingsError::LiveZoneLowerBoundOutOfRange(value))
|
|
|
|
} else if value > self.deadzone_lowerbound {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
|
|
|
livezone_lowerbound: value,
|
|
|
|
deadzone_lowerbound: self.deadzone_lowerbound,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
self.livezone_lowerbound = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Try to set the value below which negative inputs will be rounded down to -1.0.
|
|
|
|
/// If the value passed is positive or greater than `deadzone_lowerbound`,
|
2022-10-17 14:38:55 +00:00
|
|
|
/// the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of `livezone_lowerbound`.
|
|
|
|
pub fn set_livezone_lowerbound(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_livezone_lowerbound(value).ok();
|
|
|
|
self.livezone_lowerbound
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Get the value above which inputs will be rounded up to 0.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn deadzone_lowerbound(&self) -> f32 {
|
|
|
|
self.deadzone_lowerbound
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Try to set the value above which inputs will be rounded up to 0.0.
|
2022-10-17 14:38:55 +00:00
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is less than the live zone lower bound,
|
|
|
|
/// returns `AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound`.
|
2023-01-06 00:43:30 +00:00
|
|
|
/// If the value passed is not in range [-1.0..=0.0], returns `AxisSettingsError::DeadZoneLowerBoundOutOfRange`.
|
2022-10-17 14:38:55 +00:00
|
|
|
pub fn try_set_deadzone_lowerbound(&mut self, value: f32) -> Result<(), AxisSettingsError> {
|
|
|
|
if !(-1.0..=0.0).contains(&value) {
|
|
|
|
Err(AxisSettingsError::DeadZoneLowerBoundOutOfRange(value))
|
|
|
|
} else if self.livezone_lowerbound > value {
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
|
|
|
livezone_lowerbound: self.livezone_lowerbound,
|
|
|
|
deadzone_lowerbound: value,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
self.deadzone_lowerbound = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-04 23:23:45 +00:00
|
|
|
/// Try to set the value above which inputs will be rounded up to 0.0.
|
|
|
|
/// If the value passed is less than -1.0 or less than `livezone_lowerbound`,
|
2022-10-17 14:38:55 +00:00
|
|
|
/// the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of `deadzone_lowerbound`.
|
|
|
|
pub fn set_deadzone_lowerbound(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_deadzone_lowerbound(value).ok();
|
|
|
|
self.deadzone_lowerbound
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the minimum value by which input must change before the change is registered.
|
|
|
|
pub fn threshold(&self) -> f32 {
|
|
|
|
self.threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the minimum value by which input must change before the change is registered.
|
|
|
|
///
|
|
|
|
/// # Errors
|
|
|
|
///
|
|
|
|
/// If the value passed is not within [0.0..=2.0], returns `GamepadSettingsError::AxisThreshold`.
|
|
|
|
pub fn try_set_threshold(&mut self, value: f32) -> Result<(), AxisSettingsError> {
|
|
|
|
if !(0.0..=2.0).contains(&value) {
|
|
|
|
Err(AxisSettingsError::Threshold(value))
|
|
|
|
} else {
|
|
|
|
self.threshold = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Try to set the minimum value by which input must change before the changes will be applied.
|
|
|
|
/// If the value passed is not within [0.0..=2.0], the value will not be changed.
|
|
|
|
///
|
|
|
|
/// Returns the new value of threshold.
|
|
|
|
pub fn set_threshold(&mut self, value: f32) -> f32 {
|
|
|
|
self.try_set_threshold(value).ok();
|
|
|
|
self.threshold
|
|
|
|
}
|
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// Clamps the `raw_value` according to the `AxisSettings`.
|
|
|
|
pub fn clamp(&self, new_value: f32) -> f32 {
|
|
|
|
if self.deadzone_lowerbound <= new_value && new_value <= self.deadzone_upperbound {
|
|
|
|
0.0
|
|
|
|
} else if new_value >= self.livezone_upperbound {
|
|
|
|
1.0
|
|
|
|
} else if new_value <= self.livezone_lowerbound {
|
|
|
|
-1.0
|
|
|
|
} else {
|
|
|
|
new_value
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
}
|
2021-01-07 20:35:40 +00:00
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// Determines whether the change from `old_value` to `new_value` should
|
2023-04-23 17:28:36 +00:00
|
|
|
/// be registered as a change, according to the [`AxisSettings`].
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
fn should_register_change(&self, new_value: f32, old_value: Option<f32>) -> bool {
|
|
|
|
if old_value.is_none() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
f32::abs(new_value - old_value.unwrap()) > self.threshold
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Filters the `new_value` based on the `old_value`, according to the [`AxisSettings`].
|
|
|
|
///
|
|
|
|
/// Returns the clamped `new_value` if the change exceeds the settings threshold,
|
|
|
|
/// and `None` otherwise.
|
|
|
|
pub fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
|
|
|
let new_value = self.clamp(new_value);
|
|
|
|
|
|
|
|
if self.should_register_change(new_value, old_value) {
|
|
|
|
return Some(new_value);
|
|
|
|
}
|
|
|
|
None
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// Settings for a [`GamepadButton`].
|
|
|
|
///
|
|
|
|
/// It is used inside of the [`GamepadSettings`] to define the sensitivity range and
|
|
|
|
/// threshold for a button axis.
|
|
|
|
///
|
|
|
|
/// ## Logic
|
|
|
|
///
|
|
|
|
/// - Values that are higher than or equal to `high` will be rounded to 1.0.
|
|
|
|
/// - Values that are lower than or equal to `low` will be rounded to 0.0.
|
|
|
|
/// - Otherwise, values will not be rounded.
|
|
|
|
///
|
|
|
|
/// The valid range is from 0.0 to 1.0, inclusive.
|
|
|
|
///
|
|
|
|
/// ## Updating
|
|
|
|
///
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// The current value of a button is received through the [`GamepadButtonChangedEvent`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Clone, Reflect)]
|
|
|
|
#[reflect(Debug, Default)]
|
2020-10-21 22:56:07 +00:00
|
|
|
pub struct ButtonAxisSettings {
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The high value at which to apply rounding.
|
2020-10-21 17:27:00 +00:00
|
|
|
pub high: f32,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The low value at which to apply rounding.
|
2020-10-21 17:27:00 +00:00
|
|
|
pub low: f32,
|
2022-08-05 02:28:07 +00:00
|
|
|
/// The threshold to apply rounding.
|
2020-10-21 17:27:00 +00:00
|
|
|
pub threshold: f32,
|
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl Default for ButtonAxisSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
fn default() -> Self {
|
2020-10-21 22:56:07 +00:00
|
|
|
ButtonAxisSettings {
|
2020-10-21 17:27:00 +00:00
|
|
|
high: 0.95,
|
|
|
|
low: 0.05,
|
|
|
|
threshold: 0.01,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 22:56:07 +00:00
|
|
|
impl ButtonAxisSettings {
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// Clamps the `raw_value` according to the specified settings.
|
2022-08-05 02:28:07 +00:00
|
|
|
///
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// If the `raw_value` is:
|
2022-08-05 02:28:07 +00:00
|
|
|
/// - lower than or equal to `low` it will be rounded to 0.0.
|
|
|
|
/// - higher than or equal to `high` it will be rounded to 1.0.
|
|
|
|
/// - Otherwise it will not be rounded.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
fn clamp(&self, raw_value: f32) -> f32 {
|
|
|
|
if raw_value <= self.low {
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
if raw_value >= self.high {
|
|
|
|
return 1.0;
|
|
|
|
}
|
2021-12-08 01:12:49 +00:00
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
raw_value
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Determines whether the change from an `old_value` to a `new_value` should
|
|
|
|
/// be registered as a change event, according to the specified settings.
|
|
|
|
fn should_register_change(&self, new_value: f32, old_value: Option<f32>) -> bool {
|
|
|
|
if old_value.is_none() {
|
|
|
|
return true;
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
2021-12-08 01:12:49 +00:00
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
f32::abs(new_value - old_value.unwrap()) > self.threshold
|
|
|
|
}
|
|
|
|
|
2023-04-23 17:28:36 +00:00
|
|
|
/// Filters the `new_value` based on the `old_value`, according to the [`ButtonAxisSettings`].
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
///
|
|
|
|
/// Returns the clamped `new_value`, according to the [`ButtonAxisSettings`], if the change
|
|
|
|
/// exceeds the settings threshold, and `None` otherwise.
|
|
|
|
pub fn filter(&self, new_value: f32, old_value: Option<f32>) -> Option<f32> {
|
|
|
|
let new_value = self.clamp(new_value);
|
|
|
|
|
|
|
|
if self.should_register_change(new_value, old_value) {
|
|
|
|
return Some(new_value);
|
|
|
|
}
|
|
|
|
None
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
/// Handles [`GamepadConnectionEvent`]s and updates gamepad resources.
|
|
|
|
///
|
|
|
|
/// Updates the [`Gamepads`] resource and resets and/or initializes
|
2023-12-06 20:32:34 +00:00
|
|
|
/// the [`Axis<GamepadButton>`] and [`ButtonInput<GamepadButton>`] resources.
|
2021-12-08 20:28:08 +00:00
|
|
|
///
|
2022-08-05 02:28:07 +00:00
|
|
|
/// ## Note
|
|
|
|
///
|
|
|
|
/// Whenever a [`Gamepad`] connects or disconnects, an information gets printed to the console using the [`info!`] macro.
|
2021-12-08 20:28:08 +00:00
|
|
|
pub fn gamepad_connection_system(
|
|
|
|
mut gamepads: ResMut<Gamepads>,
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
mut connection_events: EventReader<GamepadConnectionEvent>,
|
|
|
|
mut axis: ResMut<Axis<GamepadAxis>>,
|
|
|
|
mut button_axis: ResMut<Axis<GamepadButton>>,
|
2023-12-06 20:32:34 +00:00
|
|
|
mut button_input: ResMut<ButtonInput<GamepadButton>>,
|
2021-12-08 20:28:08 +00:00
|
|
|
) {
|
2023-08-30 14:20:03 +00:00
|
|
|
for connection_event in connection_events.read() {
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
let gamepad = connection_event.gamepad;
|
|
|
|
|
|
|
|
if let GamepadConnection::Connected(info) = &connection_event.connection {
|
|
|
|
gamepads.register(gamepad, info.clone());
|
|
|
|
info!("{:?} Connected", gamepad);
|
|
|
|
|
|
|
|
for button_type in &ALL_BUTTON_TYPES {
|
|
|
|
let gamepad_button = GamepadButton::new(gamepad, *button_type);
|
|
|
|
button_input.reset(gamepad_button);
|
|
|
|
button_axis.set(gamepad_button, 0.0);
|
|
|
|
}
|
|
|
|
for axis_type in &ALL_AXIS_TYPES {
|
|
|
|
axis.set(GamepadAxis::new(gamepad, *axis_type), 0.0);
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
} else {
|
|
|
|
gamepads.deregister(gamepad);
|
|
|
|
info!("{:?} Disconnected", gamepad);
|
2022-10-24 14:33:50 +00:00
|
|
|
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
for button_type in &ALL_BUTTON_TYPES {
|
|
|
|
let gamepad_button = GamepadButton::new(gamepad, *button_type);
|
|
|
|
button_input.reset(gamepad_button);
|
|
|
|
button_axis.remove(gamepad_button);
|
|
|
|
}
|
|
|
|
for axis_type in &ALL_AXIS_TYPES {
|
|
|
|
axis.remove(GamepadAxis::new(gamepad, *axis_type));
|
2021-12-08 20:28:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The connection status of a gamepad.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub enum GamepadConnection {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The gamepad is connected.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
Connected(GamepadInfo),
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The gamepad is disconnected.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
Disconnected,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A Gamepad connection event. Created when a connection to a gamepad
|
|
|
|
/// is established and when a gamepad is disconnected.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Event, Debug, Clone, PartialEq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub struct GamepadConnectionEvent {
|
|
|
|
/// The gamepad whose connection status changed.
|
|
|
|
pub gamepad: Gamepad,
|
|
|
|
/// The change in the gamepads connection.
|
|
|
|
pub connection: GamepadConnection,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadConnectionEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Creates a [`GamepadConnectionEvent`].
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn new(gamepad: Gamepad, connection: GamepadConnection) -> Self {
|
|
|
|
Self {
|
|
|
|
gamepad,
|
|
|
|
connection,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Is the gamepad connected?
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn connected(&self) -> bool {
|
|
|
|
matches!(self.connection, GamepadConnection::Connected(_))
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Is the gamepad disconnected?
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn disconnected(&self) -> bool {
|
|
|
|
!self.connected()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Gamepad event for when the "value" on the axis changes
|
|
|
|
/// by an amount larger than the threshold defined in [`GamepadSettings`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Event, Debug, Clone, PartialEq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub struct GamepadAxisChangedEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The gamepad on which the axis is triggered.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub gamepad: Gamepad,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The type of the triggered axis.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub axis_type: GamepadAxisType,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the axis.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub value: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadAxisChangedEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Creates a [`GamepadAxisChangedEvent`].
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType, value: f32) -> Self {
|
|
|
|
Self {
|
|
|
|
gamepad,
|
|
|
|
axis_type,
|
|
|
|
value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gamepad event for when the "value" (amount of pressure) on the button
|
|
|
|
/// changes by an amount larger than the threshold defined in [`GamepadSettings`].
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Event, Debug, Clone, PartialEq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub struct GamepadButtonChangedEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The gamepad on which the button is triggered.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub gamepad: Gamepad,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The type of the triggered button.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub button_type: GamepadButtonType,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The value of the button.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub value: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadButtonChangedEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Creates a [`GamepadButtonChangedEvent`].
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn new(gamepad: Gamepad, button_type: GamepadButtonType, value: f32) -> Self {
|
|
|
|
Self {
|
|
|
|
gamepad,
|
|
|
|
button_type,
|
|
|
|
value,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 20:32:34 +00:00
|
|
|
/// Uses [`GamepadAxisChangedEvent`]s to update the relevant [`ButtonInput`] and [`Axis`] values.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn gamepad_axis_event_system(
|
|
|
|
mut gamepad_axis: ResMut<Axis<GamepadAxis>>,
|
|
|
|
mut axis_events: EventReader<GamepadAxisChangedEvent>,
|
|
|
|
) {
|
2023-08-30 14:20:03 +00:00
|
|
|
for axis_event in axis_events.read() {
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
let axis = GamepadAxis::new(axis_event.gamepad, axis_event.axis_type);
|
|
|
|
gamepad_axis.set(axis, axis_event.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 20:32:34 +00:00
|
|
|
/// Uses [`GamepadButtonChangedEvent`]s to update the relevant [`ButtonInput`] and [`Axis`] values.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
pub fn gamepad_button_event_system(
|
2023-08-20 20:31:27 +00:00
|
|
|
mut button_changed_events: EventReader<GamepadButtonChangedEvent>,
|
2023-12-06 20:32:34 +00:00
|
|
|
mut button_input: ResMut<ButtonInput<GamepadButton>>,
|
2023-08-20 20:31:27 +00:00
|
|
|
mut button_input_events: EventWriter<GamepadButtonInput>,
|
2020-10-21 22:56:07 +00:00
|
|
|
settings: Res<GamepadSettings>,
|
2020-10-21 17:27:00 +00:00
|
|
|
) {
|
2023-08-30 14:20:03 +00:00
|
|
|
for button_event in button_changed_events.read() {
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
let button = GamepadButton::new(button_event.gamepad, button_event.button_type);
|
|
|
|
let value = button_event.value;
|
|
|
|
let button_property = settings.get_button_settings(button);
|
|
|
|
|
|
|
|
if button_property.is_released(value) {
|
2023-08-20 20:31:27 +00:00
|
|
|
// Check if button was previously pressed
|
|
|
|
if button_input.pressed(button) {
|
|
|
|
button_input_events.send(GamepadButtonInput {
|
|
|
|
button,
|
|
|
|
state: ButtonState::Released,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// We don't have to check if the button was previously pressed here
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
// because that check is performed within Input<T>::release()
|
|
|
|
button_input.release(button);
|
|
|
|
} else if button_property.is_pressed(value) {
|
2023-08-20 20:31:27 +00:00
|
|
|
// Check if button was previously not pressed
|
|
|
|
if !button_input.pressed(button) {
|
|
|
|
button_input_events.send(GamepadButtonInput {
|
|
|
|
button,
|
|
|
|
state: ButtonState::Pressed,
|
|
|
|
});
|
|
|
|
}
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
button_input.press(button);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A gamepad event.
|
|
|
|
///
|
|
|
|
/// This event type is used over the [`GamepadConnectionEvent`],
|
|
|
|
/// [`GamepadButtonChangedEvent`] and [`GamepadAxisChangedEvent`] when
|
|
|
|
/// the in-frame relative ordering of events is important.
|
bevy_reflect: `FromReflect` Ergonomics Implementation (#6056)
# Objective
**This implementation is based on
https://github.com/bevyengine/rfcs/pull/59.**
---
Resolves #4597
Full details and motivation can be found in the RFC, but here's a brief
summary.
`FromReflect` is a very powerful and important trait within the
reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to
be formed into Real ones (e.g., `Vec<i32>`, etc.).
This mainly comes into play concerning deserialization, where the
reflection deserializers both return a `Box<dyn Reflect>` that almost
always contain one of these Dynamic representations of a Real type. To
convert this to our Real type, we need to use `FromReflect`.
It also sneaks up in other ways. For example, it's a required bound for
`T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`.
It's also required by all fields of an enum as it's used as part of the
`Reflect::apply` implementation.
So in other words, much like `GetTypeRegistration` and `Typed`, it is
very much a core reflection trait.
The problem is that it is not currently treated like a core trait and is
not automatically derived alongside `Reflect`. This makes using it a bit
cumbersome and easy to forget.
## Solution
Automatically derive `FromReflect` when deriving `Reflect`.
Users can then choose to opt-out if needed using the
`#[reflect(from_reflect = false)]` attribute.
```rust
#[derive(Reflect)]
struct Foo;
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Bar;
fn test<T: FromReflect>(value: T) {}
test(Foo); // <-- OK
test(Bar); // <-- Panic! Bar does not implement trait `FromReflect`
```
#### `ReflectFromReflect`
This PR also automatically adds the `ReflectFromReflect` (introduced in
#6245) registration to the derived `GetTypeRegistration` impl— if the
type hasn't opted out of `FromReflect` of course.
<details>
<summary><h4>Improved Deserialization</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
And since we can do all the above, we might as well improve
deserialization. We can now choose to deserialize into a Dynamic type or
automatically convert it using `FromReflect` under the hood.
`[Un]TypedReflectDeserializer::new` will now perform the conversion and
return the `Box`'d Real type.
`[Un]TypedReflectDeserializer::new_dynamic` will work like what we have
now and simply return the `Box`'d Dynamic type.
```rust
// Returns the Real type
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
// Returns the Dynamic type
let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?;
```
</details>
---
## Changelog
* `FromReflect` is now automatically derived within the `Reflect` derive
macro
* This includes auto-registering `ReflectFromReflect` in the derived
`GetTypeRegistration` impl
* ~~Renamed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped**
* ~~Changed `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` to automatically convert the
deserialized output using `FromReflect`~~ **Descoped**
## Migration Guide
* `FromReflect` is now automatically derived within the `Reflect` derive
macro. Items with both derives will need to remove the `FromReflect`
one.
```rust
// OLD
#[derive(Reflect, FromReflect)]
struct Foo;
// NEW
#[derive(Reflect)]
struct Foo;
```
If using a manual implementation of `FromReflect` and the `Reflect`
derive, users will need to opt-out of the automatic implementation.
```rust
// OLD
#[derive(Reflect)]
struct Foo;
impl FromReflect for Foo {/* ... */}
// NEW
#[derive(Reflect)]
#[reflect(from_reflect = false)]
struct Foo;
impl FromReflect for Foo {/* ... */}
```
<details>
<summary><h4>Removed Migrations</h4></summary>
> **Warning**
> This section includes changes that have since been descoped from this
PR. They will likely be implemented again in a followup PR. I am mainly
leaving these details in for archival purposes, as well as for reference
when implementing this logic again.
* The reflect deserializers now perform a `FromReflect` conversion
internally. The expected output of `TypedReflectDeserializer::new` and
`UntypedReflectDeserializer::new` is no longer a Dynamic (e.g.,
`DynamicList`), but its Real counterpart (e.g., `Vec<i32>`).
```rust
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
let mut deserializer = ron::de::Deserializer::from_str(input)?;
// OLD
let output: DynamicStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
// NEW
let output: SomeStruct = reflect_deserializer.deserialize(&mut
deserializer)?.take()?;
```
Alternatively, if this behavior isn't desired, use the
`TypedReflectDeserializer::new_dynamic` and
`UntypedReflectDeserializer::new_dynamic` methods instead:
```rust
// OLD
let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
// NEW
let reflect_deserializer =
UntypedReflectDeserializer::new_dynamic(®istry);
```
</details>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-29 01:31:34 +00:00
|
|
|
#[derive(Event, Debug, Clone, PartialEq, Reflect)]
|
|
|
|
#[reflect(Debug, PartialEq)]
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
#[cfg_attr(
|
|
|
|
feature = "serialize",
|
|
|
|
derive(serde::Serialize, serde::Deserialize),
|
|
|
|
reflect(Serialize, Deserialize)
|
|
|
|
)]
|
|
|
|
pub enum GamepadEvent {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// A gamepad has been connected or disconnected.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
Connection(GamepadConnectionEvent),
|
2023-08-19 18:19:46 +00:00
|
|
|
/// A button of the gamepad has been triggered.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
Button(GamepadButtonChangedEvent),
|
2023-08-19 18:19:46 +00:00
|
|
|
/// An axis of the gamepad has been triggered.
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
Axis(GamepadAxisChangedEvent),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<GamepadConnectionEvent> for GamepadEvent {
|
|
|
|
fn from(value: GamepadConnectionEvent) -> Self {
|
|
|
|
Self::Connection(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<GamepadButtonChangedEvent> for GamepadEvent {
|
|
|
|
fn from(value: GamepadButtonChangedEvent) -> Self {
|
|
|
|
Self::Button(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<GamepadAxisChangedEvent> for GamepadEvent {
|
|
|
|
fn from(value: GamepadAxisChangedEvent) -> Self {
|
|
|
|
Self::Axis(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Splits the [`GamepadEvent`] event stream into it's component events.
|
|
|
|
pub fn gamepad_event_system(
|
|
|
|
mut gamepad_events: EventReader<GamepadEvent>,
|
|
|
|
mut connection_events: EventWriter<GamepadConnectionEvent>,
|
|
|
|
mut button_events: EventWriter<GamepadButtonChangedEvent>,
|
|
|
|
mut axis_events: EventWriter<GamepadAxisChangedEvent>,
|
2023-12-06 20:32:34 +00:00
|
|
|
mut button_input: ResMut<ButtonInput<GamepadButton>>,
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
) {
|
2023-01-16 21:09:24 +00:00
|
|
|
button_input.bypass_change_detection().clear();
|
2023-08-30 14:20:03 +00:00
|
|
|
for gamepad_event in gamepad_events.read() {
|
Gamepad events refactor (#6965)
# Objective
- Remove redundant gamepad events
- Simplify consuming gamepad events.
- Refactor: Separate handling of gamepad events into multiple systems.
## Solution
- Removed `GamepadEventRaw`, and `GamepadEventType`.
- Added bespoke `GamepadConnectionEvent`, `GamepadAxisChangedEvent`, and `GamepadButtonChangedEvent`.
- Refactored `gamepad_event_system`.
- Added `gamepad_button_event_system`, `gamepad_axis_event_system`, and `gamepad_connection_system`, which update the `Input` and `Axis` resources using their corresponding event type.
Gamepad events are now handled in their own systems and have their own types.
This allows for querying for gamepad events without having to match on `GamepadEventType` and makes creating handlers for specific gamepad event types, like a `GamepadConnectionEvent` or `GamepadButtonChangedEvent` possible.
We remove `GamepadEventRaw` by filtering the gamepad events, using `GamepadSettings`, _at the source_, in `bevy_gilrs`. This way we can create `GamepadEvent`s directly and avoid creating `GamepadEventRaw` which do not pass the user defined filters.
We expose ordered `GamepadEvent`s and we can respond to individual gamepad event types.
## Migration Guide
- Replace `GamepadEvent` and `GamepadEventRaw` types with their specific gamepad event type.
2023-01-09 19:24:52 +00:00
|
|
|
match gamepad_event {
|
|
|
|
GamepadEvent::Connection(connection_event) => {
|
|
|
|
connection_events.send(connection_event.clone());
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
Update `Event` send methods to return `EventId` (#10551)
# Objective
- Fixes #10532
## Solution
I've updated the various `Event` send methods to return the sent
`EventId`(s). Since these methods previously returned nothing, and this
information is cheap to copy, there should be minimal negative
consequences to providing this additional information. In the case of
`send_batch`, an iterator is returned built from `Range` and `Map`,
which only consumes 16 bytes on the stack with no heap allocations for
all batch sizes. As such, the cost of this information is negligible.
These changes are reflected for `EventWriter` and `World`. For `World`,
the return types are optional to account for the possible lack of an
`Events` resource. Again, these methods previously returned no
information, so its inclusion should only be a benefit.
## Usage
Now when sending events, the IDs of those events is available for
immediate use:
```rust
// Example of a request-response system where the requester can track handled requests.
/// A system which can make and track requests
fn requester(
mut requests: EventWriter<Request>,
mut handled: EventReader<Handled>,
mut pending: Local<HashSet<EventId<Request>>>,
) {
// Check status of previous requests
for Handled(id) in handled.read() {
pending.remove(&id);
}
if !pending.is_empty() {
error!("Not all my requests were handled on the previous frame!");
pending.clear();
}
// Send a new request and remember its ID for later
let request_id = requests.send(Request::MyRequest { /* ... */ });
pending.insert(request_id);
}
/// A system which handles requests
fn responder(
mut requests: EventReader<Request>,
mut handled: EventWriter<Handled>,
) {
for (request, id) in requests.read_with_id() {
if handle(request).is_ok() {
handled.send(Handled(id));
}
}
}
```
In the above example, a `requester` system can send request events, and
keep track of which ones are currently pending by `EventId`. Then, a
`responder` system can act on that event, providing the ID as a
reference that the `requester` can use. Before this PR, it was not
trivial for a system sending events to keep track of events by ID. This
is unfortunate, since for a system reading events, it is trivial to
access the ID of a event.
---
## Changelog
- Updated `Events`:
- Added `send_batch`
- Modified `send` to return the sent `EventId`
- Modified `send_default` to return the sent `EventId`
- Updated `EventWriter`
- Modified `send_batch` to return all sent `EventId`s
- Modified `send` to return the sent `EventId`
- Modified `send_default` to return the sent `EventId`
- Updated `World`
- Modified `send_event` to return the sent `EventId` if sent, otherwise
`None`.
- Modified `send_event_default` to return the sent `EventId` if sent,
otherwise `None`.
- Modified `send_event_batch` to return all sent `EventId`s if sent,
otherwise `None`.
- Added unit test `test_send_events_ids` to ensure returned `EventId`s
match the sent `Event`s
- Updated uses of modified methods.
## Migration Guide
### `send` / `send_default` / `send_batch`
For the following methods:
- `Events::send`
- `Events::send_default`
- `Events::send_batch`
- `EventWriter::send`
- `EventWriter::send_default`
- `EventWriter::send_batch`
- `World::send_event`
- `World::send_event_default`
- `World::send_event_batch`
Ensure calls to these methods either handle the returned value, or
suppress the result with `;`.
```rust
// Now fails to compile due to mismatched return type
fn send_my_event(mut events: EventWriter<MyEvent>) {
events.send_default()
}
// Fix
fn send_my_event(mut events: EventWriter<MyEvent>) {
events.send_default();
}
```
This will most likely be noticed within `match` statements:
```rust
// Before
match is_pressed {
true => events.send(PlayerAction::Fire),
// ^--^ No longer returns ()
false => {}
}
// After
match is_pressed {
true => {
events.send(PlayerAction::Fire);
},
false => {}
}
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2023-11-16 17:20:43 +00:00
|
|
|
GamepadEvent::Button(button_event) => {
|
|
|
|
button_events.send(button_event.clone());
|
|
|
|
}
|
|
|
|
GamepadEvent::Axis(axis_event) => {
|
|
|
|
axis_events.send(axis_event.clone());
|
|
|
|
}
|
2020-10-21 17:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// An array of every [`GamepadButtonType`] variant.
|
2020-10-21 17:27:00 +00:00
|
|
|
const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [
|
|
|
|
GamepadButtonType::South,
|
|
|
|
GamepadButtonType::East,
|
|
|
|
GamepadButtonType::North,
|
|
|
|
GamepadButtonType::West,
|
|
|
|
GamepadButtonType::C,
|
|
|
|
GamepadButtonType::Z,
|
|
|
|
GamepadButtonType::LeftTrigger,
|
|
|
|
GamepadButtonType::LeftTrigger2,
|
|
|
|
GamepadButtonType::RightTrigger,
|
|
|
|
GamepadButtonType::RightTrigger2,
|
|
|
|
GamepadButtonType::Select,
|
|
|
|
GamepadButtonType::Start,
|
|
|
|
GamepadButtonType::Mode,
|
|
|
|
GamepadButtonType::LeftThumb,
|
|
|
|
GamepadButtonType::RightThumb,
|
|
|
|
GamepadButtonType::DPadUp,
|
|
|
|
GamepadButtonType::DPadDown,
|
|
|
|
GamepadButtonType::DPadLeft,
|
|
|
|
GamepadButtonType::DPadRight,
|
|
|
|
];
|
|
|
|
|
2022-08-05 02:28:07 +00:00
|
|
|
/// An array of every [`GamepadAxisType`] variant.
|
2022-07-11 14:11:25 +00:00
|
|
|
const ALL_AXIS_TYPES: [GamepadAxisType; 6] = [
|
2020-10-21 17:27:00 +00:00
|
|
|
GamepadAxisType::LeftStickX,
|
|
|
|
GamepadAxisType::LeftStickY,
|
|
|
|
GamepadAxisType::LeftZ,
|
|
|
|
GamepadAxisType::RightStickX,
|
|
|
|
GamepadAxisType::RightStickY,
|
|
|
|
GamepadAxisType::RightZ,
|
|
|
|
];
|
2021-12-08 01:12:49 +00:00
|
|
|
|
2023-04-24 15:28:53 +00:00
|
|
|
/// The intensity at which a gamepad's force-feedback motors may rumble.
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
|
|
|
pub struct GamepadRumbleIntensity {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The rumble intensity of the strong gamepad motor.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Ranges from `0.0` to `1.0`.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
|
|
|
/// By convention, this is usually a low-frequency motor on the left-hand
|
|
|
|
/// side of the gamepad, though it may vary across platforms and hardware.
|
|
|
|
pub strong_motor: f32,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The rumble intensity of the weak gamepad motor.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Ranges from `0.0` to `1.0`.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
|
|
|
/// By convention, this is usually a high-frequency motor on the right-hand
|
|
|
|
/// side of the gamepad, though it may vary across platforms and hardware.
|
|
|
|
pub weak_motor: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadRumbleIntensity {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Rumble both gamepad motors at maximum intensity.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub const MAX: Self = GamepadRumbleIntensity {
|
|
|
|
strong_motor: 1.0,
|
|
|
|
weak_motor: 1.0,
|
|
|
|
};
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Rumble the weak motor at maximum intensity.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub const WEAK_MAX: Self = GamepadRumbleIntensity {
|
|
|
|
strong_motor: 0.0,
|
|
|
|
weak_motor: 1.0,
|
|
|
|
};
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Rumble the strong motor at maximum intensity.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub const STRONG_MAX: Self = GamepadRumbleIntensity {
|
|
|
|
strong_motor: 1.0,
|
|
|
|
weak_motor: 0.0,
|
|
|
|
};
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Creates a new rumble intensity with weak motor intensity set to the given value.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Clamped within the `0.0` to `1.0` range.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub const fn weak_motor(intensity: f32) -> Self {
|
|
|
|
Self {
|
|
|
|
weak_motor: intensity,
|
|
|
|
strong_motor: 0.0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Creates a new rumble intensity with strong motor intensity set to the given value.
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Clamped within the `0.0` to `1.0` range.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub const fn strong_motor(intensity: f32) -> Self {
|
|
|
|
Self {
|
|
|
|
strong_motor: intensity,
|
|
|
|
weak_motor: 0.0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-19 18:19:46 +00:00
|
|
|
/// An event that controls force-feedback rumbling of a [`Gamepad`].
|
2023-04-24 15:28:53 +00:00
|
|
|
///
|
|
|
|
/// # Notes
|
|
|
|
///
|
|
|
|
/// Does nothing if the gamepad or platform does not support rumble.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bevy_input::gamepad::{Gamepad, Gamepads, GamepadRumbleRequest, GamepadRumbleIntensity};
|
|
|
|
/// # use bevy_ecs::prelude::{EventWriter, Res};
|
|
|
|
/// # use bevy_utils::Duration;
|
|
|
|
/// fn rumble_gamepad_system(
|
|
|
|
/// mut rumble_requests: EventWriter<GamepadRumbleRequest>,
|
|
|
|
/// gamepads: Res<Gamepads>
|
|
|
|
/// ) {
|
|
|
|
/// for gamepad in gamepads.iter() {
|
|
|
|
/// rumble_requests.send(GamepadRumbleRequest::Add {
|
|
|
|
/// gamepad,
|
|
|
|
/// intensity: GamepadRumbleIntensity::MAX,
|
|
|
|
/// duration: Duration::from_secs_f32(0.5),
|
|
|
|
/// });
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[doc(alias = "haptic feedback")]
|
|
|
|
#[doc(alias = "force feedback")]
|
|
|
|
#[doc(alias = "vibration")]
|
|
|
|
#[doc(alias = "vibrate")]
|
2023-06-06 14:44:32 +00:00
|
|
|
#[derive(Event, Clone)]
|
2023-04-24 15:28:53 +00:00
|
|
|
pub enum GamepadRumbleRequest {
|
|
|
|
/// Add a rumble to the given gamepad.
|
|
|
|
///
|
|
|
|
/// Simultaneous rumble effects add up to the sum of their strengths.
|
|
|
|
///
|
|
|
|
/// Consequently, if two rumbles at half intensity are added at the same
|
|
|
|
/// time, their intensities will be added up, and the controller will rumble
|
|
|
|
/// at full intensity until one of the rumbles finishes, then the rumble
|
|
|
|
/// will continue at the intensity of the remaining event.
|
|
|
|
///
|
|
|
|
/// To replace an existing rumble, send a [`GamepadRumbleRequest::Stop`] event first.
|
|
|
|
Add {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// How long the gamepad should rumble.
|
2023-04-24 15:28:53 +00:00
|
|
|
duration: Duration,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// How intense the rumble should be.
|
2023-04-24 15:28:53 +00:00
|
|
|
intensity: GamepadRumbleIntensity,
|
2023-08-19 18:19:46 +00:00
|
|
|
/// The gamepad to rumble.
|
|
|
|
gamepad: Gamepad,
|
|
|
|
},
|
|
|
|
/// Stop all running rumbles on the given [`Gamepad`].
|
|
|
|
Stop {
|
|
|
|
/// The gamepad to stop rumble.
|
2023-04-24 15:28:53 +00:00
|
|
|
gamepad: Gamepad,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GamepadRumbleRequest {
|
2023-08-19 18:19:46 +00:00
|
|
|
/// Get the [`Gamepad`] associated with this request.
|
2023-04-24 15:28:53 +00:00
|
|
|
pub fn gamepad(&self) -> Gamepad {
|
|
|
|
match self {
|
|
|
|
Self::Add { gamepad, .. } | Self::Stop { gamepad } => *gamepad,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-08 01:12:49 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-10-17 14:38:55 +00:00
|
|
|
use crate::gamepad::{AxisSettingsError, ButtonSettingsError};
|
|
|
|
|
2021-12-18 20:00:18 +00:00
|
|
|
use super::{AxisSettings, ButtonAxisSettings, ButtonSettings};
|
2021-12-08 01:12:49 +00:00
|
|
|
|
|
|
|
fn test_button_axis_settings_filter(
|
|
|
|
settings: ButtonAxisSettings,
|
|
|
|
new_value: f32,
|
|
|
|
old_value: Option<f32>,
|
|
|
|
expected: Option<f32>,
|
|
|
|
) {
|
|
|
|
let actual = settings.filter(new_value, old_value);
|
|
|
|
assert_eq!(
|
|
|
|
expected, actual,
|
2023-01-11 09:51:22 +00:00
|
|
|
"Testing filtering for {settings:?} with new_value = {new_value:?}, old_value = {old_value:?}",
|
2021-12-08 01:12:49 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_button_axis_settings_default_filter() {
|
|
|
|
let cases = [
|
|
|
|
(1.0, None, Some(1.0)),
|
|
|
|
(0.99, None, Some(1.0)),
|
|
|
|
(0.96, None, Some(1.0)),
|
|
|
|
(0.95, None, Some(1.0)),
|
|
|
|
(0.9499, None, Some(0.9499)),
|
|
|
|
(0.84, None, Some(0.84)),
|
|
|
|
(0.43, None, Some(0.43)),
|
|
|
|
(0.05001, None, Some(0.05001)),
|
|
|
|
(0.05, None, Some(0.0)),
|
|
|
|
(0.04, None, Some(0.0)),
|
|
|
|
(0.01, None, Some(0.0)),
|
|
|
|
(0.0, None, Some(0.0)),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (new_value, old_value, expected) in cases {
|
|
|
|
let settings = ButtonAxisSettings::default();
|
|
|
|
test_button_axis_settings_filter(settings, new_value, old_value, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_button_axis_settings_default_filter_with_old_value() {
|
|
|
|
let cases = [
|
|
|
|
(0.43, Some(0.44001), Some(0.43)),
|
|
|
|
(0.43, Some(0.44), None),
|
|
|
|
(0.43, Some(0.43), None),
|
|
|
|
(0.43, Some(0.41999), Some(0.43)),
|
|
|
|
(0.43, Some(0.17), Some(0.43)),
|
|
|
|
(0.43, Some(0.84), Some(0.43)),
|
|
|
|
(0.05, Some(0.055), Some(0.0)),
|
|
|
|
(0.95, Some(0.945), Some(1.0)),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (new_value, old_value, expected) in cases {
|
|
|
|
let settings = ButtonAxisSettings::default();
|
|
|
|
test_button_axis_settings_filter(settings, new_value, old_value, expected);
|
|
|
|
}
|
|
|
|
}
|
2021-12-18 20:00:18 +00:00
|
|
|
|
|
|
|
fn test_axis_settings_filter(
|
|
|
|
settings: AxisSettings,
|
|
|
|
new_value: f32,
|
|
|
|
old_value: Option<f32>,
|
|
|
|
expected: Option<f32>,
|
|
|
|
) {
|
|
|
|
let actual = settings.filter(new_value, old_value);
|
|
|
|
assert_eq!(
|
|
|
|
expected, actual,
|
2023-01-11 09:51:22 +00:00
|
|
|
"Testing filtering for {settings:?} with new_value = {new_value:?}, old_value = {old_value:?}",
|
2021-12-18 20:00:18 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_axis_settings_default_filter() {
|
|
|
|
let cases = [
|
|
|
|
(1.0, Some(1.0)),
|
|
|
|
(0.99, Some(1.0)),
|
|
|
|
(0.96, Some(1.0)),
|
|
|
|
(0.95, Some(1.0)),
|
|
|
|
(0.9499, Some(0.9499)),
|
|
|
|
(0.84, Some(0.84)),
|
|
|
|
(0.43, Some(0.43)),
|
|
|
|
(0.05001, Some(0.05001)),
|
|
|
|
(0.05, Some(0.0)),
|
|
|
|
(0.04, Some(0.0)),
|
|
|
|
(0.01, Some(0.0)),
|
|
|
|
(0.0, Some(0.0)),
|
|
|
|
(-1.0, Some(-1.0)),
|
|
|
|
(-0.99, Some(-1.0)),
|
|
|
|
(-0.96, Some(-1.0)),
|
|
|
|
(-0.95, Some(-1.0)),
|
|
|
|
(-0.9499, Some(-0.9499)),
|
|
|
|
(-0.84, Some(-0.84)),
|
|
|
|
(-0.43, Some(-0.43)),
|
|
|
|
(-0.05001, Some(-0.05001)),
|
|
|
|
(-0.05, Some(0.0)),
|
|
|
|
(-0.04, Some(0.0)),
|
|
|
|
(-0.01, Some(0.0)),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (new_value, expected) in cases {
|
2023-10-12 17:58:32 +00:00
|
|
|
let settings = AxisSettings::new(-0.95, -0.05, 0.05, 0.95, 0.01).unwrap();
|
2021-12-18 20:00:18 +00:00
|
|
|
test_axis_settings_filter(settings, new_value, None, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_axis_settings_default_filter_with_old_values() {
|
|
|
|
let cases = [
|
|
|
|
(0.43, Some(0.44001), Some(0.43)),
|
|
|
|
(0.43, Some(0.44), None),
|
|
|
|
(0.43, Some(0.43), None),
|
|
|
|
(0.43, Some(0.41999), Some(0.43)),
|
|
|
|
(0.43, Some(0.17), Some(0.43)),
|
|
|
|
(0.43, Some(0.84), Some(0.43)),
|
|
|
|
(0.05, Some(0.055), Some(0.0)),
|
|
|
|
(0.95, Some(0.945), Some(1.0)),
|
|
|
|
(-0.43, Some(-0.44001), Some(-0.43)),
|
|
|
|
(-0.43, Some(-0.44), None),
|
|
|
|
(-0.43, Some(-0.43), None),
|
|
|
|
(-0.43, Some(-0.41999), Some(-0.43)),
|
|
|
|
(-0.43, Some(-0.17), Some(-0.43)),
|
|
|
|
(-0.43, Some(-0.84), Some(-0.43)),
|
|
|
|
(-0.05, Some(-0.055), Some(0.0)),
|
|
|
|
(-0.95, Some(-0.945), Some(-1.0)),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (new_value, old_value, expected) in cases {
|
2023-10-12 17:58:32 +00:00
|
|
|
let settings = AxisSettings::new(-0.95, -0.05, 0.05, 0.95, 0.01).unwrap();
|
2021-12-18 20:00:18 +00:00
|
|
|
test_axis_settings_filter(settings, new_value, old_value, expected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_button_settings_default_is_pressed() {
|
|
|
|
let cases = [
|
|
|
|
(1.0, true),
|
|
|
|
(0.95, true),
|
|
|
|
(0.9, true),
|
|
|
|
(0.8, true),
|
|
|
|
(0.75, true),
|
|
|
|
(0.7, false),
|
|
|
|
(0.65, false),
|
|
|
|
(0.5, false),
|
|
|
|
(0.0, false),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (value, expected) in cases {
|
|
|
|
let settings = ButtonSettings::default();
|
|
|
|
let actual = settings.is_pressed(value);
|
|
|
|
|
2022-10-17 14:38:55 +00:00
|
|
|
assert_eq!(
|
|
|
|
expected, actual,
|
2023-01-11 09:51:22 +00:00
|
|
|
"testing ButtonSettings::is_pressed() for value: {value}",
|
2022-10-17 14:38:55 +00:00
|
|
|
);
|
2021-12-18 20:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_button_settings_default_is_released() {
|
|
|
|
let cases = [
|
|
|
|
(1.0, false),
|
|
|
|
(0.95, false),
|
|
|
|
(0.9, false),
|
|
|
|
(0.8, false),
|
|
|
|
(0.75, false),
|
|
|
|
(0.7, false),
|
|
|
|
(0.65, true),
|
|
|
|
(0.5, true),
|
|
|
|
(0.0, true),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (value, expected) in cases {
|
|
|
|
let settings = ButtonSettings::default();
|
|
|
|
let actual = settings.is_released(value);
|
|
|
|
|
2022-10-17 14:38:55 +00:00
|
|
|
assert_eq!(
|
|
|
|
expected, actual,
|
2023-01-11 09:51:22 +00:00
|
|
|
"testing ButtonSettings::is_released() for value: {value}",
|
2022-10-17 14:38:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_new_button_settings_given_valid_parameters() {
|
|
|
|
let cases = [
|
|
|
|
(1.0, 0.0),
|
|
|
|
(1.0, 1.0),
|
|
|
|
(1.0, 0.9),
|
|
|
|
(0.9, 0.9),
|
|
|
|
(0.9, 0.0),
|
|
|
|
(0.0, 0.0),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (press_threshold, release_threshold) in cases {
|
|
|
|
let bs = ButtonSettings::new(press_threshold, release_threshold);
|
|
|
|
match bs {
|
|
|
|
Ok(button_settings) => {
|
|
|
|
assert_eq!(button_settings.press_threshold, press_threshold);
|
|
|
|
assert_eq!(button_settings.release_threshold, release_threshold);
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
panic!(
|
2023-01-11 09:51:22 +00:00
|
|
|
"ButtonSettings::new({press_threshold}, {release_threshold}) should be valid"
|
2022-10-17 14:38:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_new_button_settings_given_invalid_parameters() {
|
|
|
|
let cases = [
|
|
|
|
(1.1, 0.0),
|
|
|
|
(1.1, 1.0),
|
|
|
|
(1.0, 1.1),
|
|
|
|
(-1.0, 0.9),
|
|
|
|
(-1.0, 0.0),
|
|
|
|
(-1.0, -0.4),
|
|
|
|
(0.9, 1.0),
|
|
|
|
(0.0, 0.1),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (press_threshold, release_threshold) in cases {
|
|
|
|
let bs = ButtonSettings::new(press_threshold, release_threshold);
|
|
|
|
match bs {
|
|
|
|
Ok(_) => {
|
|
|
|
panic!(
|
2023-01-11 09:51:22 +00:00
|
|
|
"ButtonSettings::new({press_threshold}, {release_threshold}) should be invalid"
|
2022-10-17 14:38:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
Err(err_code) => match err_code {
|
|
|
|
ButtonSettingsError::PressThresholdOutOfRange(_press_threshold) => {}
|
|
|
|
ButtonSettingsError::ReleaseThresholdGreaterThanPressThreshold {
|
|
|
|
press_threshold: _press_threshold,
|
|
|
|
release_threshold: _release_threshold,
|
|
|
|
} => {}
|
|
|
|
ButtonSettingsError::ReleaseThresholdOutOfRange(_release_threshold) => {}
|
|
|
|
},
|
|
|
|
}
|
2021-12-18 20:00:18 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-17 14:38:55 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_try_out_of_range_axis_settings() {
|
|
|
|
let mut axis_settings = AxisSettings::default();
|
2023-01-16 18:13:04 +00:00
|
|
|
assert_eq!(
|
|
|
|
AxisSettings::new(-0.95, -0.05, 0.05, 0.95, 0.001),
|
|
|
|
Ok(AxisSettings {
|
|
|
|
livezone_lowerbound: -0.95,
|
|
|
|
deadzone_lowerbound: -0.05,
|
|
|
|
deadzone_upperbound: 0.05,
|
|
|
|
livezone_upperbound: 0.95,
|
|
|
|
threshold: 0.001,
|
|
|
|
})
|
|
|
|
);
|
2022-10-17 14:38:55 +00:00
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::LiveZoneLowerBoundOutOfRange(-2.0)),
|
|
|
|
axis_settings.try_set_livezone_lowerbound(-2.0)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::LiveZoneLowerBoundOutOfRange(0.1)),
|
|
|
|
axis_settings.try_set_livezone_lowerbound(0.1)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::DeadZoneLowerBoundOutOfRange(-2.0)),
|
|
|
|
axis_settings.try_set_deadzone_lowerbound(-2.0)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::DeadZoneLowerBoundOutOfRange(0.1)),
|
|
|
|
axis_settings.try_set_deadzone_lowerbound(0.1)
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::DeadZoneUpperBoundOutOfRange(-0.1)),
|
|
|
|
axis_settings.try_set_deadzone_upperbound(-0.1)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::DeadZoneUpperBoundOutOfRange(1.1)),
|
|
|
|
axis_settings.try_set_deadzone_upperbound(1.1)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::LiveZoneUpperBoundOutOfRange(-0.1)),
|
|
|
|
axis_settings.try_set_livezone_upperbound(-0.1)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(AxisSettingsError::LiveZoneUpperBoundOutOfRange(1.1)),
|
|
|
|
axis_settings.try_set_livezone_upperbound(1.1)
|
|
|
|
);
|
|
|
|
|
|
|
|
axis_settings.set_livezone_lowerbound(-0.7);
|
|
|
|
axis_settings.set_deadzone_lowerbound(-0.3);
|
|
|
|
assert_eq!(
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
|
|
|
livezone_lowerbound: -0.1,
|
|
|
|
deadzone_lowerbound: -0.3,
|
|
|
|
}
|
|
|
|
),
|
|
|
|
axis_settings.try_set_livezone_lowerbound(-0.1)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::LiveZoneLowerBoundGreaterThanDeadZoneLowerBound {
|
|
|
|
livezone_lowerbound: -0.7,
|
|
|
|
deadzone_lowerbound: -0.9
|
|
|
|
}
|
|
|
|
),
|
|
|
|
axis_settings.try_set_deadzone_lowerbound(-0.9)
|
|
|
|
);
|
|
|
|
|
|
|
|
axis_settings.set_deadzone_upperbound(0.3);
|
|
|
|
axis_settings.set_livezone_upperbound(0.7);
|
|
|
|
assert_eq!(
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
|
|
|
deadzone_upperbound: 0.8,
|
|
|
|
livezone_upperbound: 0.7
|
|
|
|
}
|
|
|
|
),
|
|
|
|
axis_settings.try_set_deadzone_upperbound(0.8)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
Err(
|
|
|
|
AxisSettingsError::DeadZoneUpperBoundGreaterThanLiveZoneUpperBound {
|
|
|
|
deadzone_upperbound: 0.3,
|
|
|
|
livezone_upperbound: 0.1
|
|
|
|
}
|
|
|
|
),
|
|
|
|
axis_settings.try_set_livezone_upperbound(0.1)
|
|
|
|
);
|
|
|
|
}
|
2021-12-08 01:12:49 +00:00
|
|
|
}
|