Skip to main content

chunkedge_server/
movement.rs

1use bevy_app::prelude::*;
2use bevy_ecs::prelude::*;
3use chunkedge_entity::{HeadYaw, Look, OnGround, Position};
4use chunkedge_math::DVec3;
5use chunkedge_protocol::packets::play::{
6    MovePlayerPosC2s, MovePlayerPosRotC2s, MovePlayerRotC2s, MovePlayerStatusOnlyC2s,
7    MoveVehicleC2s,
8};
9
10use crate::event_loop::{EventLoopPreUpdate, PacketMessage};
11use crate::teleport::TeleportState;
12
13pub struct MovementPlugin;
14
15impl Plugin for MovementPlugin {
16    fn build(&self, app: &mut App) {
17        app.init_resource::<MovementSettings>()
18            .add_message::<MovementMessage>()
19            .add_systems(EventLoopPreUpdate, handle_client_movement);
20    }
21}
22
23/// Configuration resource for client movement checks.
24#[derive(Resource, Default)]
25pub struct MovementSettings; // TODO
26
27/// Message sent when a client successfully moves.
28#[derive(Message, Clone, Debug)]
29pub struct MovementMessage {
30    pub client: Entity,
31    pub position: DVec3,
32    pub old_position: DVec3,
33    pub look: Look,
34    pub old_look: Look,
35    pub on_ground: bool,
36    pub old_on_ground: bool,
37}
38
39fn handle_client_movement(
40    mut packets: MessageReader<PacketMessage>,
41    mut clients: Query<(
42        &mut Position,
43        &mut Look,
44        &mut HeadYaw,
45        &mut OnGround,
46        &mut TeleportState,
47    )>,
48    mut movement_messages: MessageWriter<MovementMessage>,
49) {
50    for packet in packets.read() {
51        if let Some(pkt) = packet.decode::<MovePlayerPosC2s>() {
52            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
53                clients.get_mut(packet.client)
54            {
55                let mov = MovementMessage {
56                    client: packet.client,
57                    position: pkt.position,
58                    old_position: pos.0,
59                    look: *look,
60                    old_look: *look,
61                    on_ground: pkt.flags.on_ground(),
62                    old_on_ground: on_ground.0,
63                };
64
65                handle(
66                    mov,
67                    pos,
68                    look,
69                    head_yaw,
70                    on_ground,
71                    teleport_state,
72                    &mut movement_messages,
73                );
74            }
75        } else if let Some(pkt) = packet.decode::<MovePlayerPosRotC2s>() {
76            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
77                clients.get_mut(packet.client)
78            {
79                let mov = MovementMessage {
80                    client: packet.client,
81                    position: pkt.position,
82                    old_position: pos.0,
83                    look: Look {
84                        yaw: pkt.yaw,
85                        pitch: pkt.pitch,
86                    },
87                    old_look: *look,
88                    on_ground: pkt.flags.on_ground(),
89                    old_on_ground: on_ground.0,
90                };
91
92                handle(
93                    mov,
94                    pos,
95                    look,
96                    head_yaw,
97                    on_ground,
98                    teleport_state,
99                    &mut movement_messages,
100                );
101            }
102        } else if let Some(pkt) = packet.decode::<MovePlayerRotC2s>() {
103            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
104                clients.get_mut(packet.client)
105            {
106                let mov = MovementMessage {
107                    client: packet.client,
108                    position: pos.0,
109                    old_position: pos.0,
110                    look: Look {
111                        yaw: pkt.yaw,
112                        pitch: pkt.pitch,
113                    },
114                    old_look: *look,
115                    on_ground: pkt.flags.on_ground(),
116                    old_on_ground: on_ground.0,
117                };
118
119                handle(
120                    mov,
121                    pos,
122                    look,
123                    head_yaw,
124                    on_ground,
125                    teleport_state,
126                    &mut movement_messages,
127                );
128            }
129        } else if let Some(pkt) = packet.decode::<MovePlayerStatusOnlyC2s>() {
130            if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
131                clients.get_mut(packet.client)
132            {
133                let mov = MovementMessage {
134                    client: packet.client,
135                    position: pos.0,
136                    old_position: pos.0,
137                    look: *look,
138                    old_look: *look,
139                    on_ground: pkt.flags.on_ground(),
140                    old_on_ground: on_ground.0,
141                };
142
143                handle(
144                    mov,
145                    pos,
146                    look,
147                    head_yaw,
148                    on_ground,
149                    teleport_state,
150                    &mut movement_messages,
151                );
152            }
153        } else if let Some(pkt) = packet.decode::<MoveVehicleC2s>()
154            && let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
155                clients.get_mut(packet.client)
156        {
157            let mov = MovementMessage {
158                client: packet.client,
159                position: pkt.position,
160                old_position: pos.0,
161                look: Look {
162                    yaw: pkt.yaw,
163                    pitch: pkt.pitch,
164                },
165                old_look: *look,
166                on_ground: on_ground.0,
167                old_on_ground: on_ground.0,
168            };
169
170            handle(
171                mov,
172                pos,
173                look,
174                head_yaw,
175                on_ground,
176                teleport_state,
177                &mut movement_messages,
178            );
179        }
180    }
181}
182
183fn handle(
184    mov: MovementMessage,
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_messages: &mut MessageWriter<MovementMessage>,
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_messages.write(mov);
207}