1use crate::math::Vec3;
6
7#[derive(Debug, Clone, PartialEq, Default)]
9pub struct TravelFrame {
10 pub uuid: String,
12 pub velocity: Vec3,
14 pub look: Vec3,
16 pub yaw: f32,
18 pub pitch: f32,
19 pub forward: f32,
21 pub strafe: f32,
22 pub jumping: bool,
23 pub sneaking: bool,
24 pub gravity: f32,
26 pub flags: u32,
28}
29
30pub fn elytra(f: &TravelFrame) -> Vec3 {
33 let v = f.velocity;
34 let look = f.look;
35 let pitch = f.pitch.to_radians();
36 let g = f.gravity as f64;
37 let (lx, ly, lz) = (look.x as f64, look.y as f64, look.z as f64);
38 let (mut vx, mut vy, mut vz) = (v.x as f64, v.y as f64, v.z as f64);
39 let d1 = (lx * lx + lz * lz).sqrt();
40 let d3 = (vx * vx + vz * vz).sqrt();
41 let d4 = (lx * lx + ly * ly + lz * lz).sqrt();
42 let mut d5 = (pitch as f64).cos();
43 d5 = d5 * d5 * (d4 / 0.4).min(1.0);
44 vy += g * (-1.0 + d5 * 0.75);
45 if vy < 0.0 && d1 > 0.0 {
46 let d6 = vy * -0.1 * d5;
47 vx += lx * d6 / d1;
48 vy += d6;
49 vz += lz * d6 / d1;
50 }
51 if pitch < 0.0 && d1 > 0.0 {
52 let d10 = d3 * (-(pitch.sin()) as f64) * 0.04;
53 vx += -lx * d10 / d1;
54 vy += d10 * 3.2;
55 vz += -lz * d10 / d1;
56 }
57 if d1 > 0.0 {
58 vx += (lx / d1 * d3 - vx) * 0.1;
59 vz += (lz / d1 * d3 - vz) * 0.1;
60 }
61 Vec3::new((vx * 0.99) as f32, (vy * 0.98) as f32, (vz * 0.99) as f32)
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn gliding_level_falls_slowly_and_keeps_going() {
70 let f = TravelFrame { velocity: Vec3::new(0.0, 0.0, 1.0), look: Vec3::new(0.0, 0.0, 1.0), gravity: 0.08, ..Default::default() };
71 let v = elytra(&f);
72 assert!(v.y < 0.0 && v.y > -0.08, "{v:?}");
73 assert!(v.z > 0.9);
74 }
75}