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