aboutsummaryrefslogtreecommitdiff
path: root/azalea-core/src
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2025-09-30 10:56:34 -0500
committerGitHub <noreply@github.com>2025-09-30 10:56:34 -0500
commit643fcb98c0e6cdc63218dd39960d9053b209d9a6 (patch)
tree6bddb7fe39b8fcc3ab3fb2665574533bb227898a /azalea-core/src
parenta80d8d1b242430c4a251876fa67bfd26af7a0de9 (diff)
downloadazalea-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.rs215
-rw-r--r--azalea-core/src/math.rs5
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
}