azalea_core/
delta.rs

1use std::io::{self, Cursor, Write};
2
3pub use azalea_buf::AzBuf;
4use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError};
5
6use crate::{math, position::Vec3};
7
8pub trait PositionDeltaTrait {
9    fn x(&self) -> f64;
10    fn y(&self) -> f64;
11    fn z(&self) -> f64;
12}
13
14/// Only works for up to 8 blocks
15#[derive(Clone, Debug, AzBuf, Default, PartialEq)]
16pub struct PositionDelta8 {
17    pub xa: i16,
18    pub ya: i16,
19    pub za: i16,
20}
21
22impl PositionDeltaTrait for PositionDelta8 {
23    fn x(&self) -> f64 {
24        (self.xa as f64) / 4096.0
25    }
26    fn y(&self) -> f64 {
27        (self.ya as f64) / 4096.0
28    }
29    fn z(&self) -> f64 {
30        (self.za as f64) / 4096.0
31    }
32}
33impl<T: PositionDeltaTrait> From<T> for Vec3 {
34    fn from(value: T) -> Self {
35        Vec3::new(value.x(), value.y(), value.z())
36    }
37}
38
39impl Vec3 {
40    #[must_use]
41    pub fn with_delta(&self, delta: &impl PositionDeltaTrait) -> Vec3 {
42        Vec3 {
43            x: self.x + delta.x(),
44            y: self.y + delta.y(),
45            z: self.z + delta.z(),
46        }
47    }
48
49    pub fn normalize(&self) -> Vec3 {
50        let length = f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
51        if length < 1e-5 {
52            return Vec3::ZERO;
53        }
54        Vec3 {
55            x: self.x / length,
56            y: self.y / length,
57            z: self.z / length,
58        }
59    }
60
61    pub fn multiply(&self, x: f64, y: f64, z: f64) -> Vec3 {
62        Vec3 {
63            x: self.x * x,
64            y: self.y * y,
65            z: self.z * z,
66        }
67    }
68    pub fn scale(&self, amount: f64) -> Vec3 {
69        self.multiply(amount, amount, amount)
70    }
71}
72
73/// A variable-length representation of a position delta.
74///
75/// Can be freely converted to and from a [`Vec3`], but some precision will be
76/// lost.
77#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
78pub enum LpVec3 {
79    #[default]
80    Zero,
81    Normal {
82        a: u8,
83        b: u8,
84        c: u32,
85    },
86    Extended {
87        a: u8,
88        b: u8,
89        c: u32,
90        d: u32,
91    },
92}
93
94impl AzaleaRead for LpVec3 {
95    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
96        let a = u8::azalea_read(buf)?;
97        if a == 0 {
98            return Ok(LpVec3::Zero);
99        }
100        let b = u8::azalea_read(buf)?;
101        let c = u32::azalea_read(buf)?;
102        if a & 4 == 4 {
103            let d = u32::azalea_read_var(buf)?;
104            Ok(LpVec3::Extended { a, b, c, d })
105        } else {
106            Ok(LpVec3::Normal { a, b, c })
107        }
108    }
109}
110impl AzaleaWrite for LpVec3 {
111    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
112        match self {
113            LpVec3::Zero => {
114                0u8.azalea_write(buf)?;
115            }
116            LpVec3::Normal { a, b, c } => {
117                a.azalea_write(buf)?;
118                b.azalea_write(buf)?;
119                c.azalea_write(buf)?;
120            }
121            LpVec3::Extended { a, b, c, d } => {
122                a.azalea_write(buf)?;
123                b.azalea_write(buf)?;
124                c.azalea_write(buf)?;
125                d.azalea_write_var(buf)?;
126            }
127        }
128        Ok(())
129    }
130}
131impl LpVec3 {
132    pub fn from_vec3(vec3: Vec3) -> Self {
133        let x = Self::sanitize(vec3.x);
134        let y = Self::sanitize(vec3.y);
135        let z = Self::sanitize(vec3.z);
136        let max = x.abs().max(y.abs()).max(z.abs());
137        if max < 3.051944088384301E-5 {
138            return LpVec3::Zero;
139        }
140
141        let divisor = math::ceil_long(max);
142        let is_extended = divisor & 3 != divisor;
143        let packed_divisor = if is_extended {
144            (divisor as u64 & 3) | 4
145        } else {
146            divisor as u64
147        };
148        let packed_x = Self::pack(x / (divisor as f64)) << 3;
149        let packed_y = Self::pack(y / (divisor as f64)) << 18;
150        let packed_z = Self::pack(z / (divisor as f64)) << 33;
151        let packed = packed_divisor | packed_x | packed_y | packed_z;
152
153        let a = packed as u8;
154        let b = (packed >> 8) as u8;
155        let c = (packed >> 16) as u32;
156
157        if is_extended {
158            let d = ((divisor as u64) >> 2) as u32;
159            Self::Extended { a, b, c, d }
160        } else {
161            Self::Normal { a, b, c }
162        }
163    }
164
165    pub fn to_vec3(self) -> Vec3 {
166        match self {
167            LpVec3::Zero => Vec3::ZERO,
168            LpVec3::Normal { a, b, c } => {
169                let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64);
170                let multiplier = (a & 3) as u64 as f64;
171
172                Vec3 {
173                    x: Self::unpack(packed >> 3) * multiplier,
174                    y: Self::unpack(packed >> 18) * multiplier,
175                    z: Self::unpack(packed >> 33) * multiplier,
176                }
177            }
178            LpVec3::Extended { a, b, c, d } => {
179                let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64);
180                let multiplier = (a & 3) as u64;
181                let multiplier = multiplier | ((d as u64) << 2);
182                let multiplier = multiplier as f64;
183
184                Vec3 {
185                    x: Self::unpack(packed >> 3) * multiplier,
186                    y: Self::unpack(packed >> 18) * multiplier,
187                    z: Self::unpack(packed >> 33) * multiplier,
188                }
189            }
190        }
191    }
192
193    fn unpack(value: u64) -> f64 {
194        f64::min((value & 32767) as f64, 32766.) * 2. / 32766. - 1.
195    }
196
197    fn pack(value: f64) -> u64 {
198        f64::round((value * 0.5 + 0.5) * 32766.) as u64
199    }
200
201    fn sanitize(value: f64) -> f64 {
202        if value.is_nan() {
203            0.
204        } else {
205            f64::clamp(value, -1.7179869183E10, 1.7179869183E10)
206        }
207    }
208}
209impl From<LpVec3> for Vec3 {
210    fn from(value: LpVec3) -> Self {
211        value.to_vec3()
212    }
213}
214impl From<Vec3> for LpVec3 {
215    fn from(value: Vec3) -> Self {
216        LpVec3::from_vec3(value)
217    }
218}
219#[cfg(test)]
220mod tests {
221    use azalea_buf::AzaleaWrite;
222
223    use super::*;
224
225    static TEST_VALUES: [Vec3; 3] = [
226        Vec3::ZERO,
227        Vec3 {
228            x: 1.234,
229            y: -5.678,
230            z: 9.876,
231        },
232        Vec3 {
233            x: 10000000.,
234            y: -5000000.,
235            z: 9876543.,
236        },
237    ];
238
239    #[test]
240    fn test_lpvec3_roundtrip() {
241        fn close_enough(a: f64, b: f64) -> bool {
242            a == b || (a / b - 1.).abs() < 0.01
243        }
244
245        for v in TEST_VALUES {
246            let lp = LpVec3::from_vec3(v);
247            let v2 = lp.to_vec3();
248            assert!(
249                close_enough(v.x, v2.x) && close_enough(v.y, v2.y) && close_enough(v.z, v2.z),
250                "Original: {:?}, Roundtrip: {:?}",
251                v,
252                v2
253            );
254        }
255    }
256
257    #[test]
258    fn test_encode_decode_lpvec3() {
259        for v in TEST_VALUES {
260            let v: LpVec3 = LpVec3::from(v);
261            let mut first_buf = Vec::new();
262            v.azalea_write(&mut first_buf).unwrap();
263            let decoded = LpVec3::azalea_read(&mut Cursor::new(&first_buf)).unwrap();
264            assert_eq!(v, decoded);
265
266            let mut second_buf = Vec::new();
267            LpVec3::from(Vec3::from(decoded))
268                .azalea_write(&mut second_buf)
269                .unwrap();
270
271            assert_eq!(first_buf, second_buf);
272        }
273    }
274}