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#[derive(Resource, Default)]
24pub struct MovementSettings; #[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 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}