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