Skip to main content

nurtex_protocol/types/
vector.rs

1use std::io::{self, Cursor, Write};
2
3use nurtex_codec::{Buffer, VarInt};
4
5/// Структура позиции
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Vector3 {
8  pub x: f64,
9  pub y: f64,
10  pub z: f64,
11}
12
13impl Vector3 {
14  /// Метод создания нового экземпляра `Vector3`
15  pub fn new(x: f64, y: f64, z: f64) -> Self {
16    Self { x, y, z }
17  }
18
19  /// Метод создания нулевого вектора
20  pub fn zero() -> Self {
21    Self { x: 0.0, y: 0.0, z: 0.0 }
22  }
23
24  /// Метод вычисления разницы между текущим и другим вектором
25  pub fn delta(&self, other: Vector3) -> Self {
26    let dx = self.x - other.x;
27    let dy = self.y - other.y;
28    let dz = self.z - other.z;
29
30    Self { x: dx, y: dy, z: dz }
31  }
32}
33
34impl Buffer for Vector3 {
35  fn read_buf(buffer: &mut Cursor<&[u8]>) -> Option<Self> {
36    Some(Self {
37      x: f64::read_buf(buffer)?,
38      y: f64::read_buf(buffer)?,
39      z: f64::read_buf(buffer)?,
40    })
41  }
42
43  fn write_buf(&self, buffer: &mut impl Write) -> io::Result<()> {
44    self.x.write_buf(buffer)?;
45    self.y.write_buf(buffer)?;
46    self.z.write_buf(buffer)?;
47    Ok(())
48  }
49}
50
51/// Структура компактного представление вектора
52#[derive(Debug, Clone, Copy, PartialEq)]
53pub struct LpVector3 {
54  pub x: f64,
55  pub y: f64,
56  pub z: f64,
57}
58
59impl LpVector3 {
60  const MAX_QUANTIZED_VALUE: f64 = 32766.0;
61
62  /// Метод создания нового экземпляра `LpVector3`
63  pub fn new(x: f64, y: f64, z: f64) -> Self {
64    Self { x, y, z }
65  }
66
67  /// Метод создания нулевого вектора
68  pub fn zero() -> Self {
69    Self { x: 0.0, y: 0.0, z: 0.0 }
70  }
71
72  /// Метод упаковки значения
73  fn pack(value: f64) -> i64 {
74    ((value * 0.5 + 0.5) * Self::MAX_QUANTIZED_VALUE).round() as i64
75  }
76
77  /// Метод распаковки значения
78  fn unpack(value: i64) -> f64 {
79    let v = (value & 32767) as f64;
80    (v.min(Self::MAX_QUANTIZED_VALUE)) * 2.0 / Self::MAX_QUANTIZED_VALUE - 1.0
81  }
82}
83
84impl Buffer for LpVector3 {
85  fn read_buf(buffer: &mut Cursor<&[u8]>) -> Option<Self> {
86    let byte1 = u8::read_buf(buffer)? as i32;
87
88    if byte1 == 0 {
89      return Some(Self { x: 0.0, y: 0.0, z: 0.0 });
90    }
91
92    let byte2 = u8::read_buf(buffer)? as i32;
93    let bytes3to4 = u32::read_buf(buffer)? as i64;
94
95    let packed = (bytes3to4 << 16) | ((byte2 as i64) << 8) | (byte1 as i64);
96
97    let mut scale_factor = (byte1 & 3) as i64;
98
99    if (byte1 & 4) == 4 {
100      scale_factor |= (i32::read_varint(buffer)? as i64 & 0xFFFFFFFF) << 2;
101    }
102
103    let scale_factor_d = scale_factor as f64;
104
105    Some(Self {
106      x: Self::unpack(packed >> 3) * scale_factor_d,
107      y: Self::unpack(packed >> 18) * scale_factor_d,
108      z: Self::unpack(packed >> 33) * scale_factor_d,
109    })
110  }
111
112  fn write_buf(&self, buffer: &mut impl Write) -> io::Result<()> {
113    let max_coordinate = self.x.abs().max(self.y.abs().max(self.z.abs()));
114
115    if max_coordinate < 3.051944088384301e-5 {
116      0u8.write_buf(buffer)?;
117    } else {
118      let max_coordinate_i = max_coordinate as i64;
119      let scale_factor = if max_coordinate > max_coordinate_i as f64 {
120        max_coordinate_i + 1
121      } else {
122        max_coordinate_i
123      };
124
125      let need_continuation = (scale_factor & 3) != scale_factor;
126      let packed_scale = if need_continuation { (scale_factor & 3) | 4 } else { scale_factor };
127
128      let packed_x = Self::pack(self.x / scale_factor as f64) << 3;
129      let packed_y = Self::pack(self.y / scale_factor as f64) << 18;
130      let packed_z = Self::pack(self.z / scale_factor as f64) << 33;
131
132      let packed = packed_z | packed_y | packed_x | packed_scale;
133
134      ((packed & 0xFF) as u8).write_buf(buffer)?;
135      (((packed >> 8) & 0xFF) as u8).write_buf(buffer)?;
136      ((packed >> 16) as u32).write_buf(buffer)?;
137
138      if need_continuation {
139        ((scale_factor >> 2) as i32).write_varint(buffer)?;
140      }
141    }
142
143    Ok(())
144  }
145}