feat!: serialize feature without errors now
This commit is contained in:
@@ -1,13 +1,77 @@
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use bevy_ecs::{system::Resource, schedule::States};
|
use bevy_ecs::{system::Resource, schedule::States};
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::de;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
#[cfg(feature = "inspector-egui")]
|
||||||
|
use bevy_inspector_egui::prelude::*;
|
||||||
|
#[cfg(all(feature = "reflect", feature = "serialize"))]
|
||||||
|
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||||
|
#[cfg(feature = "serialize")]
|
||||||
|
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||||
|
#[cfg(feature = "reflect")]
|
||||||
|
use {bevy_ecs::prelude::ReflectResource, bevy_reflect::Reflect};
|
||||||
|
|
||||||
use crate::resource::PlayerInputs;
|
use crate::resource::PlayerInputs;
|
||||||
|
|
||||||
pub trait InputsContainer<A: Action>: 'static + std::marker::Sync + std::marker::Send + Resource {
|
macro_rules! define_common_trait {
|
||||||
|
($trait_name:ident, $trait_inner:ident) => {
|
||||||
|
#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name: $trait_inner {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name: $trait_inner + Serialize + DeserializeOwned {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_reflect::Reflect {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_reflect::Reflect + Serialize + DeserializeOwned {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_inspector_egui::Inspectable + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", not(feature = "reflect"), feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_inspector_egui::Inspectable + Serialize + DeserializeOwned + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), feature = "reflect", feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_inspector_egui::Inspectable + bevy_reflect::Reflect + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", feature = "reflect", feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name: $trait_inner + bevy_inspector_egui::Inspectable + bevy_reflect::Reflect + Serialize + DeserializeOwned + InspectorOptions {}
|
||||||
|
};
|
||||||
|
($trait_name:ident<$generic:ident : $bound:path>, $trait_inner:ident<$trait_inner_generic:ident>) => {
|
||||||
|
#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + Serialize + DeserializeOwned {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_reflect::Reflect {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", feature = "reflect", not(feature = "inspector-egui")))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_reflect::Reflect + Serialize + DeserializeOwned {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_inspector_egui::Inspectable + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", not(feature = "reflect"), feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_inspector_egui::Inspectable + Serialize + DeserializeOwned + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(not(feature = "serialize"), feature = "reflect", feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_inspector_egui::Inspectable + bevy_reflect::Reflect + InspectorOptions {}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "serialize", feature = "reflect", feature = "inspector-egui"))]
|
||||||
|
pub trait $trait_name<$generic: $bound>: $trait_inner<$trait_inner_generic> + bevy_inspector_egui::Inspectable + bevy_reflect::Reflect + Serialize + DeserializeOwned + InspectorOptions {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
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<A: Action>: 'static + std::marker::Sync + std::marker::Send + Resource {
|
||||||
/// The method returning an iterator over references to the PlayerInputs.
|
/// 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.
|
/// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime.
|
||||||
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<A>> + 'a>;
|
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<A>> + 'a>;
|
||||||
@@ -17,93 +81,84 @@ pub trait InputsContainer<A: Action>: 'static + std::marker::Sync + std::marker:
|
|||||||
fn me_mut<'a>(&self) -> Option<&'a mut PlayerInputs<A>>;
|
fn me_mut<'a>(&self) -> Option<&'a mut PlayerInputs<A>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(not(feature = "serialize"), not(feature = "reflect"), not(feature = "inspector-egui")))]
|
define_common_trait!(Action, ActionInner);
|
||||||
pub trait Action: 'static + std::marker::Sync + std::marker::Send + PartialEq + Eq + Hash + IntoEnumIterator + Clone + Copy { }
|
define_common_trait!(GameState, GameStateInner);
|
||||||
|
define_common_trait!(InputsContainer<A: Action>, InputsContainerInner<A>);
|
||||||
#[cfg(all(feature = "serialize", not(feature = "reflect"), not(feature = "inspector-egui")))]
|
|
||||||
pub trait Action<'a>: 'static + std::marker::Sync + std::marker::Send + PartialEq + Eq + Hash + IntoEnumIterator + Clone + Copy + Serialize + Deserialize<'a> { }
|
|
||||||
|
|
||||||
#[cfg(all(not(feature = "serialize"), feature = "reflect", not(feature = "inspector-egui")))]
|
|
||||||
pub trait Action: 'static + std::marker::Sync + std::marker::Send + PartialEq + Eq + Hash + IntoEnumIterator + Clone + Copy + Serialize + Deserialize + Reflect { }
|
|
||||||
|
|
||||||
|
|
||||||
pub trait GameState: 'static + std::marker::Sync + std::marker::Send + States {
|
// #[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};
|
||||||
|
|
||||||
#[cfg(test)]
|
// use crate::{hashmap, resource::PlayerInputs, common_traits_conditions};
|
||||||
mod test {
|
|
||||||
use bevy_ecs::{entity::Entity, schedule::States};
|
|
||||||
use bevy_utils::{HashMap, prelude::default};
|
|
||||||
use strum_macros::EnumIter;
|
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
// common_traits_conditions! {
|
||||||
use serde::{Serialize, Deserialize};
|
// #[derive(Debug, Clone, PartialEq)]
|
||||||
|
// #[cfg_attr(feature = "reflect", reflect(Resource))]
|
||||||
|
// pub struct Lobby {
|
||||||
|
// pub me: PlayerId,
|
||||||
|
// pub players: HashMap<PlayerId, Player>,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
use crate::{hashmap, resource::PlayerInputs, common_traits_conditions};
|
// impl Default for Lobby {
|
||||||
|
// fn default() -> Self {
|
||||||
|
// Self {
|
||||||
|
// me: PlayerId::Host,
|
||||||
|
// players: hashmap! {
|
||||||
|
// PlayerId::Host => Player::default()
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
common_traits_conditions! {
|
// common_traits_conditions! {
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
// #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "reflect", reflect(Resource))]
|
// pub enum PlayerId {
|
||||||
pub struct Lobby {
|
// /// Host or alone
|
||||||
pub me: PlayerId,
|
// Host,
|
||||||
pub players: HashMap<PlayerId, Player>,
|
// /// Client
|
||||||
}
|
// Client(()),
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl Default for Lobby {
|
// #[derive(Default, Debug, PartialEq, Clone)]
|
||||||
fn default() -> Self {
|
// pub struct Player {
|
||||||
Self {
|
// /// Client do not need to know about other clients
|
||||||
me: PlayerId::Host,
|
// #[cfg_attr(feature = "serialize", serde(skip))]
|
||||||
players: hashmap! {
|
// pub inputs: PlayerInputs<Action>,
|
||||||
PlayerId::Host => Player::default()
|
// #[cfg_attr(feature = "serialize", serde(skip))]
|
||||||
},
|
// pub entity: Option<Entity>,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
common_traits_conditions! {
|
// #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)]
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
// pub enum GameState {
|
||||||
pub enum PlayerId {
|
// #[default]
|
||||||
/// Host or alone
|
// LevelEditor,
|
||||||
Host,
|
// InGame,
|
||||||
/// Client
|
// }
|
||||||
Client(()),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, Clone)]
|
// impl super::GameState for GameState {}
|
||||||
pub struct Player {
|
|
||||||
/// Client do not need to know about other clients
|
|
||||||
#[cfg_attr(feature = "serialize", serde(skip))]
|
|
||||||
pub inputs: PlayerInputs<Action>,
|
|
||||||
#[cfg_attr(feature = "serialize", serde(skip))]
|
|
||||||
pub entity: Option<Entity>,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)]
|
// // TODO: it is just plug, it must be a trait
|
||||||
pub enum GameState {
|
// /// Actions that can be performed by player
|
||||||
#[default]
|
// #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)]
|
||||||
LevelEditor,
|
// pub enum Action {
|
||||||
InGame,
|
// /// Move forward
|
||||||
}
|
// LeverEditorForward,
|
||||||
|
// /// Move backward
|
||||||
|
// LevelEditorBackward,
|
||||||
|
// /// Move left
|
||||||
|
// LevelEditorLeft,
|
||||||
|
// /// Move right
|
||||||
|
// LevelEditorRight,
|
||||||
|
// LevelEditorFly,
|
||||||
|
// }
|
||||||
|
|
||||||
impl super::GameState for GameState {}
|
// impl super::Action for Action {}
|
||||||
|
// }
|
||||||
// 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 {}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
|||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, de::DeserializeOwned, Serialize};
|
||||||
use std::mem::discriminant;
|
use std::mem::discriminant;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
@@ -39,15 +39,18 @@ where
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
common_traits_conditions! {
|
common_traits_conditions! {
|
||||||
/// Struct that contains user's inputs corresponding to actions
|
/// Struct that contains user's inputs corresponding to actions
|
||||||
#[derive(Debug, PartialEq, Clone, Deref, DerefMut)]
|
#[derive(Debug, PartialEq, Clone, Deref, DerefMut)]
|
||||||
pub struct Inputs<A: Action>(HashMap<A, InputValue>);
|
pub struct Inputs<A: Action>(#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))] HashMap<A, InputValue>);
|
||||||
|
|
||||||
/// Resource that contains current user inputs
|
/// Resource that contains current user inputs
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct PlayerInputs<A: Action> {
|
pub struct PlayerInputs<A: Action> {
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
current: Inputs<A>,
|
current: Inputs<A>,
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
previous: Inputs<A>,
|
previous: Inputs<A>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,9 +215,9 @@ common_traits_conditions! {
|
|||||||
/// Represents the manner in which input is registered
|
/// Represents the manner in which input is registered
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum ActivationMode {
|
pub enum ActivationMode {
|
||||||
/// Action is triggered when the button is pressed
|
/// for<'a> Action<'a> is triggered when the button is pressed
|
||||||
Hold,
|
Hold,
|
||||||
/// Action is triggered when the button is pressed
|
/// for<'a> Action<'a> is triggered when the button is pressed
|
||||||
/// and cannot be triggered again until the button is released
|
/// and cannot be triggered again until the button is released
|
||||||
/// you don't need to release all buttons in chord
|
/// you don't need to release all buttons in chord
|
||||||
/// you can release only last pressed button
|
/// you can release only last pressed button
|
||||||
@@ -269,6 +272,7 @@ common_traits_conditions! {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum BindingCondition<Gs: GameState> {
|
pub enum BindingCondition<Gs: GameState> {
|
||||||
/// During specific game state
|
/// During specific game state
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
InGameState(Gs),
|
InGameState(Gs),
|
||||||
/// Binding is active only if player is in pause menu
|
/// Binding is active only if player is in pause menu
|
||||||
DuringPauseMenu(bool),
|
DuringPauseMenu(bool),
|
||||||
@@ -280,6 +284,7 @@ common_traits_conditions! {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Binding<Gs: GameState> {
|
pub struct Binding<Gs: GameState> {
|
||||||
pub input: ButtonCombination,
|
pub input: ButtonCombination,
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
pub conditions: Vec<BindingCondition<Gs>>,
|
pub conditions: Vec<BindingCondition<Gs>>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,6 +378,7 @@ impl InputValue {
|
|||||||
common_traits_conditions! {
|
common_traits_conditions! {
|
||||||
pub struct Bindings<Gs: GameState> {
|
pub struct Bindings<Gs: GameState> {
|
||||||
/// List of bindings for action
|
/// List of bindings for action
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
list: Vec<Binding<Gs>>,
|
list: Vec<Binding<Gs>>,
|
||||||
/// Possibility to change this binding
|
/// Possibility to change this binding
|
||||||
options: OptionsMode,
|
options: OptionsMode,
|
||||||
@@ -451,6 +457,7 @@ common_traits_conditions! {
|
|||||||
/// and different activation options
|
/// and different activation options
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct BindingConfig<Gs: GameState> {
|
pub struct BindingConfig<Gs: GameState> {
|
||||||
|
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||||
pub bindings: Bindings<Gs>,
|
pub bindings: Bindings<Gs>,
|
||||||
#[cfg_attr(feature = "serialize", serde(skip))]
|
#[cfg_attr(feature = "serialize", serde(skip))]
|
||||||
pub activation: ActivationOptions,
|
pub activation: ActivationOptions,
|
||||||
@@ -471,7 +478,7 @@ common_traits_conditions! {
|
|||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
#[cfg_attr(feature = "reflect", reflect(Resource))]
|
#[cfg_attr(feature = "reflect", reflect(Resource))]
|
||||||
// TODO: Add delay for input
|
// TODO: Add delay for input
|
||||||
pub struct Controls<A: Action, Gs: GameState>(HashMap<A, BindingConfig<Gs>>); // TODO: change HashMap to Vec for faster iteration
|
pub struct Controls<A: Action, Gs: GameState>(#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))] HashMap<A, BindingConfig<Gs>>); // TODO: change HashMap to Vec for faster iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: Action, Gs: GameState> Default for Controls<A, Gs> {
|
impl<A: Action, Gs: GameState> Default for Controls<A, Gs> {
|
||||||
@@ -480,7 +487,7 @@ impl<A: Action, Gs: GameState> Default for Controls<A, Gs> {
|
|||||||
let controls = Self(HashMap::new());
|
let controls = Self(HashMap::new());
|
||||||
|
|
||||||
// If you see this error, you may add new action in menu_actions
|
// If you see this error, you may add new action in menu_actions
|
||||||
// or make sure that you have only one MenuAction with the same name in the MenuActions
|
// or make sure that you have only one Menufor<'a> Action<'a> with the same name in the Menufor<'a> Action<'a>s
|
||||||
assert!(validate_hash_map(&controls.0));
|
assert!(validate_hash_map(&controls.0));
|
||||||
|
|
||||||
controls
|
controls
|
||||||
|
|||||||
Reference in New Issue
Block a user