Skip to main content

yog_body/
movement.rs

1//! The local player's movement: a mod may replace a travel step (what the
2//! player moves by this tick) — gliding, flying, dashing. Runs on the
3//! client, which moves its own player; the server takes the result.
4
5use crate::math::Vec3;
6
7/// The local player before a travel step.
8#[derive(Debug, Clone, PartialEq, Default)]
9pub struct TravelFrame {
10    /// The local player.
11    pub uuid: String,
12    /// Blocks per tick, as it is now.
13    pub velocity: Vec3,
14    /// Unit view direction.
15    pub look: Vec3,
16    /// Degrees.
17    pub yaw: f32,
18    pub pitch: f32,
19    /// Movement keys: forward (−1–1), strafe left (−1–1), jump, sneak.
20    pub forward: f32,
21    pub strafe: f32,
22    pub jumping: bool,
23    pub sneaking: bool,
24    /// Pull per tick (0.08, 0.01 with slow falling).
25    pub gravity: f32,
26    /// `entity_flags` bits.
27    pub flags: u32,
28}
29
30/// Vanilla's elytra step (`LivingEntity.travel` while fall-flying): the
31/// velocity to move by this tick, drag applied.
32pub 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}