valence_server/
client_command.rs

1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3use valence_entity::entity::Flags;
4use valence_entity::{entity, Pose};
5pub use valence_protocol::packets::play::client_command_c2s::ClientCommand;
6use valence_protocol::packets::play::ClientCommandC2s;
7
8use crate::event_loop::{EventLoopPreUpdate, PacketEvent};
9
10pub struct ClientCommandPlugin;
11
12impl Plugin for ClientCommandPlugin {
13    fn build(&self, app: &mut App) {
14        app.add_event::<SprintEvent>()
15            .add_event::<SneakEvent>()
16            .add_event::<JumpWithHorseEvent>()
17            .add_event::<LeaveBedEvent>()
18            .add_systems(EventLoopPreUpdate, handle_client_command);
19    }
20}
21
22#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
23pub struct SprintEvent {
24    pub client: Entity,
25    pub state: SprintState,
26}
27
28#[derive(Copy, Clone, PartialEq, Eq, Debug)]
29pub enum SprintState {
30    Start,
31    Stop,
32}
33
34#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
35pub struct SneakEvent {
36    pub client: Entity,
37    pub state: SneakState,
38}
39
40#[derive(Copy, Clone, PartialEq, Eq, Debug)]
41pub enum SneakState {
42    Start,
43    Stop,
44}
45
46#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
47pub struct JumpWithHorseEvent {
48    pub client: Entity,
49    pub state: JumpWithHorseState,
50}
51
52#[derive(Copy, Clone, PartialEq, Eq, Debug)]
53pub enum JumpWithHorseState {
54    Start {
55        /// The power of the horse jump in `0..=100`.
56        power: u8,
57    },
58    Stop,
59}
60
61#[derive(Event, Copy, Clone, PartialEq, Eq, Debug)]
62pub struct LeaveBedEvent {
63    pub client: Entity,
64}
65
66fn handle_client_command(
67    mut packets: EventReader<PacketEvent>,
68    mut clients: Query<(&mut entity::Pose, &mut Flags)>,
69    mut sprinting_events: EventWriter<SprintEvent>,
70    mut sneaking_events: EventWriter<SneakEvent>,
71    mut jump_with_horse_events: EventWriter<JumpWithHorseEvent>,
72    mut leave_bed_events: EventWriter<LeaveBedEvent>,
73) {
74    for packet in packets.read() {
75        if let Some(pkt) = packet.decode::<ClientCommandC2s>() {
76            match pkt.action {
77                ClientCommand::StartSneaking => {
78                    if let Ok((mut pose, mut flags)) = clients.get_mut(packet.client) {
79                        pose.0 = Pose::Sneaking;
80                        flags.set_sneaking(true);
81                    }
82
83                    sneaking_events.send(SneakEvent {
84                        client: packet.client,
85                        state: SneakState::Start,
86                    });
87                }
88                ClientCommand::StopSneaking => {
89                    if let Ok((mut pose, mut flags)) = clients.get_mut(packet.client) {
90                        pose.0 = Pose::Standing;
91                        flags.set_sneaking(false);
92                    }
93
94                    sneaking_events.send(SneakEvent {
95                        client: packet.client,
96                        state: SneakState::Stop,
97                    });
98                }
99                ClientCommand::LeaveBed => {
100                    leave_bed_events.send(LeaveBedEvent {
101                        client: packet.client,
102                    });
103                }
104                ClientCommand::StartSprinting => {
105                    if let Ok((_, mut flags)) = clients.get_mut(packet.client) {
106                        flags.set_sprinting(true);
107                    }
108
109                    sprinting_events.send(SprintEvent {
110                        client: packet.client,
111                        state: SprintState::Start,
112                    });
113                }
114                ClientCommand::StopSprinting => {
115                    if let Ok((_, mut flags)) = clients.get_mut(packet.client) {
116                        flags.set_sprinting(false);
117                    }
118
119                    sprinting_events.send(SprintEvent {
120                        client: packet.client,
121                        state: SprintState::Stop,
122                    });
123                }
124                ClientCommand::StartJumpWithHorse => {
125                    jump_with_horse_events.send(JumpWithHorseEvent {
126                        client: packet.client,
127                        state: JumpWithHorseState::Start {
128                            power: pkt.jump_boost.0 as u8,
129                        },
130                    });
131                }
132                ClientCommand::StopJumpWithHorse => {
133                    jump_with_horse_events.send(JumpWithHorseEvent {
134                        client: packet.client,
135                        state: JumpWithHorseState::Stop,
136                    });
137                }
138                ClientCommand::OpenHorseInventory => {} // TODO
139                ClientCommand::StartFlyingWithElytra => {
140                    if let Ok((mut pose, _)) = clients.get_mut(packet.client) {
141                        pose.0 = Pose::FallFlying;
142                    }
143
144                    // TODO.
145                }
146            }
147        }
148    }
149}