Skip to main content

basalt_types/
vectors.rs

1use crate::{Decode, Encode, EncodedSize, Result};
2
3/// A 2D vector of f32 values.
4///
5/// Used in the Minecraft protocol for 2D positions and velocities,
6/// such as player movement input and rotation deltas.
7///
8/// Wire format: two big-endian f32 values (x, y), 8 bytes total.
9#[derive(Debug, Clone, Copy, Default, PartialEq)]
10pub struct Vec2f {
11    pub x: f32,
12    pub y: f32,
13}
14
15/// Encodes a Vec2f as two consecutive big-endian f32 values.
16impl Encode for Vec2f {
17    fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
18        self.x.encode(buf)?;
19        self.y.encode(buf)
20    }
21}
22
23/// Decodes a Vec2f from two consecutive big-endian f32 values.
24impl Decode for Vec2f {
25    fn decode(buf: &mut &[u8]) -> Result<Self> {
26        Ok(Self {
27            x: f32::decode(buf)?,
28            y: f32::decode(buf)?,
29        })
30    }
31}
32
33/// A Vec2f always occupies 8 bytes (2 × f32).
34impl EncodedSize for Vec2f {
35    fn encoded_size(&self) -> usize {
36        8
37    }
38}
39
40/// A 3D vector of f32 values.
41///
42/// Used in the Minecraft protocol for positions, velocities, and
43/// directions with single-precision floating point. Common in entity
44/// movement and particle effects.
45///
46/// Wire format: three big-endian f32 values (x, y, z), 12 bytes total.
47#[derive(Debug, Clone, Copy, Default, PartialEq)]
48pub struct Vec3f {
49    pub x: f32,
50    pub y: f32,
51    pub z: f32,
52}
53
54/// Encodes a Vec3f as three consecutive big-endian f32 values.
55impl Encode for Vec3f {
56    fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
57        self.x.encode(buf)?;
58        self.y.encode(buf)?;
59        self.z.encode(buf)
60    }
61}
62
63/// Decodes a Vec3f from three consecutive big-endian f32 values.
64impl Decode for Vec3f {
65    fn decode(buf: &mut &[u8]) -> Result<Self> {
66        Ok(Self {
67            x: f32::decode(buf)?,
68            y: f32::decode(buf)?,
69            z: f32::decode(buf)?,
70        })
71    }
72}
73
74/// A Vec3f always occupies 12 bytes (3 × f32).
75impl EncodedSize for Vec3f {
76    fn encoded_size(&self) -> usize {
77        12
78    }
79}
80
81/// A 3D vector of f64 values.
82///
83/// Used in the Minecraft protocol for precise entity positions and
84/// world coordinates. Double-precision is needed because Minecraft
85/// worlds can be very large (up to 30 million blocks from origin).
86///
87/// Wire format: three big-endian f64 values (x, y, z), 24 bytes total.
88#[derive(Debug, Clone, Copy, Default, PartialEq)]
89pub struct Vec3f64 {
90    pub x: f64,
91    pub y: f64,
92    pub z: f64,
93}
94
95/// Encodes a Vec3f64 as three consecutive big-endian f64 values.
96impl Encode for Vec3f64 {
97    fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
98        self.x.encode(buf)?;
99        self.y.encode(buf)?;
100        self.z.encode(buf)
101    }
102}
103
104/// Decodes a Vec3f64 from three consecutive big-endian f64 values.
105impl Decode for Vec3f64 {
106    fn decode(buf: &mut &[u8]) -> Result<Self> {
107        Ok(Self {
108            x: f64::decode(buf)?,
109            y: f64::decode(buf)?,
110            z: f64::decode(buf)?,
111        })
112    }
113}
114
115/// A Vec3f64 always occupies 24 bytes (3 × f64).
116impl EncodedSize for Vec3f64 {
117    fn encoded_size(&self) -> usize {
118        24
119    }
120}
121
122/// A 3D vector of i16 values.
123///
124/// Used in the Minecraft protocol for relative entity movement deltas
125/// in the Entity Position packet. Each unit represents 1/128 of a block.
126///
127/// Wire format: three big-endian i16 values (x, y, z), 6 bytes total.
128#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
129pub struct Vec3i16 {
130    pub x: i16,
131    pub y: i16,
132    pub z: i16,
133}
134
135/// Encodes a Vec3i16 as three consecutive big-endian i16 values.
136impl Encode for Vec3i16 {
137    fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
138        self.x.encode(buf)?;
139        self.y.encode(buf)?;
140        self.z.encode(buf)
141    }
142}
143
144/// Decodes a Vec3i16 from three consecutive big-endian i16 values.
145impl Decode for Vec3i16 {
146    fn decode(buf: &mut &[u8]) -> Result<Self> {
147        Ok(Self {
148            x: i16::decode(buf)?,
149            y: i16::decode(buf)?,
150            z: i16::decode(buf)?,
151        })
152    }
153}
154
155/// A Vec3i16 always occupies 6 bytes (3 × i16).
156impl EncodedSize for Vec3i16 {
157    fn encoded_size(&self) -> usize {
158        6
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165
166    fn roundtrip<T: Encode + Decode + EncodedSize + PartialEq + std::fmt::Debug>(value: T) {
167        let mut buf = Vec::with_capacity(value.encoded_size());
168        value.encode(&mut buf).unwrap();
169        assert_eq!(buf.len(), value.encoded_size());
170
171        let mut cursor = buf.as_slice();
172        let decoded = T::decode(&mut cursor).unwrap();
173        assert!(cursor.is_empty());
174        assert_eq!(decoded, value);
175    }
176
177    #[test]
178    fn vec2f_roundtrip() {
179        roundtrip(Vec2f { x: 1.5, y: -2.5 });
180    }
181
182    #[test]
183    fn vec2f_zero() {
184        roundtrip(Vec2f::default());
185    }
186
187    #[test]
188    fn vec3f_roundtrip() {
189        roundtrip(Vec3f {
190            x: 1.0,
191            y: 2.0,
192            z: 3.0,
193        });
194    }
195
196    #[test]
197    fn vec3f64_roundtrip() {
198        roundtrip(Vec3f64 {
199            x: 100.5,
200            y: 64.0,
201            z: -200.25,
202        });
203    }
204
205    #[test]
206    fn vec3i16_roundtrip() {
207        roundtrip(Vec3i16 {
208            x: 100,
209            y: -50,
210            z: 200,
211        });
212    }
213
214    #[test]
215    fn encoded_sizes() {
216        assert_eq!(Vec2f::default().encoded_size(), 8);
217        assert_eq!(Vec3f::default().encoded_size(), 12);
218        assert_eq!(Vec3f64::default().encoded_size(), 24);
219        assert_eq!(Vec3i16::default().encoded_size(), 6);
220    }
221}