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