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, PacketEvent};
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_event::<MovementEvent>()
19 .add_systems(EventLoopPreUpdate, handle_client_movement);
20 }
21}
22
23#[derive(Resource, Default)]
25pub struct MovementSettings; #[derive(Event, Clone, Debug)]
29pub struct MovementEvent {
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: EventReader<PacketEvent>,
41 mut clients: Query<(
42 &mut Position,
43 &mut Look,
44 &mut HeadYaw,
45 &mut OnGround,
46 &mut TeleportState,
47 )>,
48 mut movement_events: EventWriter<MovementEvent>,
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 = MovementEvent {
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_events,
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 = MovementEvent {
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_events,
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 = MovementEvent {
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_events,
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 = MovementEvent {
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_events,
151 );
152 }
153 } else if let Some(pkt) = packet.decode::<MoveVehicleC2s>() {
154 if let Ok((pos, look, head_yaw, on_ground, teleport_state)) =
155 clients.get_mut(packet.client)
156 {
157 let mov = MovementEvent {
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_events,
178 );
179 }
180 }
181 }
182}
183
184fn handle(
185 mov: MovementEvent,
186 mut pos: Mut<Position>,
187 mut look: Mut<Look>,
188 mut head_yaw: Mut<HeadYaw>,
189 mut on_ground: Mut<OnGround>,
190 mut teleport_state: Mut<TeleportState>,
191 movement_events: &mut EventWriter<MovementEvent>,
192) {
193 if teleport_state.pending_teleports() != 0 {
194 return;
195 }
196
197 pos.set_if_neq(Position(mov.position));
201 teleport_state.synced_pos = mov.position;
202 look.set_if_neq(mov.look);
203 teleport_state.synced_look = mov.look;
204 head_yaw.set_if_neq(HeadYaw(mov.look.yaw));
205 on_ground.set_if_neq(OnGround(mov.on_ground));
206
207 movement_events.send(mov);
208}