use std::fmt::Debug;
use bevy::math::{Vec2, Vec3};
use bevy::prelude::{Entity, World};
use bevy::reflect::{Reflect, erased_serde};
use dyn_clone::DynClone;
use dyn_eq::DynEq;
use dyn_hash::DynHash;
use serde::Serialize;
use updating::CentralInputStore;
use crate::InputControlKind;
use crate::clashing_inputs::BasicInputs;
pub use self::chord::*;
#[cfg(feature = "gamepad")]
pub use self::gamepad::*;
#[cfg(feature = "keyboard")]
pub use self::keyboard::*;
#[cfg(feature = "mouse")]
pub use self::mouse::*;
pub use self::trait_serde::RegisterUserInput;
pub use self::virtual_axial::*;
pub mod chord;
#[cfg(feature = "gamepad")]
pub mod gamepad;
#[cfg(feature = "keyboard")]
pub mod keyboard;
#[cfg(feature = "mouse")]
pub mod mouse;
pub mod testing_utils;
mod trait_reflection;
mod trait_serde;
pub mod updating;
pub mod virtual_axial;
pub trait UserInput: Send + Sync + Debug {
fn kind(&self) -> InputControlKind;
fn decompose(&self) -> BasicInputs;
}
pub trait Buttonlike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
#[must_use]
fn pressed(&self, input_store: &CentralInputStore, gamepad: Entity) -> bool {
self.get_pressed(input_store, gamepad).unwrap_or(false)
}
#[must_use]
fn get_pressed(&self, input_store: &CentralInputStore, gamepad: Entity) -> Option<bool>;
fn released(&self, input_store: &CentralInputStore, gamepad: Entity) -> bool {
!self.pressed(input_store, gamepad)
}
#[must_use]
fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
f32::from(self.pressed(input_store, gamepad))
}
fn get_value(&self, input_store: &CentralInputStore, gamepad: Entity) -> Option<f32> {
self.get_pressed(input_store, gamepad).map(f32::from)
}
fn press(&self, world: &mut World) {
self.press_as_gamepad(world, None);
}
fn press_as_gamepad(&self, world: &mut World, _gamepad: Option<Entity>) {
self.press(world);
}
fn release(&self, world: &mut World) {
self.release_as_gamepad(world, None);
}
fn release_as_gamepad(&self, world: &mut World, _gamepad: Option<Entity>) {
self.release(world);
}
fn set_value(&self, world: &mut World, value: f32) {
self.set_value_as_gamepad(world, value, None);
}
fn set_value_as_gamepad(&self, world: &mut World, value: f32, _gamepad: Option<Entity>) {
self.set_value(world, value);
}
}
pub trait Axislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
#[must_use]
fn value(&self, input_store: &CentralInputStore, gamepad: Entity) -> f32 {
self.get_value(input_store, gamepad).unwrap_or(0.0)
}
#[must_use]
fn get_value(&self, input_store: &CentralInputStore, gamepad: Entity) -> Option<f32>;
fn set_value(&self, world: &mut World, value: f32) {
self.set_value_as_gamepad(world, value, None);
}
fn set_value_as_gamepad(&self, world: &mut World, value: f32, _gamepad: Option<Entity>) {
self.set_value(world, value);
}
}
pub trait DualAxislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
#[must_use]
fn axis_pair(&self, input_store: &CentralInputStore, gamepad: Entity) -> Vec2 {
self.get_axis_pair(input_store, gamepad)
.unwrap_or(Vec2::ZERO)
}
#[must_use]
fn get_axis_pair(&self, input_store: &CentralInputStore, gamepad: Entity) -> Option<Vec2>;
fn set_axis_pair(&self, world: &mut World, value: Vec2) {
self.set_axis_pair_as_gamepad(world, value, None);
}
fn set_axis_pair_as_gamepad(&self, world: &mut World, value: Vec2, _gamepad: Option<Entity>) {
self.set_axis_pair(world, value);
}
}
pub trait TripleAxislike:
UserInput + DynClone + DynEq + DynHash + Reflect + erased_serde::Serialize
{
#[must_use]
fn axis_triple(&self, input_store: &CentralInputStore, gamepad: Entity) -> Vec3 {
self.get_axis_triple(input_store, gamepad)
.unwrap_or(Vec3::ZERO)
}
fn get_axis_triple(&self, input_store: &CentralInputStore, gamepad: Entity) -> Option<Vec3>;
fn set_axis_triple(&self, world: &mut World, value: Vec3) {
self.set_axis_triple_as_gamepad(world, value, None);
}
fn set_axis_triple_as_gamepad(&self, world: &mut World, value: Vec3, _gamepad: Option<Entity>) {
self.set_axis_triple(world, value);
}
}
#[derive(Reflect, Debug, Clone, PartialEq, Eq, Hash, Serialize)]
pub enum UserInputWrapper {
Button(Box<dyn Buttonlike>),
Axis(Box<dyn Axislike>),
DualAxis(Box<dyn DualAxislike>),
TripleAxis(Box<dyn TripleAxislike>),
}
impl UserInput for UserInputWrapper {
#[track_caller]
fn kind(&self) -> InputControlKind {
match self {
UserInputWrapper::Button(input) => {
debug_assert!(input.kind() == InputControlKind::Button);
input.kind()
}
UserInputWrapper::Axis(input) => {
debug_assert!(input.kind() == InputControlKind::Axis);
input.kind()
}
UserInputWrapper::DualAxis(input) => {
debug_assert!(input.kind() == InputControlKind::DualAxis);
input.kind()
}
UserInputWrapper::TripleAxis(input) => {
debug_assert!(input.kind() == InputControlKind::TripleAxis);
input.kind()
}
}
}
fn decompose(&self) -> BasicInputs {
match self {
UserInputWrapper::Button(input) => input.decompose(),
UserInputWrapper::Axis(input) => input.decompose(),
UserInputWrapper::DualAxis(input) => input.decompose(),
UserInputWrapper::TripleAxis(input) => input.decompose(),
}
}
}