Skip to content

Commit 7e1d925

Browse files
zicklagTekhnaeRaav
andauthored
Input refactor new (#516)
Co-authored-by: Tekhnae Raav <tekhnaeraav@katharostech.com>
1 parent a953027 commit 7e1d925

File tree

5 files changed

+95
-144
lines changed

5 files changed

+95
-144
lines changed

framework_crates/bones_framework/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ once_cell = "1.17"
103103
thiserror = "1.0"
104104
gilrs = "0.11.0"
105105
send_wrapper = "0.6.0"
106+
numquant = "0.2"
106107

107108

108109
# Tracing
@@ -147,7 +148,6 @@ ggrs = { git = "https://github.com/MaxCWhitehead/ggrs.git", rev = "96499377407ce
147148
bones_matchmaker_proto = { version = "0.4.0", path = "../../other_crates/bones_matchmaker_proto" }
148149
bytes = "1.4"
149150
mdns-sd = { version = "0.10", default-features = false }
150-
numquant = "0.2"
151151
ping-rs = "0.1"
152152
postcard = { version = "1.0", features = ["alloc"] }
153153
rcgen = "0.12"

framework_crates/bones_framework/src/input.rs

Lines changed: 73 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod gamepad;
77
pub mod gilrs;
88
pub mod keyboard;
99
pub mod mouse;
10+
pub mod proto;
1011
pub mod window;
1112

1213
/// The state of a button, ether pressed or released.
@@ -29,8 +30,10 @@ impl ButtonState {
2930

3031
/// Module prelude.
3132
pub mod prelude {
32-
pub use super::{gamepad::*, keyboard::*, mouse::*, window::*, ButtonState};
33-
pub use crate::input::{InputCollector, PlayerControls};
33+
pub use super::{gamepad::*, keyboard::*, mouse::*, proto, window::*, ButtonState};
34+
pub use crate::input::{
35+
Controls, DenseControl, DenseInput, DenseInputCollector, DenseInputConfig, InputCollector,
36+
};
3437
}
3538

3639
/// Maps raw inputs to game controls and exposes controls for respective player and their control source.
@@ -40,11 +43,7 @@ pub mod prelude {
4043
/// [`InputCollector::update_just_pressed`] computes any changes in pressed buttons that may be stored on control.
4144
///
4245
/// [`InputCollector::advance_frame`] is used to mark that the input has been consumed, and update the prev frame inputs to current, to compute changes next frame.
43-
///
44-
/// Generic type param ControlMapping is HasSchema because it is expected to be a Resource retrievable on world.
45-
pub trait InputCollector<'a, ControlMapping: HasSchema, ControlSource, Control>:
46-
Send + Sync
47-
{
46+
pub trait InputCollector<'a, Control>: Send + Sync {
4847
/// Update the internal state with new inputs. This must be called every render frame with the
4948
/// input events. This updates which buttons are pressed, but does not compute what buttons were "just_pressed".
5049
/// use [`InputCollector::update_just_pressed`] to do this.
@@ -62,30 +61,80 @@ pub trait InputCollector<'a, ControlMapping: HasSchema, ControlSource, Control>:
6261
/// This does not modify previous frame's input, to do this use [`InputCollector::advance_frame`].
6362
fn update_just_pressed(&mut self);
6463

65-
/// Get control for player based on provided `ControlSource`.
66-
fn get_control(&self, player_idx: usize, control_source: ControlSource) -> &Control;
64+
/// Get control for player.
65+
fn get_control(&self) -> &Control;
6766
}
6867

6968
/// Trait that tracks player control state. Provides associated types for other input trait implementations.
70-
pub trait PlayerControls<'a, Control> {
71-
/// InputCollector used to update controls.
72-
type InputCollector: InputCollector<'a, Self::ControlMapping, Self::ControlSource, Control>;
69+
pub trait Controls<'a, Control> {
70+
/// Get control for player.
71+
fn get_control(&self, player_idx: usize) -> &Control;
7372

74-
/// Control mapping from raw input, expected to be able to be retrieved as `Resource` from world.
75-
type ControlMapping: HasSchema;
73+
/// Get mutable control for player.
74+
fn get_control_mut(&mut self, player_idx: usize) -> &mut Control;
75+
}
7676

77-
/// Type used to map source of input to control.
78-
type ControlSource;
77+
use std::fmt::Debug;
7978

80-
/// Update control state from input collector.
81-
fn update_controls(&mut self, collector: &mut Self::InputCollector);
79+
/// Dense input for network replication.
80+
pub trait DenseInput:
81+
bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
82+
{
83+
}
8284

83-
/// Get `ControlSource` for player (only present for local player).
84-
fn get_control_source(&self, local_player_idx: usize) -> Option<Self::ControlSource>;
85+
/// Automatic implementation for `DenseInput`.
86+
impl<T> DenseInput for T where
87+
T: bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
88+
{
89+
}
8590

86-
/// Get control for player.
87-
fn get_control(&self, player_idx: usize) -> &Control;
91+
/// Define input types used by game for use in networking.
92+
///
93+
/// As long as types `Controls` and `InputCollector` implement traits [`Controls`] and [`InputCollector`],
94+
/// trait bounds [`DenseControl`] and [`DenseInputCollector`] are automatically implemented.
95+
#[allow(missing_docs)]
96+
pub trait DenseInputConfig<'a> {
97+
type Dense: DenseInput + Debug + Default;
98+
type Control: DenseControl<Self::Dense>;
99+
100+
// Must be HasSchema because expected to be retrieved from `World` as `Resource`.
101+
type Controls: Controls<'a, Self::Control> + HasSchema;
102+
103+
// InputCollector type params must match that of Controls, so using associated types.
104+
type InputCollector: InputCollector<'a, Self::Control> + Default;
105+
}
88106

89-
/// Get mutable control for player.
90-
fn get_control_mut(&mut self, player_idx: usize) -> &mut Control;
107+
/// Trait allowing for creating and applying [`DenseInput`] from control.
108+
pub trait DenseControl<Dense: DenseInput>: Send + Sync + Default {
109+
/// Get [`DenseInput`] for control.
110+
fn get_dense_input(&self) -> Dense;
111+
112+
/// Update control from [`DenseInput`].
113+
fn update_from_dense(&mut self, new_control: &Dense);
114+
}
115+
116+
/// Extension of [`InputCollector`] exposing dense control for networking.
117+
///
118+
/// This trait is automatically implemented for [`InputCollector`]'s such that `Control`
119+
/// implements [`DenseControl`] (i.e. implements dense input)
120+
pub trait DenseInputCollector<'a, Dense, Control>: InputCollector<'a, Control>
121+
where
122+
Dense: DenseInput,
123+
Control: DenseControl<Dense>,
124+
{
125+
/// Get dense control
126+
fn get_dense_control(&self) -> Dense;
127+
}
128+
129+
/// Provide automatic [`DenseInputCollector`] for [`InputCollector`] when type parameters
130+
/// meet required bounds for networking.
131+
impl<'a, T, Dense, Control> DenseInputCollector<'a, Dense, Control> for T
132+
where
133+
Dense: DenseInput,
134+
Control: DenseControl<Dense>,
135+
T: InputCollector<'a, Control>,
136+
{
137+
fn get_dense_control(&self) -> Dense {
138+
self.get_control().get_dense_input()
139+
}
91140
}

framework_crates/bones_framework/src/networking/proto.rs renamed to framework_crates/bones_framework/src/input/proto.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use numquant::{IntRange, Quantized};
66
use crate::prelude::*;
77

88
/// A newtype around [`Vec2`] that implements [`From<u16>`] and [`Into<u16>`] as a way to compress
9-
/// user stick input for use in [`self::input::DenseInput`].
9+
/// user stick input for use in [`crate::input::DenseInput`].
1010
#[derive(Debug, Deref, DerefMut, Default)]
1111
pub struct DenseMoveDirection(pub Vec2);
1212

framework_crates/bones_framework/src/networking.rs

Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#![doc = include_str!("./networking.md")]
22

3-
use self::{
4-
input::{DenseInput, NetworkInputConfig, NetworkPlayerControl, NetworkPlayerControls},
5-
socket::Socket,
6-
};
3+
use self::{input::NetworkControls, socket::Socket};
4+
use crate::input::{DenseControl, DenseInput, DenseInputConfig};
75
use crate::networking::online::OnlineMatchmakerResponse;
86
pub use crate::networking::random::RngGenerator;
97
use crate::prelude::*;
@@ -20,16 +18,13 @@ use {
2018
ggrs::{NetworkStats, PlayerHandle},
2119
};
2220

23-
use crate::input::PlayerControls as PlayerControlsTrait;
24-
2521
pub use iroh;
2622

2723
pub mod input;
2824
pub mod lan;
2925
pub mod online;
3026
pub mod online_lobby;
3127
pub mod online_matchmaking;
32-
pub mod proto;
3328
pub mod random;
3429
pub mod socket;
3530

@@ -64,7 +59,7 @@ impl From<ggrs::InputStatus> for NetworkInputStatus {
6459
/// Module prelude.
6560
pub mod prelude {
6661
pub use super::{
67-
input, lan, online, proto, random, DisconnectedPlayers, RngGenerator, SyncingInfo, RUNTIME,
62+
input, lan, online, random, DisconnectedPlayers, RngGenerator, SyncingInfo, RUNTIME,
6863
};
6964

7065
#[cfg(feature = "net-debug")]
@@ -449,7 +444,7 @@ pub struct DisconnectedPlayers {
449444
/// [`SessionRunner`] implementation that uses [`ggrs`] for network play.
450445
///
451446
/// This is where the whole `ggrs` integration is implemented.
452-
pub struct GgrsSessionRunner<'a, InputTypes: NetworkInputConfig<'a>> {
447+
pub struct GgrsSessionRunner<'a, InputTypes: DenseInputConfig<'a>> {
453448
/// The last player input we detected.
454449
pub last_player_input: InputTypes::Dense,
455450

@@ -540,7 +535,7 @@ impl GgrsSessionRunnerInfo {
540535

541536
impl<'a, InputTypes> GgrsSessionRunner<'a, InputTypes>
542537
where
543-
InputTypes: NetworkInputConfig<'a>,
538+
InputTypes: DenseInputConfig<'a>,
544539
{
545540
/// Creates a new session runner from a `OnlineMatchmakerResponse::GameStarting`
546541
/// Any input values set as `None` will be set to default.
@@ -647,7 +642,7 @@ where
647642

648643
impl<InputTypes> SessionRunner for GgrsSessionRunner<'static, InputTypes>
649644
where
650-
InputTypes: NetworkInputConfig<'static> + 'static,
645+
InputTypes: DenseInputConfig<'static> + 'static,
651646
{
652647
fn step(&mut self, frame_start: Instant, world: &mut World, stages: &mut SystemStages) {
653648
let step: f64 = 1.0 / self.network_fps;
@@ -658,26 +653,12 @@ where
658653

659654
let mut skip_frames: u32 = 0;
660655

661-
{
662-
let player_inputs = world.resource::<InputTypes::PlayerControls>();
663-
664-
// Collect inputs and update controls
665-
self.input_collector.apply_inputs(world);
666-
self.input_collector.update_just_pressed();
667-
668-
// save local players dense input for use with ggrs
669-
match player_inputs.get_control_source(self.local_player_idx as usize) {
670-
Some(control_source) => {
671-
let control = self
672-
.input_collector
673-
.get_control(self.local_player_idx as usize, control_source);
674-
675-
self.last_player_input = control.get_dense_input();
676-
},
677-
None => warn!("GgrsSessionRunner local_player_idx {} has no control source, no local input provided.",
678-
self.local_player_idx)
679-
};
680-
}
656+
// Collect inputs and update controls
657+
self.input_collector.apply_inputs(world);
658+
self.input_collector.update_just_pressed();
659+
660+
// save local players dense input for use with ggrs
661+
self.last_player_input = self.input_collector.get_control().get_dense_input();
681662

682663
#[cfg(feature = "net-debug")]
683664
// Current frame before we start network update loop
@@ -862,7 +843,7 @@ where
862843

863844
// update game controls from ggrs inputs
864845
let mut player_inputs =
865-
world.resource_mut::<InputTypes::PlayerControls>();
846+
world.resource_mut::<InputTypes::Controls>();
866847
for (player_idx, (input, status)) in
867848
network_inputs.into_iter().enumerate()
868849
{
Lines changed: 7 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,12 @@
11
//! Input traits required by networking. These traits are networking specific, either only used in networking,
22
//! or extending other traits from [`crate::input`] for networking.
33
4-
use std::fmt::Debug;
5-
6-
use bones_schema::HasSchema;
7-
8-
use crate::input::{InputCollector, PlayerControls};
4+
use crate::input::{Controls, DenseControl, DenseInput};
95

106
use super::NetworkInputStatus;
117

12-
/// Define input types used by game for use in networking.
13-
///
14-
/// As long as types `PlayerControls` and `InputCollector` implement traits [`PlayerControls`] and [`InputCollector`],
15-
/// trait bounds [`NetworkPlayerControl`] and [`NetworkInputCollector`] are automatically implemented.
16-
#[allow(missing_docs)]
17-
pub trait NetworkInputConfig<'a> {
18-
type Dense: DenseInput + Debug + Default;
19-
type Control: NetworkPlayerControl<Self::Dense>;
20-
21-
// Must be HasSchema because expected to be retrieved from `World` as `Resource`.
22-
type PlayerControls: PlayerControls<'a, Self::Control> + HasSchema;
23-
24-
// InputCollector type params must match that of PlayerControls, so using associated types.
25-
type InputCollector: InputCollector<
26-
'a,
27-
<Self::PlayerControls as PlayerControls<'a, Self::Control>>::ControlMapping,
28-
<Self::PlayerControls as PlayerControls<'a, Self::Control>>::ControlSource,
29-
Self::Control,
30-
> + Default;
31-
}
32-
33-
/// Required for use of [`PlayerControls`] in networking.
34-
pub trait NetworkPlayerControls<'a, Dense: DenseInput, Control>:
35-
PlayerControls<'a, Control>
36-
{
8+
/// Required for use of [`Controls`] in networking.
9+
pub trait NetworkControls<'a, Dense: DenseInput, Control>: Controls<'a, Control> {
3710
/// Update control of player from dense input.
3811
///
3912
/// [`NetworkInputStatus`] communicates if input is confirmed, predicted, or from disconnected player.
@@ -48,13 +21,13 @@ pub trait NetworkPlayerControls<'a, Dense: DenseInput, Control>:
4821
fn get_dense_control(&self, player_idx: usize) -> Dense;
4922
}
5023

51-
impl<'a, T, Dense, Control> NetworkPlayerControls<'a, Dense, Control> for T
24+
impl<'a, T, Dense, Control> NetworkControls<'a, Dense, Control> for T
5225
where
5326
Dense: DenseInput,
54-
Control: NetworkPlayerControl<Dense>,
55-
T: PlayerControls<'a, Control>,
27+
Control: DenseControl<Dense>,
28+
T: Controls<'a, Control>,
5629
{
57-
// type NetworkControl = PlayerControl;
30+
// type NetworkControl = Control;
5831
fn network_update(
5932
&mut self,
6033
player_idx: usize,
@@ -69,55 +42,3 @@ where
6942
self.get_control(player_idx).get_dense_input()
7043
}
7144
}
72-
73-
/// Dense input for network replication.
74-
pub trait DenseInput:
75-
bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
76-
{
77-
}
78-
79-
/// Automatic implementation for `DenseInput`.
80-
impl<T> DenseInput for T where
81-
T: bytemuck::Pod + bytemuck::Zeroable + Copy + Clone + PartialEq + Eq + Send + Sync
82-
{
83-
}
84-
85-
/// Trait allowing for creating and applying [`DenseInput`] from control.
86-
pub trait NetworkPlayerControl<Dense: DenseInput>: Send + Sync + Default {
87-
/// Get [`DenseInput`] for control.
88-
fn get_dense_input(&self) -> Dense;
89-
90-
/// Update control from [`DenseInput`].
91-
fn update_from_dense(&mut self, new_control: &Dense);
92-
}
93-
94-
/// Extension of [`InputCollector`] exposing dense control for networking.
95-
///
96-
/// This trait is automatically implemented for [`InputCollector`]'s such that `Control`
97-
/// implements [`NetworkPlayerControl`] (i.e. implements dense input)
98-
pub trait NetworkInputCollector<'a, Dense, ControlMapping, ControlSource, Control>:
99-
InputCollector<'a, ControlMapping, ControlSource, Control>
100-
where
101-
Dense: DenseInput,
102-
ControlMapping: HasSchema,
103-
Control: NetworkPlayerControl<Dense>,
104-
{
105-
/// Get dense control
106-
fn get_dense_control(&self, player_idx: usize, control_soure: ControlSource) -> Dense;
107-
}
108-
109-
/// Provide automatic [`NetworkInputCollector`] for [`InputCollector`] when type parameters
110-
/// meet required bounds for networking.
111-
impl<'a, T, Dense, ControlMapping, ControlSource, Control>
112-
NetworkInputCollector<'a, Dense, ControlMapping, ControlSource, Control> for T
113-
where
114-
Dense: DenseInput,
115-
Control: NetworkPlayerControl<Dense>,
116-
ControlMapping: HasSchema,
117-
T: InputCollector<'a, ControlMapping, ControlSource, Control>,
118-
{
119-
fn get_dense_control(&self, player_idx: usize, control_source: ControlSource) -> Dense {
120-
self.get_control(player_idx, control_source)
121-
.get_dense_input()
122-
}
123-
}

0 commit comments

Comments
 (0)