1use crate::math::Vec3;
6
7#[derive(yog_data::Schema, 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
30mod glide {
32 pub const FULL_LIFT_LOOK: f64 = 0.4;
34 pub const LIFT: f64 = 0.75;
36 pub const FALL_TO_SPEED: f64 = 0.1;
38 pub const CLIMB: f64 = 0.04;
40 pub const CLIMB_UP: f64 = 3.2;
42 pub const STEER: f64 = 0.1;
44 pub const DRAG: f64 = 0.99;
46 pub const DRAG_Y: f64 = 0.98;
47}
48
49pub fn elytra(f: &TravelFrame) -> Vec3 {
52 let v = f.velocity;
53 let look = f.look;
54 let pitch = f.pitch.to_radians();
55 let g = f.gravity as f64;
56 let (lx, ly, lz) = (look.x as f64, look.y as f64, look.z as f64);
57 let (mut vx, mut vy, mut vz) = (v.x as f64, v.y as f64, v.z as f64);
58 let d1 = (lx * lx + lz * lz).sqrt();
59 let d3 = (vx * vx + vz * vz).sqrt();
60 let d4 = (lx * lx + ly * ly + lz * lz).sqrt();
61 let mut d5 = (pitch as f64).cos();
62 d5 = d5 * d5 * (d4 / glide::FULL_LIFT_LOOK).min(1.0);
63 vy += g * (-1.0 + d5 * glide::LIFT);
64 if vy < 0.0 && d1 > 0.0 {
65 let d6 = vy * -glide::FALL_TO_SPEED * d5;
66 vx += lx * d6 / d1;
67 vy += d6;
68 vz += lz * d6 / d1;
69 }
70 if pitch < 0.0 && d1 > 0.0 {
71 let d10 = d3 * (-(pitch.sin()) as f64) * glide::CLIMB;
72 vx += -lx * d10 / d1;
73 vy += d10 * glide::CLIMB_UP;
74 vz += -lz * d10 / d1;
75 }
76 if d1 > 0.0 {
77 vx += (lx / d1 * d3 - vx) * glide::STEER;
78 vz += (lz / d1 * d3 - vz) * glide::STEER;
79 }
80 Vec3::new(
81 (vx * glide::DRAG) as f32,
82 (vy * glide::DRAG_Y) as f32,
83 (vz * glide::DRAG) as f32,
84 )
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn gliding_level_falls_slowly_and_keeps_going() {
93 let f = TravelFrame {
94 velocity: Vec3::new(0.0, 0.0, 1.0),
95 look: Vec3::new(0.0, 0.0, 1.0),
96 gravity: 0.08,
97 ..Default::default()
98 };
99 let v = elytra(&f);
100 assert!(v.y < 0.0 && v.y > -0.08, "{v:?}");
101 assert!(v.z > 0.9);
102 }
103}