1use crate::common::{Controls, EntityAction, MovePacket, Pose, Vec3};
5
6const POSITION_EPSILON_SQ: f64 = 9.0e-4;
8const POSITION_REFRESH_TICKS: u32 = 20;
10
11#[derive(Debug, Clone, Copy, Default, PartialEq)]
14pub struct MovementSender {
15 last_pos: Vec3,
16 last_yaw: f32,
17 last_pitch: f32,
18 ticks_since_pos: u32,
19 server_sprint: bool,
20 server_sneak: bool,
21 increment_first: bool,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq)]
28pub struct MoveStep {
29 pub sprint: Option<EntityAction>,
31 pub sneak: Option<EntityAction>,
33 pub packet: MovePacket,
35}
36
37impl MovementSender {
38 #[must_use]
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 #[must_use]
49 pub fn new_1_9() -> Self {
50 MovementSender {
51 increment_first: true,
52 ..Self::default()
53 }
54 }
55
56 #[must_use]
58 pub fn ticks_since_pos(&self) -> u32 {
59 self.ticks_since_pos
60 }
61
62 pub fn update(&mut self, pose: &Pose) -> MoveStep {
64 let sprint = (pose.sprinting != self.server_sprint).then(|| {
65 self.server_sprint = pose.sprinting;
66 if pose.sprinting {
67 EntityAction::StartSprinting
68 } else {
69 EntityAction::StopSprinting
70 }
71 });
72 let sneak = (pose.sneaking != self.server_sneak).then(|| {
73 self.server_sneak = pose.sneaking;
74 if pose.sneaking {
75 EntityAction::StartSneaking
76 } else {
77 EntityAction::StopSneaking
78 }
79 });
80 let dx = pose.pos.x - self.last_pos.x;
81 let dy = pose.pos.y - self.last_pos.y;
82 let dz = pose.pos.z - self.last_pos.z;
83 let turned = pose.yaw - self.last_yaw != 0.0 || pose.pitch - self.last_pitch != 0.0;
85 if self.increment_first {
86 self.ticks_since_pos += 1;
87 }
88 let moved = dx * dx + dy * dy + dz * dz > POSITION_EPSILON_SQ
89 || self.ticks_since_pos >= POSITION_REFRESH_TICKS;
90 let on_ground = pose.on_ground;
91 let packet = match (moved, turned) {
92 (true, true) => MovePacket::PositionLook {
93 pos: pose.pos,
94 yaw: pose.yaw,
95 pitch: pose.pitch,
96 on_ground,
97 },
98 (true, false) => MovePacket::Position {
99 pos: pose.pos,
100 on_ground,
101 },
102 (false, true) => MovePacket::Look {
103 yaw: pose.yaw,
104 pitch: pose.pitch,
105 on_ground,
106 },
107 (false, false) => MovePacket::Flying { on_ground },
108 };
109 if !self.increment_first {
110 self.ticks_since_pos += 1;
111 }
112 if moved {
113 self.last_pos = pose.pos;
114 self.ticks_since_pos = 0;
115 }
116 if turned {
117 self.last_yaw = pose.yaw;
118 self.last_pitch = pose.pitch;
119 }
120 MoveStep {
121 sprint,
122 sneak,
123 packet,
124 }
125 }
126}
127
128#[derive(Debug, Clone, Copy, Default, PartialEq)]
136pub struct StandStill {
137 ticks_since_teleport: u32,
138}
139
140impl StandStill {
141 pub fn teleported(&mut self) {
143 self.ticks_since_teleport = 0;
144 }
145
146 pub fn step(&mut self, pose: &mut Pose, controls: &Controls) {
148 pose.on_ground = self.ticks_since_teleport > 0;
149 self.ticks_since_teleport = self.ticks_since_teleport.saturating_add(1);
150 pose.motion = Vec3::default();
151 pose.sneaking = controls.sneak && !pose.flying;
152 pose.sprinting = false;
153 }
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159
160 fn pose(x: f64, y: f64, z: f64, yaw: f32, pitch: f32) -> Pose {
161 Pose {
162 pos: Vec3::new(x, y, z),
163 yaw,
164 pitch,
165 on_ground: true,
166 ..Pose::default()
167 }
168 }
169
170 #[test]
171 fn packet_choice() {
172 let mut s = MovementSender::new();
173 let p = pose(10.5, 64.0, -3.5, 90.0, 10.0);
175 assert!(matches!(
176 s.update(&p).packet,
177 MovePacket::PositionLook { .. }
178 ));
179 for _ in 0..20 {
182 assert!(matches!(
183 s.update(&p).packet,
184 MovePacket::Flying { on_ground: true }
185 ));
186 }
187 assert!(matches!(s.update(&p).packet, MovePacket::Position { .. }));
188 let p2 = pose(10.51, 64.0, -3.5, 91.0, 10.0);
190 assert!(matches!(s.update(&p2).packet, MovePacket::Look { .. }));
191 let p3 = pose(10.6, 64.0, -3.5, 91.0, 10.0);
192 assert!(matches!(s.update(&p3).packet, MovePacket::Position { .. }));
193 }
194
195 #[test]
196 fn position_refresh_1_9() {
197 let mut s = MovementSender::new_1_9();
198 let p = pose(10.5, 64.0, -3.5, 90.0, 10.0);
199 assert!(matches!(
200 s.update(&p).packet,
201 MovePacket::PositionLook { .. }
202 ));
203 for _ in 0..19 {
204 assert!(matches!(s.update(&p).packet, MovePacket::Flying { .. }));
205 }
206 assert!(matches!(s.update(&p).packet, MovePacket::Position { .. }));
207 }
208
209 #[test]
210 fn sneak_and_sprint_order() {
211 let mut s = MovementSender::new();
212 let mut p = pose(0.0, 0.0, 0.0, 0.0, 0.0);
213 p.sneaking = true;
214 p.sprinting = true;
215 let st = s.update(&p);
216 assert_eq!(st.sprint, Some(EntityAction::StartSprinting));
217 assert_eq!(st.sneak, Some(EntityAction::StartSneaking));
218 let st = s.update(&p);
219 assert_eq!((st.sprint, st.sneak), (None, None));
220 p.sneaking = false;
221 assert_eq!(s.update(&p).sneak, Some(EntityAction::StopSneaking));
222 }
223
224 #[test]
225 fn stand_still_ground() {
226 let mut m = StandStill::default();
227 let mut p = Pose::default();
228 m.teleported();
229 m.step(&mut p, &Controls::default());
230 assert!(!p.on_ground);
231 m.step(&mut p, &Controls::default());
232 assert!(p.on_ground);
233 }
234}