use crate::input_system::input_system;
use fnv::FnvHashMap;
use serde::Deserialize;
use std::any::Any;
use std::hash::Hash;
use zengine_engine::{Module, Stage};
use zengine_macro::Resource;
mod input;
mod input_system;
pub use input::*;
pub struct InputModule<T: InputType>(pub Bindings<T>);
impl<T: InputType> Module for InputModule<T> {
fn init(self, engine: &mut zengine_engine::Engine) {
engine.add_system_into_stage(input_system(self.0), Stage::PreUpdate);
}
}
pub mod device {
use serde::Deserialize;
pub type Key = winit::event::VirtualKeyCode;
pub type MouseButton = winit::event::MouseButton;
pub type ControllerButton = gilrs::Button;
#[derive(Eq, PartialEq, Hash, Debug, Deserialize, Clone)]
pub enum Which {
Left,
Right,
}
}
pub trait InputType:
Any + Eq + PartialEq + Hash + Clone + Send + Sync + Default + std::fmt::Debug
{
}
impl InputType for String {}
#[derive(Debug, Deserialize, PartialEq)]
pub struct AxisBind {
source: Input,
#[serde(default)]
invert: bool,
#[serde(default)]
discrete_map: Option<f32>,
}
impl AxisBind {
pub fn with_source(source: Input) -> Self {
Self {
source,
invert: false,
discrete_map: None,
}
}
pub fn invert_input(mut self) -> Self {
self.invert = true;
self
}
pub fn with_discrete_map(mut self, discrete_map: f32) -> Self {
self.discrete_map = Some(discrete_map);
self
}
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
pub struct ActionBind {
source: Input,
}
impl ActionBind {
pub fn with_source(source: Input) -> Self {
Self { source }
}
}
#[derive(Default, Deserialize, PartialEq)]
pub struct Bindings<T: InputType> {
pub axis_mappings: Option<FnvHashMap<T, Vec<AxisBind>>>,
pub action_mappings: Option<FnvHashMap<T, Vec<ActionBind>>>,
}
impl<T: InputType> Bindings<T> {
pub fn add_action(mut self, input_type: T, bind: ActionBind) -> Self {
match &mut self.action_mappings {
Some(action_mappings) => match action_mappings.get_mut(&input_type) {
Some(mappings) => {
mappings.push(bind);
}
None => {
action_mappings.insert(input_type, vec![bind]);
}
},
None => {
let mut action_mappings = FnvHashMap::default();
action_mappings.insert(input_type, vec![bind]);
self.action_mappings = Some(action_mappings);
}
};
self
}
pub fn add_axis(mut self, input_type: T, bind: AxisBind) -> Self {
match &mut self.axis_mappings {
Some(axis_mappings) => match axis_mappings.get_mut(&input_type) {
Some(mappings) => {
mappings.push(bind);
}
None => {
axis_mappings.insert(input_type, vec![bind]);
}
},
None => {
let mut axis_mappings = FnvHashMap::default();
axis_mappings.insert(input_type, vec![bind]);
self.axis_mappings = Some(axis_mappings);
}
};
self
}
}
#[derive(Resource, Debug)]
pub struct InputHandler<T: InputType> {
actions_value: FnvHashMap<T, Vec<(Input, bool)>>,
axes_value: FnvHashMap<T, Vec<(Input, f32)>>,
}
impl<T: InputType> Default for InputHandler<T> {
fn default() -> Self {
InputHandler {
actions_value: FnvHashMap::default(),
axes_value: FnvHashMap::default(),
}
}
}
impl<T: InputType> InputHandler<T> {
pub fn axis_value(&self, input_type: T) -> f32 {
self.axes_value
.get(&input_type)
.and_then(|entry| entry.iter().last().map(|last_event| last_event.1))
.unwrap_or(0.0)
}
pub fn action_value(&self, input_type: T) -> bool {
self.actions_value
.get(&input_type)
.and_then(|entry| entry.iter().last().map(|last_event| last_event.1))
.unwrap_or(false)
}
}