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