From 9d60abb7502c25a6a56ecac74d8422a880d4ff23 Mon Sep 17 00:00:00 2001 From: barsoosayque <33784900+barsoosayque@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:50:47 +0100 Subject: [PATCH] Derive Reflect and Asset for InputMap (#426) * impl TypePath for InputMap * add a note to RELEASES * implement reflection for most types * allow large enum variant * fix allow large enum * update releases * update registered types --------- Co-authored-by: Alice Cecile --- Cargo.toml | 1 - RELEASES.md | 2 ++ src/input_map.rs | 36 ++++++++++++++++++++++-------------- src/lib.rs | 6 ++++-- src/plugin.rs | 32 ++++++++++++++++++++++++++++++-- src/user_input.rs | 12 ++++++------ 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 635590b1..6646fe3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ itertools = "0.12" serde = { version = "1.0", features = ["derive"] } fixedbitset = "0.4.2" once_cell = "1.17.1" -multimap = "0.9.0" [dev-dependencies] bevy = { version = "0.12", default-features = false, features = [ diff --git a/RELEASES.md b/RELEASES.md index 518f2390..367fbe3f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -2,6 +2,8 @@ ## Unreleased +- Removed `multimap` dependency in favor of regular `HashMap` which allowed to derive `Reflect` for `InputMap`. +- Register types in the reflection system. - added support in `ActionDiff` for value and axis_pair changes - Added `InputMap::Clear`. diff --git a/src/input_map.rs b/src/input_map.rs index b5ffdf18..6623cf24 100644 --- a/src/input_map.rs +++ b/src/input_map.rs @@ -7,12 +7,12 @@ use crate::input_streams::InputStreams; use crate::user_input::{InputKind, Modifier, UserInput}; use crate::Actionlike; +use bevy::asset::Asset; use bevy::ecs::component::Component; use bevy::ecs::system::Resource; use bevy::input::gamepad::Gamepad; -use bevy::reflect::TypeUuid; -use bevy::utils::HashMap; -use multimap::MultiMap; +use bevy::reflect::Reflect; +use bevy::utils::{Entry, HashMap}; use serde::{Deserialize, Serialize}; use core::fmt::Debug; @@ -70,18 +70,19 @@ input_map.insert(MouseButton::Left, Action::Run) input_map.clear_action(Action::Hide); ``` **/ -#[derive(Resource, Component, Debug, Clone, PartialEq, Eq, TypeUuid, Serialize, Deserialize)] -#[uuid = "D7DECC78-8573-42FF-851A-F0344C7D05C9"] +#[derive( + Resource, Component, Debug, Clone, PartialEq, Eq, Asset, Reflect, Serialize, Deserialize, +)] pub struct InputMap { /// The usize stored here is the index of the input in the Actionlike iterator - map: MultiMap, + map: HashMap>, associated_gamepad: Option, } impl Default for InputMap { fn default() -> Self { InputMap { - map: MultiMap::default(), + map: HashMap::default(), associated_gamepad: None, } } @@ -165,13 +166,20 @@ impl InputMap { let input = input.into(); // Check for existing copies of the input: insertion should be idempotent - if let Some(vec) = self.map.get_vec(&action) { + if let Some(vec) = self.map.get(&action) { if vec.contains(&input) { return self; } } - self.map.insert(action, input); + match self.map.entry(action) { + Entry::Occupied(mut entry) => { + entry.get_mut().push(input); + } + Entry::Vacant(entry) => { + entry.insert(vec![input]); + } + }; self } @@ -398,18 +406,18 @@ impl InputMap { impl InputMap { /// Returns an iterator over actions with their inputs pub fn iter(&self) -> impl Iterator)> { - self.map.iter_all() + self.map.iter() } /// Returns a reference to the inputs mapped to `action` #[must_use] pub fn get(&self, action: A) -> Option<&Vec> { - self.map.get_vec(&action) + self.map.get(&action) } /// Returns a mutable reference to the inputs mapped to `action` #[must_use] pub fn get_mut(&mut self, action: A) -> Option<&mut Vec> { - self.map.get_vec_mut(&action) + self.map.get_mut(&action) } /// How many input bindings are registered total? @@ -451,7 +459,7 @@ impl InputMap { /// /// Returns `Some(input)` if found. pub fn remove_at(&mut self, action: A, index: usize) -> Option { - let input_vec = self.map.get_vec_mut(&action)?; + let input_vec = self.map.get_mut(&action)?; if input_vec.len() <= index { None } else { @@ -463,7 +471,7 @@ impl InputMap { /// /// Returns [`Some`] with index if the input was found, or [`None`] if no matching input was found. pub fn remove(&mut self, action: A, input: impl Into) -> Option { - let input_vec = self.map.get_vec_mut(&action)?; + let input_vec = self.map.get_mut(&action)?; let user_input = input.into(); let index = input_vec.iter().position(|i| i == &user_input)?; input_vec.remove(index); diff --git a/src/lib.rs b/src/lib.rs index 8a08acd6..e7a543c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,7 @@ use crate::action_state::ActionState; use crate::input_map::InputMap; use bevy::ecs::prelude::*; -use bevy::reflect::Reflect; +use bevy::reflect::{FromReflect, Reflect, TypePath}; use std::hash::Hash; use std::marker::PhantomData; @@ -83,7 +83,9 @@ pub mod prelude { /// Ultimate, /// } /// ``` -pub trait Actionlike: Eq + Hash + Send + Sync + Clone + Hash + Reflect + 'static { +pub trait Actionlike: + Eq + Hash + Send + Sync + Clone + Hash + Reflect + TypePath + FromReflect + 'static +{ /// The number of variants of this action type fn n_variants() -> usize; diff --git a/src/plugin.rs b/src/plugin.rs index c8079fe6..140c0c71 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,7 +1,15 @@ //! Contains main plugin exported by this crate. +use crate::action_state::{ActionData, ActionState, Timing}; +use crate::axislike::{ + AxisType, DeadZoneShape, DualAxis, DualAxisData, MouseMotionAxisType, MouseWheelAxisType, + SingleAxis, VirtualAxis, VirtualDPad, +}; +use crate::buttonlike::{MouseMotionDirection, MouseWheelDirection}; use crate::clashing_inputs::ClashStrategy; -use crate::prelude::ActionState; +use crate::dynamic_action::DynAction; +use crate::input_map::InputMap; +use crate::user_input::{InputKind, Modifier, UserInput}; use crate::Actionlike; use core::hash::Hash; use core::marker::PhantomData; @@ -9,7 +17,7 @@ use std::fmt::Debug; use bevy::app::{App, Plugin}; use bevy::ecs::prelude::*; -use bevy::input::InputSystem; +use bevy::input::{ButtonState, InputSystem}; use bevy::prelude::{PostUpdate, PreUpdate}; use bevy::reflect::TypePath; #[cfg(feature = "ui")] @@ -151,6 +159,26 @@ impl Plugin for InputManagerPlugin { }; app.register_type::>() + .register_type::>() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::>() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() // Resources .init_resource::>() .init_resource::(); diff --git a/src/user_input.rs b/src/user_input.rs index 74975708..e6a19c90 100644 --- a/src/user_input.rs +++ b/src/user_input.rs @@ -1,7 +1,10 @@ //! Helpful abstractions over user inputs of all sorts +use bevy::input::keyboard::ScanCode; use bevy::input::{gamepad::GamepadButtonType, keyboard::KeyCode, mouse::MouseButton}; use bevy::reflect::Reflect; +use bevy::utils::HashSet; +use serde::{Deserialize, Serialize}; use crate::axislike::VirtualAxis; use crate::scan_codes::QwertyScanCode; @@ -9,16 +12,13 @@ use crate::{ axislike::{AxisType, DualAxis, SingleAxis, VirtualDPad}, buttonlike::{MouseMotionDirection, MouseWheelDirection}, }; -use bevy::prelude::ScanCode; -use bevy::utils::HashSet; -use serde::{Deserialize, Serialize}; /// Some combination of user input, which may cross input-mode boundaries. /// /// For example, this may store mouse, keyboard or gamepad input, including cross-device chords! /// /// Suitable for use in an [`InputMap`](crate::input_map::InputMap) -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Reflect)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum UserInput { /// A single button Single(InputKind), @@ -358,7 +358,7 @@ impl From for UserInput { /// /// Please contact the maintainers if you need support for another type! #[non_exhaustive] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Reflect)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum InputKind { /// A button on a gamepad GamepadButton(GamepadButtonType), @@ -452,7 +452,7 @@ impl From for InputKind { /// /// This buttonlike input is stored in [`InputKind`], and will be triggered whenever either of these buttons are pressed. /// This will be decomposed into both values when converted into [`RawInputs`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Reflect)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)] pub enum Modifier { /// Corresponds to [`KeyCode::AltLeft`] and [`KeyCode::AltRight`]. Alt,