diff --git a/Cargo.toml b/Cargo.toml index 087bdf3..0508ffd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,3 @@ -[workspace] -resolver = "2" +[workspace] +resolver = "2" members = ["crate/*"] \ No newline at end of file diff --git a/crate/bevy_controls/Cargo.toml b/crate/bevy_controls/Cargo.toml index 2206005..b9a4b9b 100644 --- a/crate/bevy_controls/Cargo.toml +++ b/crate/bevy_controls/Cargo.toml @@ -23,4 +23,9 @@ strum = "0.25.0" strum_macros = "0.25.3" [dev-dependencies] -env_logger = "0.10.1" \ No newline at end of file +env_logger = "0.10.1" + +[[example]] +name = "basic" +path = "example/basic/src/main.rs" +doc-scrape-examples = true diff --git a/crate/bevy_controls/example/basic/Cargo.toml b/crate/bevy_controls/example/basic/Cargo.toml new file mode 100644 index 0000000..2098f63 --- /dev/null +++ b/crate/bevy_controls/example/basic/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "basic" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crate/bevy_controls/example/basic/src/main.rs b/crate/bevy_controls/example/basic/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/crate/bevy_controls/example/basic/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/crate/bevy_controls/src/contract.rs b/crate/bevy_controls/src/contract.rs index 0fe00ad..ea2cda5 100644 --- a/crate/bevy_controls/src/contract.rs +++ b/crate/bevy_controls/src/contract.rs @@ -1,176 +1,176 @@ -use std::hash::Hash; - -use bevy_ecs::{system::Resource, schedule::States}; -use strum::IntoEnumIterator; -#[cfg(feature = "inspector-egui")] -use bevy_inspector_egui::inspector_options::InspectorOptionsType; -// #[cfg(all(feature = "reflect", feature = "serialize"))] -// use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; -#[cfg(feature = "serialize")] -use serde::{Serialize, de::DeserializeOwned}; -#[cfg(feature = "reflect")] -use bevy_reflect::{Reflect, TypePath, FromReflect}; - -use crate::resource::PlayerInputs; - -pub trait ActionInner: 'static + std::marker::Sync + std::marker::Send + PartialEq + Eq + Hash + IntoEnumIterator + Clone + Copy { } - -pub trait GameStateInner: 'static + std::marker::Sync + std::marker::Send + States { } - -pub trait InputsContainerInner: 'static + std::marker::Sync + std::marker::Send + Resource { - /// The method returning an iterator over references to the PlayerInputs. - /// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime. - fn iter_inputs<'a>(&'a self) -> Box> + 'a>; - /// The method returning an player inputs of this client. - fn me<'a>(&self) -> Option<&'a PlayerInputs>; - /// The method returning an mutable player inputs of this client. - fn me_mut<'a>(&self) -> Option<&'a mut PlayerInputs>; -} - -#[cfg(feature = "serialize")] -pub trait SerializeImpl: Serialize + DeserializeOwned { } - -#[cfg(feature = "reflect")] -pub trait ReflectImpl: Reflect + TypePath + FromReflect { } - -#[cfg(feature = "inspector-egui")] -pub trait InspectorEguiImpl: InspectorOptionsType { } - -// ===== Action ===== -// SAFATY: inspector-egui includes reflect -#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait Action: ActionInner {} - -#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait Action: ActionInner + SerializeImpl {} - -#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] -pub trait Action: ActionInner + ReflectImpl {} - -#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] -pub trait Action: ActionInner + SerializeImpl + ReflectImpl{} - -#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] -pub trait Action: ActionInner + ReflectImpl + InspectorEguiImpl {} - -#[cfg(all(feature = "serialize", feature = "inspector-egui"))] -pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} - -// ===== GameState ===== -// SAFATY: inspector-egui includes reflect -#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait GameState: GameStateInner {} - -#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait GameState: GameStateInner + SerializeImpl {} - -#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] -pub trait GameState: GameStateInner + ReflectImpl {} - -#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] -pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl{} - -#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] -pub trait GameState: GameStateInner + ReflectImpl + InspectorEguiImpl {} - -#[cfg(all(feature = "serialize", feature = "inspector-egui"))] -pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} - - - -// ===== InputsContainer ===== -// SAFATY: inspector-egui includes reflect -#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait InputsContainer: InputsContainerInner {} - -#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] -pub trait InputsContainer: InputsContainerInner + SerializeImpl {} - -#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] -pub trait InputsContainer: InputsContainerInner + ReflectImpl {} - -#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] -pub trait InputsContainer: InputsContainerInner + SerializeImpl + ReflectImpl{} - -#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] -pub trait InputsContainer: InputsContainerInner + ReflectImpl + InspectorEguiImpl {} - -#[cfg(all(feature = "serialize", feature = "inspector-egui"))] -pub trait InputsContainer: InputsContainerInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} - -// #[cfg(test)] -// mod test { -// use bevy_ecs::{entity::Entity, schedule::States}; -// use bevy_utils::{HashMap, prelude::default}; -// use strum_macros::EnumIter; - -// #[cfg(feature = "serialize")] -// use serde::{Serialize, Deserialize}; - -// use crate::{hashmap, resource::PlayerInputs, common_traits_conditions}; - -// common_traits_conditions! { -// #[derive(Debug, Clone, PartialEq)] -// #[cfg_attr(feature = "reflect", reflect(Resource))] -// pub struct Lobby { -// pub me: PlayerId, -// pub players: HashMap, -// } -// } - -// impl Default for Lobby { -// fn default() -> Self { -// Self { -// me: PlayerId::Host, -// players: hashmap! { -// PlayerId::Host => Player::default() -// }, -// } -// } -// } - -// common_traits_conditions! { -// #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] -// pub enum PlayerId { -// /// Host or alone -// Host, -// /// Client -// Client(()), -// } - -// #[derive(Default, Debug, PartialEq, Clone)] -// pub struct Player { -// /// Client do not need to know about other clients -// #[cfg_attr(feature = "serialize", serde(skip))] -// pub inputs: PlayerInputs, -// #[cfg_attr(feature = "serialize", serde(skip))] -// pub entity: Option, -// } -// } - -// #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)] -// pub enum GameState { -// #[default] -// LevelEditor, -// InGame, -// } - -// impl super::GameState for GameState {} - -// // TODO: it is just plug, it must be a trait -// /// Actions that can be performed by player -// #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)] -// pub enum Action { -// /// Move forward -// LeverEditorForward, -// /// Move backward -// LevelEditorBackward, -// /// Move left -// LevelEditorLeft, -// /// Move right -// LevelEditorRight, -// LevelEditorFly, -// } - -// impl super::Action for Action {} -// } \ No newline at end of file +use std::hash::Hash; + +use bevy_ecs::{system::Resource, schedule::States}; +use strum::IntoEnumIterator; +#[cfg(feature = "inspector-egui")] +use bevy_inspector_egui::inspector_options::InspectorOptionsType; +// #[cfg(all(feature = "reflect", feature = "serialize"))] +// use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; +#[cfg(feature = "serialize")] +use serde::{Serialize, de::DeserializeOwned}; +#[cfg(feature = "reflect")] +use bevy_reflect::{Reflect, TypePath, FromReflect}; + +use crate::resource::PlayerInputs; + +pub trait ActionInner: 'static + std::marker::Sync + std::marker::Send + PartialEq + Eq + Hash + IntoEnumIterator + Clone + Copy { } + +pub trait GameStateInner: 'static + std::marker::Sync + std::marker::Send + States { } + +pub trait InputsContainerInner: 'static + std::marker::Sync + std::marker::Send + Resource { + /// The method returning an iterator over references to the PlayerInputs. + /// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime. + fn iter_inputs<'a>(&'a self) -> Box> + 'a>; + /// The method returning an player inputs of this client. + fn me<'a>(&self) -> Option<&'a PlayerInputs>; + /// The method returning an mutable player inputs of this client. + fn me_mut<'a>(&self) -> Option<&'a mut PlayerInputs>; +} + +#[cfg(feature = "serialize")] +pub trait SerializeImpl: Serialize + DeserializeOwned { } + +#[cfg(feature = "reflect")] +pub trait ReflectImpl: Reflect + TypePath + FromReflect { } + +#[cfg(feature = "inspector-egui")] +pub trait InspectorEguiImpl: InspectorOptionsType { } + +// ===== Action ===== +// SAFATY: inspector-egui includes reflect +#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait Action: ActionInner {} + +#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait Action: ActionInner + SerializeImpl {} + +#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] +pub trait Action: ActionInner + ReflectImpl {} + +#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] +pub trait Action: ActionInner + SerializeImpl + ReflectImpl{} + +#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] +pub trait Action: ActionInner + ReflectImpl + InspectorEguiImpl {} + +#[cfg(all(feature = "serialize", feature = "inspector-egui"))] +pub trait Action: ActionInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} + +// ===== GameState ===== +// SAFATY: inspector-egui includes reflect +#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait GameState: GameStateInner {} + +#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait GameState: GameStateInner + SerializeImpl {} + +#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] +pub trait GameState: GameStateInner + ReflectImpl {} + +#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] +pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl{} + +#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] +pub trait GameState: GameStateInner + ReflectImpl + InspectorEguiImpl {} + +#[cfg(all(feature = "serialize", feature = "inspector-egui"))] +pub trait GameState: GameStateInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} + + + +// ===== InputsContainer ===== +// SAFATY: inspector-egui includes reflect +#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait InputsContainer: InputsContainerInner {} + +#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))] +pub trait InputsContainer: InputsContainerInner + SerializeImpl {} + +#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))] +pub trait InputsContainer: InputsContainerInner + ReflectImpl {} + +#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))] +pub trait InputsContainer: InputsContainerInner + SerializeImpl + ReflectImpl{} + +#[cfg(all(not(feature = "serialize"), feature = "inspector-egui"))] +pub trait InputsContainer: InputsContainerInner + ReflectImpl + InspectorEguiImpl {} + +#[cfg(all(feature = "serialize", feature = "inspector-egui"))] +pub trait InputsContainer: InputsContainerInner + SerializeImpl + ReflectImpl + InspectorEguiImpl {} + +// #[cfg(test)] +// mod test { +// use bevy_ecs::{entity::Entity, schedule::States}; +// use bevy_utils::{HashMap, prelude::default}; +// use strum_macros::EnumIter; + +// #[cfg(feature = "serialize")] +// use serde::{Serialize, Deserialize}; + +// use crate::{hashmap, resource::PlayerInputs, common_traits_conditions}; + +// common_traits_conditions! { +// #[derive(Debug, Clone, PartialEq)] +// #[cfg_attr(feature = "reflect", reflect(Resource))] +// pub struct Lobby { +// pub me: PlayerId, +// pub players: HashMap, +// } +// } + +// impl Default for Lobby { +// fn default() -> Self { +// Self { +// me: PlayerId::Host, +// players: hashmap! { +// PlayerId::Host => Player::default() +// }, +// } +// } +// } + +// common_traits_conditions! { +// #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] +// pub enum PlayerId { +// /// Host or alone +// Host, +// /// Client +// Client(()), +// } + +// #[derive(Default, Debug, PartialEq, Clone)] +// pub struct Player { +// /// Client do not need to know about other clients +// #[cfg_attr(feature = "serialize", serde(skip))] +// pub inputs: PlayerInputs, +// #[cfg_attr(feature = "serialize", serde(skip))] +// pub entity: Option, +// } +// } + +// #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)] +// pub enum GameState { +// #[default] +// LevelEditor, +// InGame, +// } + +// impl super::GameState for GameState {} + +// // TODO: it is just plug, it must be a trait +// /// Actions that can be performed by player +// #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)] +// pub enum Action { +// /// Move forward +// LeverEditorForward, +// /// Move backward +// LevelEditorBackward, +// /// Move left +// LevelEditorLeft, +// /// Move right +// LevelEditorRight, +// LevelEditorFly, +// } + +// impl super::Action for Action {} +// } diff --git a/crate/bevy_controls/src/plugin.rs b/crate/bevy_controls/src/plugin.rs index 770af9a..e4fc72a 100644 --- a/crate/bevy_controls/src/plugin.rs +++ b/crate/bevy_controls/src/plugin.rs @@ -1,238 +1,238 @@ -use bevy_app::{Plugin, App, Update}; -use bevy_ecs::{system::{Res, ResMut}, schedule::State}; -use bevy_input::{Input, keyboard::KeyCode, mouse::MouseButton}; - -use crate::{resource::*, contract::{Action, GameState, InputsContainer}}; - -pub struct ControlsPlugin { - _action: std::marker::PhantomData, - _inputs_container: std::marker::PhantomData, - _game_state: std::marker::PhantomData, -} - -impl< - A: Action, - Ic: InputsContainer, - Gs: GameState -> Plugin for ControlsPlugin { - fn build(&self, app: &mut App) { - app.init_resource::>() - .add_systems(Update, Self::save_input); - - #[cfg(feature = "reflect")] - app.register_type::>(); - } - -} - -impl< - A: Action, - Ic: InputsContainer, - Gs: GameState -> ControlsPlugin { - /// Process all hard inputs and bindings to update [`PlayerInputs`] - fn save_input( - keyboard_input: Res>, - mouse_input: Res>, - lobby: ResMut, - controls: Res>, - game_state: Res>, - ) { - if let Some(inputs) = lobby.me_mut() { - for (action, config) in controls.iter() { - 'bindings_loop: for binding in config.bindings.iter() { - for condition in &binding.conditions { - match condition { - BindingCondition::InGameState(state) => { - if *state != *game_state.get() { - continue 'bindings_loop; - } - } - } - } - - match &binding.input { - ButtonCombination::Single(button) => match button { - InputType::Keyboard(key) => { - inputs.forced_set(*action, keyboard_input.pressed(*key)); - } - InputType::Mouse(input) => { - match input { - MouseInput::Axis(_axis) => { - todo!(); - } - MouseInput::Button(button) => { - if !mouse_input - .get_pressed() - .any(|b| b == button) - { - continue 'bindings_loop; - } - } - MouseInput::Wheel(_axis) => { - todo!(); - } - } - } - }, - ButtonCombination::Chord(buttons) => { - // If any button in chord is not pressed we skip this `binding` - for button in buttons { - match button { - InputType::Keyboard(key) => { - if !keyboard_input.pressed(*key) { - continue 'bindings_loop; - } - } - InputType::Mouse(input) => { - match input { - MouseInput::Axis(_axis) => { - todo!(); - } - MouseInput::Button(button) => { - if !mouse_input - .get_pressed() - .any(|b| b == button) - { - continue 'bindings_loop; - } - } - MouseInput::Wheel(_axis) => { - todo!(); - } - } - } - } - } - - // TODO: should be [`Chord`](ButtonCombination::Chord) only [`Boolean`](InputValue::Boolean) type - inputs.forced_set(*action, true); - } - } - } - } - } else { - log::error!("cannot find me in inputs container") - } - } -} - - -// #[cfg(test)] -// mod performance_test { -// use crate::{ util::test::{enable_loggings, measure_time, Times}, resource::PlayerInputs}; - -// use super::Controls; -// use std::time::Duration; - -// /// Test for execution time for [`Controls`] get -// /// -// /// Example: -// /// ``` -// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::controls_get --exact --nocapture -// /// ``` -// #[test] -// fn controls_get() { -// enable_loggings(); - -// let controls = Controls::default(); - -// let duration = measure_time( -// || { -// controls.get(Action::LeverEditorForward); -// controls.get(Action::LevelEditorBackward); -// controls.get(Action::LevelEditorLeft); -// controls.get(Action::LevelEditorRight); -// }, -// Times::default(), -// ); - -// log::info!("time: {:?}", duration); -// } - -// /// Test for execution speed for [`PlayerInputs`] get -// fn player_inputs_get() -> Duration { -// enable_loggings(); - -// let inputs = PlayerInputs::default(); - -// let duration = measure_time( -// || { -// inputs.get(Action::LeverEditorForward); -// inputs.get(Action::LevelEditorBackward); -// inputs.get(Action::LevelEditorLeft); -// inputs.get(Action::LevelEditorRight); -// }, -// Times::default(), -// ); - -// duration -// } - -// /// Test for execution speed for [`PlayerInputs`] get_many -// fn player_inputs_get_many() -> Duration { -// enable_loggings(); - -// let inputs = PlayerInputs::default(); - -// let duration = measure_time( -// || { -// inputs.get_many(vec![ -// Action::LeverEditorForward, -// Action::LevelEditorBackward, -// Action::LevelEditorLeft, -// Action::LevelEditorRight, -// ]); -// }, -// Times::default(), -// ); - -// duration -// } - -// /// Test for execution speed for [`PlayerInputs`] get and get_many -// /// -// /// Example: -// /// ``` -// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::compare_player_inputs_get_and_get_many --exact --nocapture -// /// ``` -// #[test] -// fn compare_player_inputs_get_and_get_many() { -// let get = player_inputs_get(); -// let get_many = player_inputs_get_many(); - -// log::info!("get: {:?}", get); -// log::info!("get_many: {:?}", get_many); -// } - -// /// Test for execution speed for [`InputValue`] casting -// #[test] -// fn action_casting() { -// enable_loggings(); - -// let inputs = PlayerInputs::default(); - -// let duration = measure_time( -// || { -// let _ = (inputs.get(Action::LeverEditorForward).as_boolean() as i8 -// - inputs.get(Action::LevelEditorBackward).as_boolean() as i8) -// as f32; -// }, -// 10000000.into(), -// ); - -// log::info!("with casting: {:?}", duration); - -// let inputs = PlayerInputs::default(); - -// let duration = measure_time( -// || { -// let _ = inputs.get(Action::LeverEditorForward); -// let _ = inputs.get(Action::LevelEditorBackward); -// }, -// 10000000.into(), -// ); - -// log::info!("without casting: {:?}", duration); -// } +use bevy_app::{Plugin, App, Update}; +use bevy_ecs::{system::{Res, ResMut}, schedule::State}; +use bevy_input::{Input, keyboard::KeyCode, mouse::MouseButton}; + +use crate::{resource::*, contract::{Action, GameState, InputsContainer}}; + +pub struct ControlsPlugin { + _action: std::marker::PhantomData, + _inputs_container: std::marker::PhantomData, + _game_state: std::marker::PhantomData, +} + +impl< + A: Action, + Ic: InputsContainer, + Gs: GameState +> Plugin for ControlsPlugin { + fn build(&self, app: &mut App) { + app.init_resource::>() + .add_systems(Update, Self::save_input); + + #[cfg(feature = "reflect")] + app.register_type::>(); + } + +} + +impl< + A: Action, + Ic: InputsContainer, + Gs: GameState +> ControlsPlugin { + /// Process all hard inputs and bindings to update [`PlayerInputs`] + fn save_input( + keyboard_input: Res>, + mouse_input: Res>, + lobby: ResMut, + controls: Res>, + game_state: Res>, + ) { + if let Some(inputs) = lobby.me_mut() { + for (action, config) in controls.iter() { + 'bindings_loop: for binding in config.bindings.iter() { + for condition in &binding.conditions { + match condition { + BindingCondition::InGameState(state) => { + if *state != *game_state.get() { + continue 'bindings_loop; + } + } + } + } + + match &binding.input { + ButtonCombination::Single(button) => match button { + InputType::Keyboard(key) => { + inputs.forced_set(*action, keyboard_input.pressed(*key)); + } + InputType::Mouse(input) => { + match input { + MouseInput::Axis(_axis) => { + todo!(); + } + MouseInput::Button(button) => { + if !mouse_input + .get_pressed() + .any(|b| b == button) + { + continue 'bindings_loop; + } + } + MouseInput::Wheel(_axis) => { + todo!(); + } + } + } + }, + ButtonCombination::Chord(buttons) => { + // If any button in chord is not pressed we skip this `binding` + for button in buttons { + match button { + InputType::Keyboard(key) => { + if !keyboard_input.pressed(*key) { + continue 'bindings_loop; + } + } + InputType::Mouse(input) => { + match input { + MouseInput::Axis(_axis) => { + todo!(); + } + MouseInput::Button(button) => { + if !mouse_input + .get_pressed() + .any(|b| b == button) + { + continue 'bindings_loop; + } + } + MouseInput::Wheel(_axis) => { + todo!(); + } + } + } + } + } + + // TODO: should be [`Chord`](ButtonCombination::Chord) only [`Boolean`](InputValue::Boolean) type + inputs.forced_set(*action, true); + } + } + } + } + } else { + log::error!("cannot find me in inputs container") + } + } +} + + +// #[cfg(test)] +// mod performance_test { +// use crate::{ util::test::{enable_loggings, measure_time, Times}, resource::PlayerInputs}; + +// use super::Controls; +// use std::time::Duration; + +// /// Test for execution time for [`Controls`] get +// /// +// /// Example: +// /// ``` +// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::controls_get --exact --nocapture +// /// ``` +// #[test] +// fn controls_get() { +// enable_loggings(); + +// let controls = Controls::default(); + +// let duration = measure_time( +// || { +// controls.get(Action::LeverEditorForward); +// controls.get(Action::LevelEditorBackward); +// controls.get(Action::LevelEditorLeft); +// controls.get(Action::LevelEditorRight); +// }, +// Times::default(), +// ); + +// log::info!("time: {:?}", duration); +// } + +// /// Test for execution speed for [`PlayerInputs`] get +// fn player_inputs_get() -> Duration { +// enable_loggings(); + +// let inputs = PlayerInputs::default(); + +// let duration = measure_time( +// || { +// inputs.get(Action::LeverEditorForward); +// inputs.get(Action::LevelEditorBackward); +// inputs.get(Action::LevelEditorLeft); +// inputs.get(Action::LevelEditorRight); +// }, +// Times::default(), +// ); + +// duration +// } + +// /// Test for execution speed for [`PlayerInputs`] get_many +// fn player_inputs_get_many() -> Duration { +// enable_loggings(); + +// let inputs = PlayerInputs::default(); + +// let duration = measure_time( +// || { +// inputs.get_many(vec![ +// Action::LeverEditorForward, +// Action::LevelEditorBackward, +// Action::LevelEditorLeft, +// Action::LevelEditorRight, +// ]); +// }, +// Times::default(), +// ); + +// duration +// } + +// /// Test for execution speed for [`PlayerInputs`] get and get_many +// /// +// /// Example: +// /// ``` +// /// cargo test --package pih-pah-app --lib --features "dev, ui_egui" -- controls::test::compare_player_inputs_get_and_get_many --exact --nocapture +// /// ``` +// #[test] +// fn compare_player_inputs_get_and_get_many() { +// let get = player_inputs_get(); +// let get_many = player_inputs_get_many(); + +// log::info!("get: {:?}", get); +// log::info!("get_many: {:?}", get_many); +// } + +// /// Test for execution speed for [`InputValue`] casting +// #[test] +// fn action_casting() { +// enable_loggings(); + +// let inputs = PlayerInputs::default(); + +// let duration = measure_time( +// || { +// let _ = (inputs.get(Action::LeverEditorForward).as_boolean() as i8 +// - inputs.get(Action::LevelEditorBackward).as_boolean() as i8) +// as f32; +// }, +// 10000000.into(), +// ); + +// log::info!("with casting: {:?}", duration); + +// let inputs = PlayerInputs::default(); + +// let duration = measure_time( +// || { +// let _ = inputs.get(Action::LeverEditorForward); +// let _ = inputs.get(Action::LevelEditorBackward); +// }, +// 10000000.into(), +// ); + +// log::info!("without casting: {:?}", duration); +// } // } \ No newline at end of file diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1187d9a --- /dev/null +++ b/flake.nix @@ -0,0 +1,36 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs = { + nixpkgs.follows = "nixpkgs"; + flake-utils.follows = "flake-utils"; + }; + }; + }; + + outputs = { self, nixpkgs, flake-utils, rust-overlay }: + flake-utils.lib.eachDefaultSystem + (system: + let + overlays = [ (import rust-overlay) ]; + pkgs = import nixpkgs { + inherit system overlays; + }; + rustToolchain = (pkgs.pkgsBuildHost.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml); + nativeBuildInputs = with pkgs; [ rustToolchain pkg-config ]; + buildInputs = with pkgs; [ + openssl + ]; + in + with pkgs; + { + devShells.default = mkShell { + inherit buildInputs nativeBuildInputs; + }; + } + ); + +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e7aba9c..263cc78 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = '1.72.0' \ No newline at end of file +channel = '1.72.0'