use bevy::ecs::event::{Events, ManualEventReader};
use bevy::input::InputPlugin;
use bevy::prelude::*;
use leafwing_input_manager::action_state::ActionDiff;
use leafwing_input_manager::prelude::*;
use leafwing_input_manager::systems::{generate_action_diffs, process_action_diffs};
use std::fmt::Debug;
#[derive(Actionlike, Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum FpsAction {
MoveLeft,
MoveRight,
Jump,
Shoot,
}
#[derive(Component, Clone, PartialEq, Eq, Debug)]
struct StableId(u64);
fn main() {
let mut client_app = App::new();
client_app
.add_plugins(MinimalPlugins)
.add_plugin(InputPlugin)
.add_plugin(InputManagerPlugin::<FpsAction>::default())
.add_system_to_stage(
CoreStage::PostUpdate,
generate_action_diffs::<FpsAction, StableId>,
)
.add_event::<ActionDiff<FpsAction, StableId>>()
.add_startup_system(spawn_player);
let mut server_app = App::new();
server_app
.add_plugins(MinimalPlugins)
.add_plugin(InputManagerPlugin::<FpsAction>::server())
.add_event::<ActionDiff<FpsAction, StableId>>()
.add_system_to_stage(
CoreStage::PreUpdate,
process_action_diffs::<FpsAction, StableId>,
)
.add_startup_system(spawn_player);
client_app.update();
client_app.send_input(KeyCode::Space);
client_app.send_input(MouseButton::Left);
client_app.update();
let mut player_state_query = client_app.world.query::<&ActionState<FpsAction>>();
let player_state = player_state_query.iter(&client_app.world).next().unwrap();
assert!(player_state.pressed(FpsAction::Jump));
assert!(player_state.pressed(FpsAction::Shoot));
let event_reader =
send_events::<ActionDiff<FpsAction, StableId>>(&client_app, &mut server_app, None);
server_app.update();
let mut player_state_query = server_app.world.query::<&ActionState<FpsAction>>();
let player_state = player_state_query.iter(&server_app.world).next().unwrap();
assert!(player_state.pressed(FpsAction::Jump));
assert!(player_state.pressed(FpsAction::Shoot));
client_app.reset_inputs();
client_app.update();
let mut player_state_query = client_app.world.query::<&ActionState<FpsAction>>();
let player_state = player_state_query.iter(&client_app.world).next().unwrap();
assert!(player_state.released(FpsAction::Jump));
assert!(player_state.released(FpsAction::Shoot));
let _event_reader = send_events::<ActionDiff<FpsAction, StableId>>(
&client_app,
&mut server_app,
Some(event_reader),
);
server_app.update();
let mut player_state_query = server_app.world.query::<&ActionState<FpsAction>>();
let player_state = player_state_query.iter(&server_app.world).next().unwrap();
assert!(player_state.released(FpsAction::Jump));
assert!(player_state.released(FpsAction::Shoot));
}
#[derive(Component)]
struct Player;
fn spawn_player(mut commands: Commands) {
use FpsAction::*;
use KeyCode::*;
commands
.spawn(InputManagerBundle {
input_map: InputMap::new([(W, MoveLeft), (D, MoveRight), (Space, Jump)])
.insert(MouseButton::Left, Shoot)
.build(),
..default()
})
.insert(StableId(76))
.insert(Player);
}
#[must_use]
fn send_events<A: Send + Sync + 'static + Debug + Clone>(
client_app: &App,
server_app: &mut App,
reader: Option<ManualEventReader<A>>,
) -> ManualEventReader<A> {
let client_events: &Events<A> = client_app.world.resource();
let mut server_events: Mut<Events<A>> = server_app.world.resource_mut();
let mut reader = reader.unwrap_or_else(|| client_events.get_reader());
for client_event in reader.iter(client_events) {
dbg!(client_event.clone());
server_events.send(client_event.clone());
}
reader
}