Skip to main content

nurtex_protocol/types/
vector.rs

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