diff --git a/Cargo.toml b/Cargo.toml index 2d98488..46c9616 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "bevy_enhanced_input" version = "0.1.0" authors = ["Hennadii Chernyshchyk "] edition = "2021" -description = "Dynamic and contextual input mappings for Bevy " +description = "Dynamic and contextual input mappings for Bevy" readme = "README.md" repository = "https://github.com/projectharmonia/bevy_enhanced_input" keywords = ["bevy", "input"] @@ -12,6 +12,7 @@ license = "MIT OR Apache-2.0" include = ["/src", "/tests", "/LICENSE*"] [dependencies] +bevy_enhanced_input_macros = { path = "macros" } bevy = { version = "0.14", default-features = false, features = ["serialize"] } bevy_egui = { version = "0.30", default-features = false, features = [ "immutable_ctx", # Require to get read-only access in our exclusive system. @@ -34,3 +35,6 @@ ui_priority = ['bevy/bevy_ui'] # Prioritizes 'egui' over actions when processing inputs. egui_priority = ['dep:bevy_egui'] + +[workspace] +members = ["macros"] diff --git a/examples/minimal.rs b/examples/minimal.rs index 23ab657..0e7ff4f 100644 --- a/examples/minimal.rs +++ b/examples/minimal.rs @@ -31,27 +31,18 @@ impl InputContext for OnFoot { } } -#[derive(Debug)] +#[derive(Debug, InputAction)] +#[action_dim(Axis2D)] struct Walk; -impl InputAction for Walk { - const DIM: ActionValueDim = ActionValueDim::Axis2D; -} - -#[derive(Debug)] +#[derive(Debug, InputAction)] +#[action_dim(Bool)] struct Jump; -impl InputAction for Jump { - const DIM: ActionValueDim = ActionValueDim::Bool; -} - -#[derive(Debug)] +#[derive(Debug, InputAction)] +#[action_dim(Bool)] struct EnterCar; -impl InputAction for EnterCar { - const DIM: ActionValueDim = ActionValueDim::Bool; -} - #[derive(Component)] struct InCar; @@ -66,20 +57,14 @@ impl InputContext for InCar { } } -#[derive(Debug)] +#[derive(Debug, InputAction)] +#[action_dim(Axis2D)] struct Drive; -impl InputAction for Drive { - const DIM: ActionValueDim = ActionValueDim::Axis2D; -} - -#[derive(Debug)] +#[derive(Debug, InputAction)] +#[action_dim(Bool)] struct ExitCar; -impl InputAction for ExitCar { - const DIM: ActionValueDim = ActionValueDim::Bool; -} - fn spawn(mut commands: Commands) { commands.spawn(OnFoot); } diff --git a/macros/Cargo.toml b/macros/Cargo.toml new file mode 100644 index 0000000..7483e06 --- /dev/null +++ b/macros/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bevy_enhanced_input_macros" +version = "0.1.0" +description = "Bevy Enhanced Input Macros" +edition = "2021" +license = "MIT OR Apache-2.0" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "2.0", features = ["full"] } +quote = "1.0" +proc-macro2 = "1.0" diff --git a/macros/src/lib.rs b/macros/src/lib.rs new file mode 100644 index 0000000..f9d3ca4 --- /dev/null +++ b/macros/src/lib.rs @@ -0,0 +1,50 @@ +use proc_macro::TokenStream; +use proc_macro2::TokenTree; +use quote::quote; +use syn::{parse_macro_input, DeriveInput, Meta}; + +#[proc_macro_derive(InputAction, attributes(action_dim))] +pub fn input_action_derive(item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as DeriveInput); + + const ATTR_NAME: &str = "action_dim"; + let mut dim = None; + for attr in input.attrs { + let Meta::List(list) = attr.meta else { + continue; + }; + + if list + .path + .segments + .iter() + .any(|segment| segment.ident == ATTR_NAME) + { + assert!(dim.is_none(), "`{ATTR_NAME}` can be defined only once"); + + let mut token_iter = list.tokens.into_iter(); + let token = token_iter + .next() + .unwrap_or_else(|| panic!("`{ATTR_NAME}` should have argument")); + + let TokenTree::Ident(indent) = token else { + panic!("`{token}` is invalid argument for `{ATTR_NAME}`"); + }; + + dim = Some(indent); + + assert!( + token_iter.next().is_none(), + "`{ATTR_NAME}` should have only a single argument" + ); + } + } + + let dim = dim.unwrap_or_else(|| panic!("`InputAction` should have `{ATTR_NAME}` attribute")); + let struct_name = input.ident; + TokenStream::from(quote! { + impl InputAction for #struct_name { + const DIM: ActionValueDim = ActionValueDim::#dim; + } + }) +} diff --git a/src/lib.rs b/src/lib.rs index 5e39c0d..f0c8f56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod prelude { input_reader::KeyboardModifiers, EnhancedInputPlugin, }; + pub use bevy_enhanced_input_macros::InputAction; } use bevy::{ecs::system::SystemState, input::InputSystem, prelude::*};