azalea_core/
position.rs

1//! Representations of positions of various things in Minecraft.
2//!
3//! The most common ones are [`Vec3`] and [`BlockPos`], which are usually used
4//! for entity positions and block positions, respectively.
5
6use std::{
7    fmt,
8    hash::{Hash, Hasher},
9    io,
10    io::{Cursor, Write},
11    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, Sub},
12    str::FromStr,
13};
14
15use azalea_buf::{AzBuf, AzaleaRead, AzaleaWrite, BufReadError};
16
17use crate::{direction::Direction, math, resource_location::ResourceLocation};
18
19macro_rules! vec3_impl {
20    ($name:ident, $type:ty) => {
21        impl $name {
22            #[inline]
23            pub const fn new(x: $type, y: $type, z: $type) -> Self {
24                Self { x, y, z }
25            }
26
27            /// Get the distance of this vector to the origin by doing `x^2 + y^2 +
28            /// z^2`.
29            #[inline]
30            pub fn length_squared(&self) -> $type {
31                self.x * self.x + self.y * self.y + self.z * self.z
32            }
33
34            /// Get the squared distance from this position to another position.
35            /// Equivalent to `(self - other).length_squared()`.
36            #[inline]
37            pub fn distance_squared_to(&self, other: &Self) -> $type {
38                (self - other).length_squared()
39            }
40
41            #[inline]
42            pub fn horizontal_distance_squared(&self) -> $type {
43                self.x * self.x + self.z * self.z
44            }
45
46            #[inline]
47            pub fn horizontal_distance_squared_to(&self, other: &Self) -> $type {
48                (self - other).horizontal_distance_squared()
49            }
50
51            /// Return a new instance of this position with the y coordinate
52            /// decreased by the given number.
53            #[inline]
54            pub fn down(&self, y: $type) -> Self {
55                Self {
56                    x: self.x,
57                    y: self.y - y,
58                    z: self.z,
59                }
60            }
61            /// Return a new instance of this position with the y coordinate
62            /// increased by the given number.
63            #[inline]
64            pub fn up(&self, y: $type) -> Self {
65                Self {
66                    x: self.x,
67                    y: self.y + y,
68                    z: self.z,
69                }
70            }
71
72            /// Return a new instance of this position with the z coordinate subtracted
73            /// by the given number.
74            #[inline]
75            pub fn north(&self, z: $type) -> Self {
76                Self {
77                    x: self.x,
78                    y: self.y,
79                    z: self.z - z,
80                }
81            }
82            /// Return a new instance of this position with the x coordinate increased
83            /// by the given number.
84            #[inline]
85            pub fn east(&self, x: $type) -> Self {
86                Self {
87                    x: self.x + x,
88                    y: self.y,
89                    z: self.z,
90                }
91            }
92            /// Return a new instance of this position with the z coordinate increased
93            /// by the given number.
94            #[inline]
95            pub fn south(&self, z: $type) -> Self {
96                Self {
97                    x: self.x,
98                    y: self.y,
99                    z: self.z + z,
100                }
101            }
102            /// Return a new instance of this position with the x coordinate subtracted
103            /// by the given number.
104            #[inline]
105            pub fn west(&self, x: $type) -> Self {
106                Self {
107                    x: self.x - x,
108                    y: self.y,
109                    z: self.z,
110                }
111            }
112
113            #[inline]
114            pub fn dot(&self, other: Self) -> $type {
115                self.x * other.x + self.y * other.y + self.z * other.z
116            }
117
118            /// Replace the Y with 0.
119            #[inline]
120            pub fn xz(&self) -> Self {
121                Self {
122                    x: self.x,
123                    y: <$type>::default(),
124                    z: self.z,
125                }
126            }
127
128            pub fn with_x(&self, x: $type) -> Self {
129                Self { x, ..*self }
130            }
131            pub fn with_y(&self, y: $type) -> Self {
132                Self { y, ..*self }
133            }
134            pub fn with_z(&self, z: $type) -> Self {
135                Self { z, ..*self }
136            }
137        }
138
139        impl Add for &$name {
140            type Output = $name;
141
142            #[inline]
143            fn add(self, rhs: Self) -> Self::Output {
144                $name {
145                    x: self.x + rhs.x,
146                    y: self.y + rhs.y,
147                    z: self.z + rhs.z,
148                }
149            }
150        }
151        impl Add for $name {
152            type Output = $name;
153
154            #[inline]
155            fn add(self, rhs: Self) -> Self::Output {
156                (&self).add(&rhs)
157            }
158        }
159        impl Add<$type> for $name {
160            type Output = Self;
161
162            #[inline]
163            fn add(self, rhs: $type) -> Self::Output {
164                Self {
165                    x: self.x + rhs,
166                    y: self.y + rhs,
167                    z: self.z + rhs,
168                }
169            }
170        }
171
172        impl AddAssign for $name {
173            #[inline]
174            fn add_assign(&mut self, rhs: Self) {
175                self.x += rhs.x;
176                self.y += rhs.y;
177                self.z += rhs.z;
178            }
179        }
180        impl Rem<$type> for $name {
181            type Output = Self;
182
183            #[inline]
184            fn rem(self, rhs: $type) -> Self::Output {
185                Self {
186                    x: self.x % rhs,
187                    y: self.y % rhs,
188                    z: self.z % rhs,
189                }
190            }
191        }
192
193        impl Sub for &$name {
194            type Output = $name;
195
196            /// Find the difference between two positions.
197            #[inline]
198            fn sub(self, other: Self) -> Self::Output {
199                Self::Output {
200                    x: self.x - other.x,
201                    y: self.y - other.y,
202                    z: self.z - other.z,
203                }
204            }
205        }
206        impl Sub for $name {
207            type Output = Self;
208
209            #[inline]
210            fn sub(self, other: Self) -> Self::Output {
211                (&self).sub(&other)
212            }
213        }
214
215        impl Mul<$type> for $name {
216            type Output = Self;
217
218            #[inline]
219            fn mul(self, multiplier: $type) -> Self::Output {
220                Self {
221                    x: self.x * multiplier,
222                    y: self.y * multiplier,
223                    z: self.z * multiplier,
224                }
225            }
226        }
227        impl MulAssign<$type> for $name {
228            #[inline]
229            fn mul_assign(&mut self, multiplier: $type) {
230                self.x *= multiplier;
231                self.y *= multiplier;
232                self.z *= multiplier;
233            }
234        }
235
236        impl Div<$type> for $name {
237            type Output = Self;
238
239            #[inline]
240            fn div(self, divisor: $type) -> Self::Output {
241                Self {
242                    x: self.x / divisor,
243                    y: self.y / divisor,
244                    z: self.z / divisor,
245                }
246            }
247        }
248        impl DivAssign<$type> for $name {
249            #[inline]
250            fn div_assign(&mut self, divisor: $type) {
251                self.x /= divisor;
252                self.y /= divisor;
253                self.z /= divisor;
254            }
255        }
256
257        impl From<($type, $type, $type)> for $name {
258            #[inline]
259            fn from(pos: ($type, $type, $type)) -> Self {
260                Self::new(pos.0, pos.1, pos.2)
261            }
262        }
263        impl From<&($type, $type, $type)> for $name {
264            #[inline]
265            fn from(pos: &($type, $type, $type)) -> Self {
266                Self::new(pos.0, pos.1, pos.2)
267            }
268        }
269        impl From<$name> for ($type, $type, $type) {
270            #[inline]
271            fn from(pos: $name) -> Self {
272                (pos.x, pos.y, pos.z)
273            }
274        }
275    };
276}
277
278/// Used to represent an exact position in the world where an entity could be.
279///
280/// For blocks, [`BlockPos`] is used instead.
281#[derive(Clone, Copy, Debug, Default, PartialEq, AzBuf)]
282#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
283pub struct Vec3 {
284    pub x: f64,
285    pub y: f64,
286    pub z: f64,
287}
288vec3_impl!(Vec3, f64);
289
290impl Vec3 {
291    pub const ZERO: Vec3 = Vec3::new(0.0, 0.0, 0.0);
292
293    /// Get the distance of this vector to the origin by doing
294    /// `sqrt(x^2 + y^2 + z^2)`.
295    pub fn length(&self) -> f64 {
296        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
297    }
298
299    /// Get the distance from this position to another position.
300    /// Equivalent to `(self - other).length()`.
301    pub fn distance_to(&self, other: &Self) -> f64 {
302        (self - other).length()
303    }
304
305    pub fn x_rot(self, radians: f32) -> Vec3 {
306        let x_delta = math::cos(radians);
307        let y_delta = math::sin(radians);
308        let x = self.x;
309        let y = self.y * (x_delta as f64) + self.z * (y_delta as f64);
310        let z = self.z * (x_delta as f64) - self.y * (y_delta as f64);
311        Vec3 { x, y, z }
312    }
313    pub fn y_rot(self, radians: f32) -> Vec3 {
314        let x_delta = math::cos(radians);
315        let y_delta = math::sin(radians);
316        let x = self.x * (x_delta as f64) + self.z * (y_delta as f64);
317        let y = self.y;
318        let z = self.z * (x_delta as f64) - self.x * (y_delta as f64);
319        Vec3 { x, y, z }
320    }
321
322    pub fn to_block_pos_floor(&self) -> BlockPos {
323        BlockPos {
324            x: self.x.floor() as i32,
325            y: self.y.floor() as i32,
326            z: self.z.floor() as i32,
327        }
328    }
329    pub fn to_block_pos_ceil(&self) -> BlockPos {
330        BlockPos {
331            x: self.x.ceil() as i32,
332            y: self.y.ceil() as i32,
333            z: self.z.ceil() as i32,
334        }
335    }
336}
337
338/// The coordinates of a block in the world. For entities (if the coordinate
339/// have decimals), use [`Vec3`] instead.
340#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
341#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
342pub struct BlockPos {
343    pub x: i32,
344    pub y: i32,
345    pub z: i32,
346}
347vec3_impl!(BlockPos, i32);
348
349impl BlockPos {
350    /// Get the absolute center of a block position by adding 0.5 to each
351    /// coordinate.
352    pub fn center(&self) -> Vec3 {
353        Vec3 {
354            x: self.x as f64 + 0.5,
355            y: self.y as f64 + 0.5,
356            z: self.z as f64 + 0.5,
357        }
358    }
359
360    /// Convert the block position into a Vec3 without centering it.
361    pub fn to_vec3_floored(&self) -> Vec3 {
362        Vec3 {
363            x: self.x as f64,
364            y: self.y as f64,
365            z: self.z as f64,
366        }
367    }
368
369    /// Get the distance of this vector from the origin by doing `x + y + z`.
370    pub fn length_manhattan(&self) -> u32 {
371        (self.x.abs() + self.y.abs() + self.z.abs()) as u32
372    }
373
374    /// Make a new BlockPos with the lower coordinates for each axis.
375    ///
376    /// ```
377    /// # use azalea_core::position::BlockPos;
378    /// assert_eq!(
379    ///     BlockPos::min(&BlockPos::new(1, 20, 300), &BlockPos::new(50, 40, 30),),
380    ///     BlockPos::new(1, 20, 30),
381    /// );
382    /// ```
383    pub fn min(&self, other: &Self) -> Self {
384        Self {
385            x: self.x.min(other.x),
386            y: self.y.min(other.y),
387            z: self.z.min(other.z),
388        }
389    }
390
391    /// Make a new BlockPos with the higher coordinates for each axis.
392    ///
393    /// ```
394    /// # use azalea_core::position::BlockPos;
395    /// assert_eq!(
396    ///     BlockPos::max(&BlockPos::new(1, 20, 300), &BlockPos::new(50, 40, 30),),
397    ///     BlockPos::new(50, 40, 300),
398    /// );
399    /// ```
400    pub fn max(&self, other: &Self) -> Self {
401        Self {
402            x: self.x.max(other.x),
403            y: self.y.max(other.y),
404            z: self.z.max(other.z),
405        }
406    }
407
408    pub fn offset_with_direction(self, direction: Direction) -> Self {
409        self + direction.normal()
410    }
411}
412
413/// Similar to [`BlockPos`] but it's serialized as 3 varints instead of one
414/// 64-bit integer, so it can represent a bigger range of numbers.
415#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, AzBuf)]
416pub struct Vec3i {
417    #[var]
418    pub x: i32,
419    #[var]
420    pub y: i32,
421    #[var]
422    pub z: i32,
423}
424
425/// Chunk coordinates are used to represent where a chunk is in the world. You
426/// can convert the x and z to block coordinates by multiplying them by 16.
427#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
428pub struct ChunkPos {
429    pub x: i32,
430    pub z: i32,
431}
432impl ChunkPos {
433    pub fn new(x: i32, z: i32) -> Self {
434        ChunkPos { x, z }
435    }
436}
437impl Add<ChunkPos> for ChunkPos {
438    type Output = Self;
439
440    fn add(self, rhs: Self) -> Self::Output {
441        Self {
442            x: self.x + rhs.x,
443            z: self.z + rhs.z,
444        }
445    }
446}
447
448// reading ChunkPos is done in reverse, so z first and then x
449// ........
450// mojang why
451impl From<ChunkPos> for u64 {
452    #[inline]
453    fn from(pos: ChunkPos) -> Self {
454        (pos.x as u64) | ((pos.z as u64) << 32)
455    }
456}
457impl From<u64> for ChunkPos {
458    #[inline]
459    fn from(pos: u64) -> Self {
460        ChunkPos {
461            x: (pos) as i32,
462            z: (pos >> 32) as i32,
463        }
464    }
465}
466impl AzaleaRead for ChunkPos {
467    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
468        let long = u64::azalea_read(buf)?;
469        Ok(ChunkPos::from(long))
470    }
471}
472impl AzaleaWrite for ChunkPos {
473    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
474        u64::from(*self).azalea_write(buf)?;
475        Ok(())
476    }
477}
478
479impl Hash for ChunkPos {
480    #[inline]
481    fn hash<H: Hasher>(&self, state: &mut H) {
482        // optimized hash that only calls hash once
483        u64::from(*self).hash(state);
484    }
485}
486/// nohash_hasher lets us have IntMap<ChunkPos, _> which is significantly faster
487/// than a normal HashMap
488impl nohash_hasher::IsEnabled for ChunkPos {}
489
490/// The coordinates of a chunk section in the world.
491#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
492pub struct ChunkSectionPos {
493    pub x: i32,
494    pub y: i32,
495    pub z: i32,
496}
497vec3_impl!(ChunkSectionPos, i32);
498
499impl ChunkSectionPos {
500    pub fn block_to_section_coord(block: i32) -> i32 {
501        block >> 4
502    }
503}
504
505/// The coordinates of a block inside a chunk.
506#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
507pub struct ChunkBlockPos {
508    pub x: u8,
509    pub y: i32,
510    pub z: u8,
511}
512
513impl ChunkBlockPos {
514    pub fn new(x: u8, y: i32, z: u8) -> Self {
515        ChunkBlockPos { x, y, z }
516    }
517}
518
519impl Hash for ChunkBlockPos {
520    // optimized hash that only calls hash once
521    #[inline]
522    fn hash<H: Hasher>(&self, state: &mut H) {
523        u64::from(*self).hash(state);
524    }
525}
526impl From<ChunkBlockPos> for u64 {
527    #[inline]
528    fn from(pos: ChunkBlockPos) -> Self {
529        // convert to u64
530        let mut val: u64 = 0;
531        // first 32 bits are y
532        val |= pos.y as u64;
533        // next 8 bits are z
534        val |= (pos.z as u64) << 32;
535        // last 8 bits are x
536        val |= (pos.x as u64) << 40;
537        val
538    }
539}
540impl nohash_hasher::IsEnabled for ChunkBlockPos {}
541
542/// The coordinates of a block inside a chunk section. Each coordinate must be
543/// in the range [0, 15].
544#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
545pub struct ChunkSectionBlockPos {
546    pub x: u8,
547    pub y: u8,
548    pub z: u8,
549}
550vec3_impl!(ChunkSectionBlockPos, u8);
551
552impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
553    type Output = BlockPos;
554
555    fn add(self, rhs: ChunkSectionBlockPos) -> Self::Output {
556        BlockPos::new(
557            self.x * 16 + rhs.x as i32,
558            self.y * 16 + rhs.y as i32,
559            self.z * 16 + rhs.z as i32,
560        )
561    }
562}
563impl Hash for ChunkSectionBlockPos {
564    // optimized hash that only calls hash once
565    #[inline]
566    fn hash<H: Hasher>(&self, state: &mut H) {
567        u16::from(*self).hash(state);
568    }
569}
570
571impl From<ChunkSectionBlockPos> for u16 {
572    #[inline]
573    fn from(pos: ChunkSectionBlockPos) -> Self {
574        // (pos.z as u16) | ((pos.y as u16) << 4) | ((pos.x as u16) << 8)
575        ((((pos.y as u16) << 4) | pos.z as u16) << 4) | pos.x as u16
576    }
577}
578impl nohash_hasher::IsEnabled for ChunkSectionBlockPos {}
579
580/// A block pos with an attached world
581#[derive(Debug, Clone, PartialEq)]
582pub struct GlobalPos {
583    // this is actually a ResourceKey in Minecraft, but i don't think it matters?
584    pub world: ResourceLocation,
585    pub pos: BlockPos,
586}
587
588impl From<&BlockPos> for ChunkPos {
589    #[inline]
590    fn from(pos: &BlockPos) -> Self {
591        ChunkPos {
592            x: pos.x >> 4,
593            z: pos.z >> 4,
594        }
595    }
596}
597impl From<BlockPos> for ChunkPos {
598    #[inline]
599    fn from(pos: BlockPos) -> Self {
600        ChunkPos {
601            x: pos.x >> 4,
602            z: pos.z >> 4,
603        }
604    }
605}
606
607impl From<BlockPos> for ChunkSectionPos {
608    #[inline]
609    fn from(pos: BlockPos) -> Self {
610        ChunkSectionPos {
611            x: pos.x >> 4,
612            y: pos.y >> 4,
613            z: pos.z >> 4,
614        }
615    }
616}
617impl From<&BlockPos> for ChunkSectionPos {
618    #[inline]
619    fn from(pos: &BlockPos) -> Self {
620        ChunkSectionPos {
621            x: pos.x >> 4,
622            y: pos.y >> 4,
623            z: pos.z >> 4,
624        }
625    }
626}
627
628impl From<ChunkSectionPos> for ChunkPos {
629    fn from(pos: ChunkSectionPos) -> Self {
630        ChunkPos { x: pos.x, z: pos.z }
631    }
632}
633impl From<&Vec3> for ChunkSectionPos {
634    fn from(pos: &Vec3) -> Self {
635        ChunkSectionPos::from(&BlockPos::from(pos))
636    }
637}
638impl From<Vec3> for ChunkSectionPos {
639    fn from(pos: Vec3) -> Self {
640        ChunkSectionPos::from(&pos)
641    }
642}
643
644impl From<&BlockPos> for ChunkBlockPos {
645    #[inline]
646    fn from(pos: &BlockPos) -> Self {
647        ChunkBlockPos {
648            x: (pos.x & 0xF) as u8,
649            y: pos.y,
650            z: (pos.z & 0xF) as u8,
651        }
652    }
653}
654impl From<BlockPos> for ChunkBlockPos {
655    #[inline]
656    fn from(pos: BlockPos) -> Self {
657        ChunkBlockPos {
658            x: (pos.x & 0xF) as u8,
659            y: pos.y,
660            z: (pos.z & 0xF) as u8,
661        }
662    }
663}
664
665impl From<BlockPos> for ChunkSectionBlockPos {
666    #[inline]
667    fn from(pos: BlockPos) -> Self {
668        ChunkSectionBlockPos {
669            x: (pos.x & 0xF) as u8,
670            y: (pos.y & 0xF) as u8,
671            z: (pos.z & 0xF) as u8,
672        }
673    }
674}
675
676impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
677    #[inline]
678    fn from(pos: &ChunkBlockPos) -> Self {
679        ChunkSectionBlockPos {
680            x: pos.x,
681            y: (pos.y & 0xF) as u8,
682            z: pos.z,
683        }
684    }
685}
686impl From<&Vec3> for BlockPos {
687    #[inline]
688    fn from(pos: &Vec3) -> Self {
689        BlockPos {
690            x: pos.x.floor() as i32,
691            y: pos.y.floor() as i32,
692            z: pos.z.floor() as i32,
693        }
694    }
695}
696impl From<Vec3> for BlockPos {
697    #[inline]
698    fn from(pos: Vec3) -> Self {
699        BlockPos::from(&pos)
700    }
701}
702
703impl From<&Vec3> for ChunkPos {
704    fn from(pos: &Vec3) -> Self {
705        ChunkPos::from(&BlockPos::from(pos))
706    }
707}
708impl From<Vec3> for ChunkPos {
709    fn from(pos: Vec3) -> Self {
710        ChunkPos::from(&pos)
711    }
712}
713
714impl From<&Vec3> for ChunkBlockPos {
715    fn from(pos: &Vec3) -> Self {
716        ChunkBlockPos::from(&BlockPos::from(pos))
717    }
718}
719impl From<Vec3> for ChunkBlockPos {
720    fn from(pos: Vec3) -> Self {
721        ChunkBlockPos::from(&pos)
722    }
723}
724
725impl fmt::Display for BlockPos {
726    /// Display a block position as `x y z`.
727    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
728        write!(f, "{} {} {}", self.x, self.y, self.z)
729    }
730}
731impl fmt::Display for Vec3 {
732    /// Display a position as `x y z`.
733    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734        write!(f, "{} {} {}", self.x, self.y, self.z)
735    }
736}
737
738const PACKED_X_LENGTH: u64 = 1 + 25; // minecraft does something a bit more complicated to get this 25
739const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
740const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
741const PACKED_X_MASK: u64 = (1 << PACKED_X_LENGTH) - 1;
742const PACKED_Y_MASK: u64 = (1 << PACKED_Y_LENGTH) - 1;
743const PACKED_Z_MASK: u64 = (1 << PACKED_Z_LENGTH) - 1;
744const Z_OFFSET: u64 = PACKED_Y_LENGTH;
745const X_OFFSET: u64 = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
746
747impl AzaleaRead for BlockPos {
748    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
749        let val = i64::azalea_read(buf)?;
750        let x = (val << (64 - X_OFFSET - PACKED_X_LENGTH) >> (64 - PACKED_X_LENGTH)) as i32;
751        let y = (val << (64 - PACKED_Y_LENGTH) >> (64 - PACKED_Y_LENGTH)) as i32;
752        let z = (val << (64 - Z_OFFSET - PACKED_Z_LENGTH) >> (64 - PACKED_Z_LENGTH)) as i32;
753        Ok(BlockPos { x, y, z })
754    }
755}
756
757impl AzaleaRead for GlobalPos {
758    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
759        Ok(GlobalPos {
760            world: ResourceLocation::azalea_read(buf)?,
761            pos: BlockPos::azalea_read(buf)?,
762        })
763    }
764}
765
766impl AzaleaRead for ChunkSectionPos {
767    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
768        let long = i64::azalea_read(buf)?;
769        Ok(ChunkSectionPos {
770            x: (long >> 42) as i32,
771            y: (long << 44 >> 44) as i32,
772            z: (long << 22 >> 42) as i32,
773        })
774    }
775}
776
777impl AzaleaWrite for BlockPos {
778    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
779        let mut val: u64 = 0;
780        val |= ((self.x as u64) & PACKED_X_MASK) << X_OFFSET;
781        val |= (self.y as u64) & PACKED_Y_MASK;
782        val |= ((self.z as u64) & PACKED_Z_MASK) << Z_OFFSET;
783        val.azalea_write(buf)
784    }
785}
786
787impl AzaleaWrite for GlobalPos {
788    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
789        ResourceLocation::azalea_write(&self.world, buf)?;
790        BlockPos::azalea_write(&self.pos, buf)?;
791
792        Ok(())
793    }
794}
795
796impl AzaleaWrite for ChunkSectionPos {
797    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
798        let long = (((self.x & 0x3FFFFF) as i64) << 42)
799            | (self.y & 0xFFFFF) as i64
800            | (((self.z & 0x3FFFFF) as i64) << 20);
801        long.azalea_write(buf)?;
802        Ok(())
803    }
804}
805
806fn parse_three_values<T>(s: &str) -> Result<[T; 3], &'static str>
807where
808    T: FromStr,
809    <T as FromStr>::Err: fmt::Debug,
810{
811    let parts = s.split_whitespace().collect::<Vec<_>>();
812    if parts.len() != 3 {
813        return Err("Expected three values");
814    }
815
816    let x = parts[0].parse().map_err(|_| "Invalid X value")?;
817    let y = parts[1].parse().map_err(|_| "Invalid Y value")?;
818    let z = parts[2].parse().map_err(|_| "Invalid Z value")?;
819
820    Ok([x, y, z])
821}
822
823/// Parses a string in the format "X Y Z" into a BlockPos.
824///
825/// The input string should contain three integer values separated by spaces,
826/// representing the x, y, and z components of the vector respectively.
827/// This can be used to parse user input or from `BlockPos::to_string`.
828impl FromStr for BlockPos {
829    type Err = &'static str;
830
831    fn from_str(s: &str) -> Result<Self, Self::Err> {
832        let [x, y, z] = parse_three_values::<i32>(s)?;
833        Ok(BlockPos { x, y, z })
834    }
835}
836
837/// Parses a string in the format "X Y Z" into a Vec3.
838///
839/// The input string should contain three floating-point values separated by
840/// spaces, representing the x, y, and z components of the vector respectively.
841/// This can be used to parse user input or from `Vec3::to_string`.
842impl FromStr for Vec3 {
843    type Err = &'static str;
844
845    fn from_str(s: &str) -> Result<Self, Self::Err> {
846        let [x, y, z] = parse_three_values::<f64>(s)?;
847        Ok(Vec3 { x, y, z })
848    }
849}
850
851#[cfg(test)]
852mod tests {
853    use super::*;
854
855    #[test]
856    fn test_from_block_pos_to_chunk_pos() {
857        let block_pos = BlockPos::new(5, 78, -2);
858        let chunk_pos = ChunkPos::from(&block_pos);
859        assert_eq!(chunk_pos, ChunkPos::new(0, -1));
860    }
861
862    #[test]
863    fn test_from_block_pos_to_chunk_block_pos() {
864        let block_pos = BlockPos::new(5, 78, -2);
865        let chunk_block_pos = ChunkBlockPos::from(&block_pos);
866        assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14));
867    }
868
869    #[test]
870    fn test_from_entity_pos_to_block_pos() {
871        let entity_pos = Vec3 {
872            x: 31.5,
873            y: 80.0,
874            z: -16.1,
875        };
876        let block_pos = BlockPos::from(&entity_pos);
877        assert_eq!(block_pos, BlockPos::new(31, 80, -17));
878    }
879
880    #[test]
881    fn test_from_entity_pos_to_chunk_pos() {
882        let entity_pos = Vec3 {
883            x: 31.5,
884            y: 80.0,
885            z: -16.1,
886        };
887        let chunk_pos = ChunkPos::from(&entity_pos);
888        assert_eq!(chunk_pos, ChunkPos::new(1, -2));
889    }
890
891    #[test]
892    fn test_read_blockpos_from() {
893        let mut buf = Vec::new();
894        13743895338965u64.azalea_write(&mut buf).unwrap();
895        let mut buf = Cursor::new(&buf[..]);
896        let block_pos = BlockPos::azalea_read(&mut buf).unwrap();
897        assert_eq!(block_pos, BlockPos::new(49, -43, -3));
898    }
899
900    #[test]
901    fn test_into_chunk_section_block_pos() {
902        let block_pos = BlockPos::new(0, -60, 0);
903        assert_eq!(
904            ChunkSectionBlockPos::from(block_pos),
905            ChunkSectionBlockPos::new(0, 4, 0)
906        );
907    }
908
909    #[test]
910    fn test_read_chunk_pos_from() {
911        let mut buf = Vec::new();
912        ChunkPos::new(2, -1).azalea_write(&mut buf).unwrap();
913        let mut buf = Cursor::new(&buf[..]);
914        let chunk_pos = ChunkPos::from(u64::azalea_read(&mut buf).unwrap());
915        assert_eq!(chunk_pos, ChunkPos::new(2, -1));
916    }
917}