move clientside gated parts of control to the client (#70)

This commit is contained in:
PROMETHIA-27
2025-10-08 18:54:39 -04:00
committed by GitHub
parent 8f24f4e03a
commit 11684b80a9
8 changed files with 104 additions and 115 deletions

View File

@@ -1,21 +1,15 @@
use super::{ControlState, Controls}; use super::Controls;
#[cfg(feature = "client")]
use crate::control::ControllerSet;
use crate::{GameState, control::CharacterInputEnabled}; use crate::{GameState, control::CharacterInputEnabled};
#[cfg(feature = "client")]
use bevy::input::{ use bevy::input::{
ButtonState, ButtonState,
gamepad::{GamepadConnection, GamepadEvent}, gamepad::{GamepadConnection, GamepadEvent},
mouse::{MouseButtonInput, MouseMotion}, mouse::{MouseButtonInput, MouseMotion},
}; };
use bevy::prelude::*; use bevy::prelude::*;
#[cfg(feature = "client")]
use lightyear::input::client::InputSet; use lightyear::input::client::InputSet;
#[cfg(feature = "client")]
use lightyear::prelude::input::native::{ActionState, InputMarker}; use lightyear::prelude::input::native::{ActionState, InputMarker};
use serde::{Deserialize, Serialize}; use shared::control::{ControlState, ControllerSet};
use std::collections::HashMap; use std::collections::HashMap;
#[cfg(feature = "client")]
use std::hash::Hash; use std::hash::Hash;
pub fn plugin(app: &mut App) { pub fn plugin(app: &mut App) {
@@ -24,37 +18,32 @@ pub fn plugin(app: &mut App) {
app.register_required_components::<Gamepad, InputStateCache<GamepadButton>>(); app.register_required_components::<Gamepad, InputStateCache<GamepadButton>>();
app.register_type::<ControllerSettings>();
app.add_systems(PreUpdate, (cache_keyboard_state, cache_gamepad_state)); app.add_systems(PreUpdate, (cache_keyboard_state, cache_gamepad_state));
#[cfg(feature = "client")] app.add_systems(
{ FixedPreUpdate,
app.add_systems( (
FixedPreUpdate, gamepad_controls,
( keyboard_controls,
gamepad_controls, mouse_rotate,
keyboard_controls, mouse_click,
mouse_rotate, gamepad_connections.run_if(on_event::<GamepadEvent>),
mouse_click, combine_controls,
gamepad_connections.run_if(on_event::<GamepadEvent>), clear_keyboard_state,
combine_controls, clear_gamepad_state,
clear_keyboard_state,
clear_gamepad_state,
)
.chain()
.in_set(ControllerSet::CollectInputs)
.before(InputSet::WriteClientInputs)
.run_if(
in_state(GameState::Playing)
.and(resource_exists_and_equals(CharacterInputEnabled::On)),
),
) )
.add_systems( .chain()
FixedPreUpdate, .in_set(ControllerSet::CollectInputs)
buffer_inputs.in_set(InputSet::WriteClientInputs), .before(InputSet::WriteClientInputs)
); .run_if(
} in_state(GameState::Playing)
.and(resource_exists_and_equals(CharacterInputEnabled::On)),
),
)
.add_systems(
FixedPreUpdate,
buffer_inputs.in_set(InputSet::WriteClientInputs),
);
app.add_systems( app.add_systems(
Update, Update,
@@ -62,14 +51,6 @@ pub fn plugin(app: &mut App) {
); );
} }
#[derive(Component, Clone, PartialEq, Reflect, Serialize, Deserialize)]
#[reflect(Component)]
pub struct ControllerSettings {
pub deceleration_factor: f32,
pub jump_force: f32,
}
#[cfg(feature = "client")]
/// Write inputs from combined keyboard/gamepad state into the networked input buffer /// Write inputs from combined keyboard/gamepad state into the networked input buffer
/// for the local player. /// for the local player.
fn buffer_inputs( fn buffer_inputs(
@@ -104,7 +85,6 @@ impl<Button> Default for InputStateCache<Button> {
} }
} }
#[cfg(feature = "client")]
impl<Button: Hash + Eq> InputStateCache<Button> { impl<Button: Hash + Eq> InputStateCache<Button> {
fn clear(&mut self) { fn clear(&mut self) {
for state in self.map.values_mut() { for state in self.map.values_mut() {
@@ -151,7 +131,6 @@ fn cache_keyboard_state(
cache_key(KeyCode::KeyE); cache_key(KeyCode::KeyE);
} }
#[cfg(feature = "client")]
fn clear_keyboard_state(mut cache: ResMut<InputStateCache<KeyCode>>) { fn clear_keyboard_state(mut cache: ResMut<InputStateCache<KeyCode>>) {
cache.clear(); cache.clear();
} }
@@ -182,14 +161,12 @@ fn cache_gamepad_state(mut gamepads: Query<(&Gamepad, &mut InputStateCache<Gamep
} }
} }
#[cfg(feature = "client")]
fn clear_gamepad_state(mut caches: Query<&mut InputStateCache<GamepadButton>>) { fn clear_gamepad_state(mut caches: Query<&mut InputStateCache<GamepadButton>>) {
for mut cache in caches.iter_mut() { for mut cache in caches.iter_mut() {
cache.clear(); cache.clear();
} }
} }
#[cfg(feature = "client")]
/// Take keyboard and gamepad state and combine them into unified input state /// Take keyboard and gamepad state and combine them into unified input state
fn combine_controls(controls: Res<Controls>, mut combined_controls: ResMut<ControlState>) { fn combine_controls(controls: Res<Controls>, mut combined_controls: ResMut<ControlState>) {
let keyboard = controls.keyboard_state; let keyboard = controls.keyboard_state;
@@ -210,7 +187,6 @@ fn combine_controls(controls: Res<Controls>, mut combined_controls: ResMut<Contr
combined_controls.cash_heal = gamepad.cash_heal | keyboard.cash_heal; combined_controls.cash_heal = gamepad.cash_heal | keyboard.cash_heal;
} }
#[cfg(feature = "client")]
/// Applies a square deadzone to a Vec2 /// Applies a square deadzone to a Vec2
fn deadzone_square(v: Vec2, min: f32) -> Vec2 { fn deadzone_square(v: Vec2, min: f32) -> Vec2 {
Vec2::new( Vec2::new(
@@ -219,7 +195,6 @@ fn deadzone_square(v: Vec2, min: f32) -> Vec2 {
) )
} }
#[cfg(feature = "client")]
/// Collect gamepad inputs /// Collect gamepad inputs
fn gamepad_controls( fn gamepad_controls(
gamepads: Query<(Entity, &Gamepad, &InputStateCache<GamepadButton>)>, gamepads: Query<(Entity, &Gamepad, &InputStateCache<GamepadButton>)>,
@@ -282,7 +257,6 @@ fn gamepad_controls(
} }
} }
#[cfg(feature = "client")]
/// Collect mouse movement input /// Collect mouse movement input
fn mouse_rotate(mut mouse: EventReader<MouseMotion>, mut controls: ResMut<Controls>) { fn mouse_rotate(mut mouse: EventReader<MouseMotion>, mut controls: ResMut<Controls>) {
controls.keyboard_state.look_dir = Vec2::ZERO; controls.keyboard_state.look_dir = Vec2::ZERO;
@@ -292,7 +266,6 @@ fn mouse_rotate(mut mouse: EventReader<MouseMotion>, mut controls: ResMut<Contro
} }
} }
#[cfg(feature = "client")]
/// Collect keyboard input /// Collect keyboard input
fn keyboard_controls( fn keyboard_controls(
keyboard: Res<ButtonInput<KeyCode>>, keyboard: Res<ButtonInput<KeyCode>>,
@@ -325,7 +298,6 @@ fn keyboard_controls(
controls.keyboard_state.cash_heal = cache.just_pressed(KeyCode::Enter); controls.keyboard_state.cash_heal = cache.just_pressed(KeyCode::Enter);
} }
#[cfg(feature = "client")]
/// Collect mouse button input when pressed /// Collect mouse button input when pressed
fn mouse_click(mut events: EventReader<MouseButtonInput>, mut controls: ResMut<Controls>) { fn mouse_click(mut events: EventReader<MouseButtonInput>, mut controls: ResMut<Controls>) {
controls.keyboard_state.just_triggered = false; controls.keyboard_state.just_triggered = false;
@@ -352,7 +324,6 @@ fn mouse_click(mut events: EventReader<MouseButtonInput>, mut controls: ResMut<C
} }
} }
#[cfg(feature = "client")]
/// Receive gamepad connections and disconnections /// Receive gamepad connections and disconnections
fn gamepad_connections(mut evr_gamepad: EventReader<GamepadEvent>) { fn gamepad_connections(mut evr_gamepad: EventReader<GamepadEvent>) {
for ev in evr_gamepad.read() { for ev in evr_gamepad.read() {

View File

@@ -0,0 +1,28 @@
use crate::GameState;
use bevy::prelude::*;
use shared::control::{ControlState, ControllerSet};
pub mod controls;
#[derive(Resource, Debug, Default)]
struct Controls {
keyboard_state: ControlState,
gamepad_state: Option<ControlState>,
}
#[derive(Resource, Debug, PartialEq, Eq)]
pub enum CharacterInputEnabled {
On,
Off,
}
pub fn plugin(app: &mut App) {
app.insert_resource(CharacterInputEnabled::On);
app.add_plugins(controls::plugin);
app.configure_sets(
FixedPreUpdate,
ControllerSet::CollectInputs.run_if(in_state(GameState::Playing)),
);
}

View File

@@ -1,5 +1,6 @@
mod backpack; mod backpack;
mod client; mod client;
mod control;
mod debug; mod debug;
mod enemy; mod enemy;
mod heal_effect; mod heal_effect;
@@ -124,6 +125,7 @@ fn main() {
app.add_plugins(backpack::plugin); app.add_plugins(backpack::plugin);
app.add_plugins(client::plugin); app.add_plugins(client::plugin);
app.add_plugins(control::plugin);
app.add_plugins(debug::plugin); app.add_plugins(debug::plugin);
app.add_plugins(enemy::plugin); app.add_plugins(enemy::plugin);
app.add_plugins(heal_effect::plugin); app.add_plugins(heal_effect::plugin);

View File

@@ -1,6 +1,6 @@
use crate::GameState; use crate::{GameState, control::CharacterInputEnabled};
use bevy::{color::palettes::css::BLACK, prelude::*}; use bevy::{color::palettes::css::BLACK, prelude::*};
use shared::{HEDZ_GREEN, HEDZ_PURPLE, control::CharacterInputEnabled, loading_assets::UIAssets}; use shared::{HEDZ_GREEN, HEDZ_PURPLE, loading_assets::UIAssets};
#[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)] #[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)]
#[states(scoped_entities)] #[states(scoped_entities)]

View File

@@ -3,7 +3,7 @@ use crate::{
GameState, GameState,
abilities::TriggerStateRes, abilities::TriggerStateRes,
animation::AnimationFlags, animation::AnimationFlags,
control::{ControlState, SelectedController, controls::ControllerSettings}, control::{ControlState, ControllerSettings, SelectedController},
head::ActiveHead, head::ActiveHead,
heads_database::{HeadControls, HeadsDatabase}, heads_database::{HeadControls, HeadsDatabase},
physics_layers::GameLayer, physics_layers::GameLayer,

View File

@@ -2,7 +2,7 @@ use super::{ControlState, ControllerSet};
use crate::{ use crate::{
GameState, GameState,
animation::AnimationFlags, animation::AnimationFlags,
control::{controller_common::MovementSpeedFactor, controls::ControllerSettings}, control::{ControllerSettings, controller_common::MovementSpeedFactor},
player::PlayerBodyMesh, player::PlayerBodyMesh,
}; };
use bevy::prelude::*; use bevy::prelude::*;

View File

@@ -1,25 +1,60 @@
use bevy::{ecs::entity::MapEntities, prelude::*};
use serde::{Deserialize, Serialize};
use crate::{ use crate::{
GameState, GameState,
head::ActiveHead, head::ActiveHead,
heads_database::{HeadControls, HeadsDatabase}, heads_database::{HeadControls, HeadsDatabase},
player::Player, player::Player,
}; };
use bevy::{ecs::entity::MapEntities, prelude::*};
use serde::{Deserialize, Serialize};
pub mod controller_common; pub mod controller_common;
pub mod controller_flying; pub mod controller_flying;
pub mod controller_running; pub mod controller_running;
pub mod controls;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone, Default)] #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone, Default)]
enum ControllerSet { pub enum ControllerSet {
CollectInputs, CollectInputs,
ApplyControlsFly, ApplyControlsFly,
#[default] #[default]
ApplyControlsRun, ApplyControlsRun,
} }
#[derive(Event)]
pub struct ControllerSwitchEvent;
#[derive(Resource, Debug, Default, PartialEq)]
pub struct SelectedController(pub ControllerSet);
pub fn plugin(app: &mut App) {
app.register_type::<ControllerSettings>();
app.init_resource::<SelectedController>();
app.init_resource::<ControlState>();
app.add_event::<ControllerSwitchEvent>();
app.add_plugins(controller_common::plugin);
app.add_plugins(controller_flying::CharacterControllerPlugin);
app.add_plugins(controller_running::CharacterControllerPlugin);
app.configure_sets(
FixedUpdate,
(
ControllerSet::ApplyControlsFly.run_if(resource_equals(SelectedController(
ControllerSet::ApplyControlsFly,
))),
ControllerSet::ApplyControlsRun.run_if(resource_equals(SelectedController(
ControllerSet::ApplyControlsRun,
))),
)
.chain()
.run_if(in_state(GameState::Playing)),
);
app.add_systems(Update, head_change.run_if(in_state(GameState::Playing)));
}
#[derive(Resource, Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, Reflect)] #[derive(Resource, Debug, Clone, Copy, Default, PartialEq, Serialize, Deserialize, Reflect)]
pub struct ControlState { pub struct ControlState {
/// Movement direction with a maximum length of 1.0 /// Movement direction with a maximum length of 1.0
@@ -43,57 +78,11 @@ impl MapEntities for ControlState {
fn map_entities<E: EntityMapper>(&mut self, _entity_mapper: &mut E) {} fn map_entities<E: EntityMapper>(&mut self, _entity_mapper: &mut E) {}
} }
#[derive(Resource, Debug, Default)] #[derive(Component, Clone, PartialEq, Reflect, Serialize, Deserialize)]
struct Controls { #[reflect(Component)]
#[cfg(feature = "client")] pub struct ControllerSettings {
keyboard_state: ControlState, pub deceleration_factor: f32,
#[cfg(feature = "client")] pub jump_force: f32,
gamepad_state: Option<ControlState>,
}
#[derive(Resource, Debug, PartialEq, Eq)]
pub enum CharacterInputEnabled {
On,
Off,
}
#[derive(Event)]
pub struct ControllerSwitchEvent;
#[derive(Resource, Debug, Default, PartialEq)]
pub struct SelectedController(ControllerSet);
pub fn plugin(app: &mut App) {
app.init_resource::<SelectedController>();
app.init_resource::<ControlState>();
app.insert_resource(CharacterInputEnabled::On);
app.add_plugins(controls::plugin);
app.add_plugins(controller_common::plugin);
app.add_plugins(controller_flying::CharacterControllerPlugin);
app.add_plugins(controller_running::CharacterControllerPlugin);
app.add_event::<ControllerSwitchEvent>();
app.configure_sets(
FixedPreUpdate,
ControllerSet::CollectInputs.run_if(in_state(GameState::Playing)),
)
.configure_sets(
FixedUpdate,
(
ControllerSet::ApplyControlsFly.run_if(resource_equals(SelectedController(
ControllerSet::ApplyControlsFly,
))),
ControllerSet::ApplyControlsRun.run_if(resource_equals(SelectedController(
ControllerSet::ApplyControlsRun,
))),
)
.chain()
.run_if(in_state(GameState::Playing)),
);
app.add_systems(Update, head_change.run_if(in_state(GameState::Playing)));
} }
fn head_change( fn head_change(

View File

@@ -12,9 +12,8 @@ use crate::{
cash::CashResource, cash::CashResource,
character::{self, AnimatedCharacter}, character::{self, AnimatedCharacter},
control::{ control::{
ControlState, ControlState, ControllerSettings,
controller_common::{MovementSpeedFactor, PlayerCharacterController}, controller_common::{MovementSpeedFactor, PlayerCharacterController},
controls::ControllerSettings,
}, },
cutscene::StartCutscene, cutscene::StartCutscene,
global_observer, global_observer,