diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-09-30 10:56:34 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-30 10:56:34 -0500 |
| commit | 643fcb98c0e6cdc63218dd39960d9053b209d9a6 (patch) | |
| tree | 6bddb7fe39b8fcc3ab3fb2665574533bb227898a /azalea-core/src | |
| parent | a80d8d1b242430c4a251876fa67bfd26af7a0de9 (diff) | |
| download | azalea-drasl-643fcb98c0e6cdc63218dd39960d9053b209d9a6.tar.xz | |
1.21.9 (#235)
* start updating to 25w33a
* 1.21.9-pre2
* clippy
* cleanup, and fix c_explode and c_player_rotation
* mc update should be in Changed section in the changelog
* 1.21.9
Diffstat (limited to 'azalea-core/src')
| -rw-r--r-- | azalea-core/src/delta.rs | 215 | ||||
| -rw-r--r-- | azalea-core/src/math.rs | 5 |
2 files changed, 218 insertions, 2 deletions
diff --git a/azalea-core/src/delta.rs b/azalea-core/src/delta.rs index d6a99b11..50fdeafa 100644 --- a/azalea-core/src/delta.rs +++ b/azalea-core/src/delta.rs @@ -1,6 +1,9 @@ +use std::io::{self, Cursor, Write}; + pub use azalea_buf::AzBuf; +use azalea_buf::{AzaleaRead, AzaleaReadVar, AzaleaWrite, AzaleaWriteVar, BufReadError}; -use crate::position::Vec3; +use crate::{math, position::Vec3}; pub trait PositionDeltaTrait { fn x(&self) -> f64; @@ -17,7 +20,7 @@ pub struct PositionDelta8 { } impl PositionDelta8 { - #[deprecated] + #[deprecated = "Use Self::x, y, z instead"] pub fn float(&self) -> (f64, f64, f64) { ( (self.xa as f64) / 4096.0, @@ -38,6 +41,11 @@ impl PositionDeltaTrait for PositionDelta8 { (self.za as f64) / 4096.0 } } +impl<T: PositionDeltaTrait> From<T> for Vec3 { + fn from(value: T) -> Self { + Vec3::new(value.x(), value.y(), value.z()) + } +} impl Vec3 { #[must_use] @@ -72,3 +80,206 @@ impl Vec3 { self.multiply(amount, amount, amount) } } + +/// A variable-length representation of a position delta. +/// +/// Can be freely converted to and from a [`Vec3`], but some precision will be +/// lost. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub enum LpVec3 { + #[default] + Zero, + Normal { + a: u8, + b: u8, + c: u32, + }, + Extended { + a: u8, + b: u8, + c: u32, + d: u32, + }, +} + +impl AzaleaRead for LpVec3 { + fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> { + let a = u8::azalea_read(buf)?; + if a == 0 { + return Ok(LpVec3::Zero); + } + let b = u8::azalea_read(buf)?; + let c = u32::azalea_read(buf)?; + if a & 4 == 4 { + let d = u32::azalea_read_var(buf)?; + Ok(LpVec3::Extended { a, b, c, d }) + } else { + Ok(LpVec3::Normal { a, b, c }) + } + } +} +impl AzaleaWrite for LpVec3 { + fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> { + match self { + LpVec3::Zero => { + 0u8.azalea_write(buf)?; + } + LpVec3::Normal { a, b, c } => { + a.azalea_write(buf)?; + b.azalea_write(buf)?; + c.azalea_write(buf)?; + } + LpVec3::Extended { a, b, c, d } => { + a.azalea_write(buf)?; + b.azalea_write(buf)?; + c.azalea_write(buf)?; + d.azalea_write_var(buf)?; + } + } + Ok(()) + } +} +impl LpVec3 { + pub fn from_vec3(vec3: Vec3) -> Self { + let x = Self::sanitize(vec3.x); + let y = Self::sanitize(vec3.y); + let z = Self::sanitize(vec3.z); + let max = x.abs().max(y.abs()).max(z.abs()); + if max < 3.051944088384301E-5 { + return LpVec3::Zero; + } + + let divisor = math::ceil_long(max); + let is_extended = divisor & 3 != divisor; + let packed_divisor = if is_extended { + (divisor as u64 & 3) | 4 + } else { + divisor as u64 + }; + let packed_x = Self::pack(x / (divisor as f64)) << 3; + let packed_y = Self::pack(y / (divisor as f64)) << 18; + let packed_z = Self::pack(z / (divisor as f64)) << 33; + let packed = packed_divisor | packed_x | packed_y | packed_z; + + let a = packed as u8; + let b = (packed >> 8) as u8; + let c = (packed >> 16) as u32; + + if is_extended { + let d = ((divisor as u64) >> 2) as u32; + Self::Extended { a, b, c, d } + } else { + Self::Normal { a, b, c } + } + } + + pub fn to_vec3(self) -> Vec3 { + match self { + LpVec3::Zero => Vec3::ZERO, + LpVec3::Normal { a, b, c } => { + let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64); + let multiplier = (a & 3) as u64 as f64; + + Vec3 { + x: Self::unpack(packed >> 3) * multiplier, + y: Self::unpack(packed >> 18) * multiplier, + z: Self::unpack(packed >> 33) * multiplier, + } + } + LpVec3::Extended { a, b, c, d } => { + let packed: u64 = (c as u64) << 16 | (b as u64) << 8 | (a as u64); + let multiplier = (a & 3) as u64; + let multiplier = multiplier | ((d as u64) << 2); + let multiplier = multiplier as f64; + + Vec3 { + x: Self::unpack(packed >> 3) * multiplier, + y: Self::unpack(packed >> 18) * multiplier, + z: Self::unpack(packed >> 33) * multiplier, + } + } + } + } + + fn unpack(value: u64) -> f64 { + f64::min((value & 32767) as f64, 32766.) * 2. / 32766. - 1. + } + + fn pack(value: f64) -> u64 { + f64::round((value * 0.5 + 0.5) * 32766.) as u64 + } + + fn sanitize(value: f64) -> f64 { + if value.is_nan() { + 0. + } else { + f64::clamp(value, -1.7179869183E10, 1.7179869183E10) + } + } +} +impl From<LpVec3> for Vec3 { + fn from(value: LpVec3) -> Self { + value.to_vec3() + } +} +impl From<Vec3> for LpVec3 { + fn from(value: Vec3) -> Self { + LpVec3::from_vec3(value) + } +} +#[cfg(test)] +mod tests { + use azalea_buf::AzaleaWrite; + + use super::*; + + static TEST_VALUES: [Vec3; 3] = [ + Vec3::ZERO, + Vec3 { + x: 1.234, + y: -5.678, + z: 9.876, + }, + Vec3 { + x: 10000000., + y: -5000000., + z: 9876543., + }, + ]; + + #[test] + fn test_lpvec3_roundtrip() { + fn close_enough(a: f64, b: f64) -> bool { + a == b || (a / b - 1.).abs() < 0.01 + } + + for v in TEST_VALUES { + let lp = LpVec3::from_vec3(v); + let v2 = lp.to_vec3(); + assert!( + close_enough(v.x, v2.x) && close_enough(v.y, v2.y) && close_enough(v.z, v2.z), + "Original: {:?}, Roundtrip: {:?}", + v, + v2 + ); + } + } + + #[test] + fn test_encode_decode_lpvec3() { + for v in TEST_VALUES { + let v: LpVec3 = LpVec3::from(v); + let mut first_buf = Vec::new(); + v.azalea_write(&mut first_buf).unwrap(); + let decoded = LpVec3::azalea_read(&mut Cursor::new(&first_buf)).unwrap(); + assert_eq!(v, decoded); + + let mut second_buf = Vec::new(); + LpVec3::from(Vec3::from(decoded)) + .azalea_write(&mut second_buf) + .unwrap(); + + assert_eq!(first_buf, second_buf); + } + } +} diff --git a/azalea-core/src/math.rs b/azalea-core/src/math.rs index e62a3d23..4d3bf84c 100644 --- a/azalea-core/src/math.rs +++ b/azalea-core/src/math.rs @@ -92,6 +92,11 @@ pub fn sign_as_int(num: f64) -> i32 { if num == 0. { 0 } else { num.signum() as i32 } } +pub fn ceil_long(x: f64) -> i64 { + let x_i64 = x as i64; + if x > x_i64 as f64 { x_i64 + 1 } else { x_i64 } +} + pub fn equal(a: f64, b: f64) -> bool { (b - a).abs() < 1.0e-5 } |
