valence_server/
movement.rs

1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3use valence_entity::{HeadYaw, Look, OnGround, Position};
4use valence_math::DVec3;
5use valence_protocol::packets::play::{
6    FullC2s, LookAndOnGroundC2s, OnGroundOnlyC2s, PositionAndOnGroundC2s, VehicleMoveC2s,
7};
8
9use crate::event_loop::{EventLoopPreUpdate, PacketEvent};
10use crate::teleport::TeleportState;
11
12pub struct MovementPlugin;
13
14impl Plugin for MovementPlugin {
15    fn build(&self, app: &mut App) {
16        app.init_resource::<MovementSettings>()
17            .add_event::<MovementEvent>()
18            .add_systems(EventLoopPreUpdate, handle_client_movement);
19    }
20}
21
22/// Configuration resource for client movement checks.
23#[derive(Resource, Default)]
24pub struct MovementSettings; // TODO
25
26/// Event sent when a client successfully moves.
27#[derive(Event, Clone, Debug)]
28pub struct MovementEvent {
29    pub client: Entity,
30    pub position: DVec3,
31    pub old_position: DVec3,
32    pub look: Look,
33    pub old_look: Look,
34    pub on_ground: bool,
35    pub old_on_ground: bool,
36}
37
38fn handle_client_movement(
39    mut packets: EventReader<PacketEvent>,
40    mut clients: Query<(
41        &mut Position,
42        &mut Look,
43        &mut HeadYaw,
44        &mut OnGround,
45        &mut TeleportState,
46    )>,
47    mut movement_events: EventWriter<MovementEvent>,
48) {
49    for packet in packets.read() {
50        if let Some(pkt) = packet.decode::<PositionAndOnGroundC2s>() {
51            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
52                clients.get_mut(packet.client)
53            {
54                let mov = MovementEvent {
55                    client: packet.client,
56                    position: pkt.position,
57                    old_position: pos.0,
58                    look: *look,
59                    old_look: *look,
60                    on_ground: pkt.on_ground,
61                    old_on_ground: on_ground.0,
62                };
63
64                handle(
65                    mov,
66                    pos,
67                    look,
68                    head_yaw,
69                    on_ground,
70                    teleport_state,
71                    &mut movement_events,
72                );
73            }
74        } else if let Some(pkt) = packet.decode::<FullC2s>() {
75            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
76                clients.get_mut(packet.client)
77            {
78                let mov = MovementEvent {
79                    client: packet.client,
80                    position: pkt.position,
81                    old_position: pos.0,
82                    look: Look {
83                        yaw: pkt.yaw,
84                        pitch: pkt.pitch,
85                    },
86                    old_look: *look,
87                    on_ground: pkt.on_ground,
88                    old_on_ground: on_ground.0,
89                };
90
91                handle(
92                    mov,
93                    pos,
94                    look,
95                    head_yaw,
96                    on_ground,
97                    teleport_state,
98                    &mut movement_events,
99                );
100            }
101        } else if let Some(pkt) = packet.decode::<LookAndOnGroundC2s>() {
102            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
103                clients.get_mut(packet.client)
104            {
105                let mov = MovementEvent {
106                    client: packet.client,
107                    position: pos.0,
108                    old_position: pos.0,
109                    look: Look {
110                        yaw: pkt.yaw,
111                        pitch: pkt.pitch,
112                    },
113                    old_look: *look,
114                    on_ground: pkt.on_ground,
115                    old_on_ground: on_ground.0,
116                };
117
118                handle(
119                    mov,
120                    pos,
121                    look,
122                    head_yaw,
123                    on_ground,
124                    teleport_state,
125                    &mut movement_events,
126                );
127            }
128        } else if let Some(pkt) = packet.decode::<OnGroundOnlyC2s>() {
129            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
130                clients.get_mut(packet.client)
131            {
132                let mov = MovementEvent {
133                    client: packet.client,
134                    position: pos.0,
135                    old_position: pos.0,
136                    look: *look,
137                    old_look: *look,
138                    on_ground: pkt.on_ground,
139                    old_on_ground: on_ground.0,
140                };
141
142                handle(
143                    mov,
144                    pos,
145                    look,
146                    head_yaw,
147                    on_ground,
148                    teleport_state,
149                    &mut movement_events,
150                );
151            }
152        } else if let Some(pkt) = packet.decode::<VehicleMoveC2s>() {
153            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
154                clients.get_mut(packet.client)
155            {
156                let mov = MovementEvent {
157                    client: packet.client,
158                    position: pkt.position,
159                    old_position: pos.0,
160                    look: Look {
161                        yaw: pkt.yaw,
162                        pitch: pkt.pitch,
163                    },
164                    old_look: *look,
165                    on_ground: on_ground.0,
166                    old_on_ground: on_ground.0,
167                };
168
169                handle(
170                    mov,
171                    pos,
172                    look,
173                    head_yaw,
174                    on_ground,
175                    teleport_state,
176                    &mut movement_events,
177                );
178            }
179        }
180    }
181}
182
183fn handle(
184    mov: MovementEvent,
185    mut pos: Mut<Position>,
186    mut look: Mut<Look>,
187    mut head_yaw: Mut<HeadYaw>,
188    mut on_ground: Mut<OnGround>,
189    mut teleport_state: Mut<TeleportState>,
190    movement_events: &mut EventWriter<MovementEvent>,
191) {
192    if teleport_state.pending_teleports() != 0 {
193        return;
194    }
195
196    // TODO: check that the client isn't moving too fast / flying.
197    // TODO: check that the client isn't clipping through blocks.
198
199    pos.set_if_neq(Position(mov.position));
200    teleport_state.synced_pos = mov.position;
201    look.set_if_neq(mov.look);
202    teleport_state.synced_look = mov.look;
203    head_yaw.set_if_neq(HeadYaw(mov.look.yaw));
204    on_ground.set_if_neq(OnGround(mov.on_ground));
205
206    movement_events.send(mov);
207}