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, BufReadError};
16use azalea_registry::identifier::Identifier;
17#[cfg(feature = "serde")]
18use serde::Serializer;
19use simdnbt::borrow::NbtTag;
20
21use crate::{direction::Direction, math};
22
23macro_rules! vec3_impl {
24    ($name:ident, $type:ty) => {
25        impl $name {
26            /// The position where x, y, and z are all 0.
27            pub const ZERO: Self = Self {
28                x: 0 as $type,
29                y: 0 as $type,
30                z: 0 as $type,
31            };
32
33            #[inline]
34            pub const fn new(x: $type, y: $type, z: $type) -> Self {
35                Self { x, y, z }
36            }
37
38            /// Get the distance of this vector to the origin by doing `x^2 + y^2 +
39            /// z^2`.
40            #[inline]
41            pub fn length_squared(&self) -> $type {
42                self.x * self.x + self.y * self.y + self.z * self.z
43            }
44
45            /// Get the squared distance from this position to another position.
46            /// Equivalent to `(self - other).length_squared()`.
47            #[inline]
48            pub fn distance_squared_to(self, other: Self) -> $type {
49                (self - other).length_squared()
50            }
51
52            #[inline]
53            pub fn horizontal_distance_squared(&self) -> $type {
54                self.x * self.x + self.z * self.z
55            }
56
57            #[inline]
58            pub fn horizontal_distance_squared_to(self, other: Self) -> $type {
59                (self - other).horizontal_distance_squared()
60            }
61
62            /// Return a new instance of this position with the y coordinate
63            /// decreased by the given number.
64            #[inline]
65            pub fn down(&self, y: $type) -> Self {
66                Self {
67                    x: self.x,
68                    y: self.y - y,
69                    z: self.z,
70                }
71            }
72            /// Return a new instance of this position with the y coordinate
73            /// increased by the given number.
74            #[inline]
75            pub fn up(&self, y: $type) -> Self {
76                Self {
77                    x: self.x,
78                    y: self.y + y,
79                    z: self.z,
80                }
81            }
82
83            /// Return a new instance of this position with the z coordinate subtracted
84            /// by the given number.
85            #[inline]
86            pub fn north(&self, z: $type) -> Self {
87                Self {
88                    x: self.x,
89                    y: self.y,
90                    z: self.z - z,
91                }
92            }
93            /// Return a new instance of this position with the x coordinate increased
94            /// by the given number.
95            #[inline]
96            pub fn east(&self, x: $type) -> Self {
97                Self {
98                    x: self.x + x,
99                    y: self.y,
100                    z: self.z,
101                }
102            }
103            /// Return a new instance of this position with the z coordinate increased
104            /// by the given number.
105            #[inline]
106            pub fn south(&self, z: $type) -> Self {
107                Self {
108                    x: self.x,
109                    y: self.y,
110                    z: self.z + z,
111                }
112            }
113            /// Return a new instance of this position with the x coordinate subtracted
114            /// by the given number.
115            #[inline]
116            pub fn west(&self, x: $type) -> Self {
117                Self {
118                    x: self.x - x,
119                    y: self.y,
120                    z: self.z,
121                }
122            }
123
124            #[inline]
125            pub fn dot(&self, other: Self) -> $type {
126                self.x * other.x + self.y * other.y + self.z * other.z
127            }
128
129            /// Make a new position with the lower coordinates for each axis.
130            pub fn min(&self, other: Self) -> Self {
131                Self {
132                    x: self.x.min(other.x),
133                    y: self.x.min(other.y),
134                    z: self.x.min(other.z),
135                }
136            }
137            /// Make a new position with the higher coordinates for each axis.
138            pub fn max(&self, other: Self) -> Self {
139                Self {
140                    x: self.x.max(other.x),
141                    y: self.x.max(other.y),
142                    z: self.x.max(other.z),
143                }
144            }
145
146            /// Replace the Y with 0.
147            #[inline]
148            pub fn xz(&self) -> Self {
149                Self {
150                    x: self.x,
151                    y: <$type>::default(),
152                    z: self.z,
153                }
154            }
155
156            pub fn with_x(&self, x: $type) -> Self {
157                Self { x, ..*self }
158            }
159            pub fn with_y(&self, y: $type) -> Self {
160                Self { y, ..*self }
161            }
162            pub fn with_z(&self, z: $type) -> Self {
163                Self { z, ..*self }
164            }
165        }
166
167        impl Add for &$name {
168            type Output = $name;
169
170            #[inline]
171            fn add(self, rhs: Self) -> Self::Output {
172                $name {
173                    x: self.x + rhs.x,
174                    y: self.y + rhs.y,
175                    z: self.z + rhs.z,
176                }
177            }
178        }
179        impl Add for $name {
180            type Output = $name;
181
182            #[inline]
183            fn add(self, rhs: Self) -> Self::Output {
184                (&self).add(&rhs)
185            }
186        }
187        impl Add<$type> for $name {
188            type Output = Self;
189
190            #[inline]
191            fn add(self, rhs: $type) -> Self::Output {
192                Self {
193                    x: self.x + rhs,
194                    y: self.y + rhs,
195                    z: self.z + rhs,
196                }
197            }
198        }
199
200        impl AddAssign for $name {
201            #[inline]
202            fn add_assign(&mut self, rhs: Self) {
203                self.x += rhs.x;
204                self.y += rhs.y;
205                self.z += rhs.z;
206            }
207        }
208        impl Rem<$type> for $name {
209            type Output = Self;
210
211            #[inline]
212            fn rem(self, rhs: $type) -> Self::Output {
213                Self {
214                    x: self.x % rhs,
215                    y: self.y % rhs,
216                    z: self.z % rhs,
217                }
218            }
219        }
220
221        impl Sub for &$name {
222            type Output = $name;
223
224            /// Find the difference between two positions.
225            #[inline]
226            fn sub(self, other: Self) -> Self::Output {
227                Self::Output {
228                    x: self.x - other.x,
229                    y: self.y - other.y,
230                    z: self.z - other.z,
231                }
232            }
233        }
234        impl Sub for $name {
235            type Output = Self;
236
237            #[inline]
238            fn sub(self, other: Self) -> Self::Output {
239                (&self).sub(&other)
240            }
241        }
242
243        impl Mul<$type> for $name {
244            type Output = Self;
245
246            #[inline]
247            fn mul(self, multiplier: $type) -> Self::Output {
248                Self {
249                    x: self.x * multiplier,
250                    y: self.y * multiplier,
251                    z: self.z * multiplier,
252                }
253            }
254        }
255        impl MulAssign<$type> for $name {
256            #[inline]
257            fn mul_assign(&mut self, multiplier: $type) {
258                self.x *= multiplier;
259                self.y *= multiplier;
260                self.z *= multiplier;
261            }
262        }
263
264        impl Div<$type> for $name {
265            type Output = Self;
266
267            #[inline]
268            fn div(self, divisor: $type) -> Self::Output {
269                Self {
270                    x: self.x / divisor,
271                    y: self.y / divisor,
272                    z: self.z / divisor,
273                }
274            }
275        }
276        impl DivAssign<$type> for $name {
277            #[inline]
278            fn div_assign(&mut self, divisor: $type) {
279                self.x /= divisor;
280                self.y /= divisor;
281                self.z /= divisor;
282            }
283        }
284
285        impl From<($type, $type, $type)> for $name {
286            #[inline]
287            fn from(pos: ($type, $type, $type)) -> Self {
288                Self::new(pos.0, pos.1, pos.2)
289            }
290        }
291        impl From<&($type, $type, $type)> for $name {
292            #[inline]
293            fn from(pos: &($type, $type, $type)) -> Self {
294                Self::new(pos.0, pos.1, pos.2)
295            }
296        }
297        impl From<$name> for ($type, $type, $type) {
298            #[inline]
299            fn from(pos: $name) -> Self {
300                (pos.x, pos.y, pos.z)
301            }
302        }
303    };
304}
305
306/// Used to represent an exact position in the world where an entity could be.
307///
308/// For blocks, [`BlockPos`] is used instead.
309#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
310#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
311pub struct Vec3 {
312    pub x: f64,
313    pub y: f64,
314    pub z: f64,
315}
316vec3_impl!(Vec3, f64);
317impl simdnbt::FromNbtTag for Vec3 {
318    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
319        let pos = tag.list()?;
320        if let Some(pos) = pos.doubles() {
321            let [x, y, z] = <[f64; 3]>::try_from(pos).ok()?;
322            Some(Self { x, y, z })
323        } else if let Some(pos) = pos.floats() {
324            // used on hypixel
325            let [x, y, z] = <[f32; 3]>::try_from(pos).ok()?.map(|f| f as f64);
326            Some(Self { x, y, z })
327        } else {
328            None
329        }
330    }
331}
332
333impl Vec3 {
334    /// Get the distance of this vector to the origin by doing
335    /// `sqrt(x^2 + y^2 + z^2)`.
336    pub fn length(&self) -> f64 {
337        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
338    }
339
340    /// Get the distance from this position to another position.
341    /// Equivalent to `(self - other).length()`.
342    pub fn distance_to(self, other: Self) -> f64 {
343        (self - other).length()
344    }
345
346    pub fn x_rot(self, radians: f32) -> Vec3 {
347        let x_delta = math::cos(radians);
348        let y_delta = math::sin(radians);
349        let x = self.x;
350        let y = self.y * (x_delta as f64) + self.z * (y_delta as f64);
351        let z = self.z * (x_delta as f64) - self.y * (y_delta as f64);
352        Vec3 { x, y, z }
353    }
354    pub fn y_rot(self, radians: f32) -> Vec3 {
355        let x_delta = math::cos(radians);
356        let y_delta = math::sin(radians);
357        let x = self.x * (x_delta as f64) + self.z * (y_delta as f64);
358        let y = self.y;
359        let z = self.z * (x_delta as f64) - self.x * (y_delta as f64);
360        Vec3 { x, y, z }
361    }
362
363    pub fn to_block_pos_floor(&self) -> BlockPos {
364        BlockPos {
365            x: self.x.floor() as i32,
366            y: self.y.floor() as i32,
367            z: self.z.floor() as i32,
368        }
369    }
370    pub fn to_block_pos_ceil(&self) -> BlockPos {
371        BlockPos {
372            x: self.x.ceil() as i32,
373            y: self.y.ceil() as i32,
374            z: self.z.ceil() as i32,
375        }
376    }
377
378    /// Whether the distance between this point and `other` is less than
379    /// `range`.
380    pub fn closer_than(&self, other: Vec3, range: f64) -> bool {
381        self.distance_squared_to(other) < range.powi(2)
382    }
383}
384
385/// A lower precision [`Vec3`], used for some fields in entity metadata.
386#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
387pub struct Vec3f32 {
388    pub x: f32,
389    pub y: f32,
390    pub z: f32,
391}
392impl From<Vec3f32> for Vec3 {
393    fn from(v: Vec3f32) -> Self {
394        Vec3 {
395            x: v.x as f64,
396            y: v.y as f64,
397            z: v.z as f64,
398        }
399    }
400}
401impl From<Vec3> for Vec3f32 {
402    fn from(v: Vec3) -> Self {
403        Vec3f32 {
404            x: v.x as f32,
405            y: v.y as f32,
406            z: v.z as f32,
407        }
408    }
409}
410
411/// The coordinates of a block in the world.
412///
413/// For entities (if the coordinates are floating-point), use [`Vec3`] instead.
414/// To convert a `BlockPos` to a `Vec3`, you'll usually want [`Self::center`].
415#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
416pub struct BlockPos {
417    pub x: i32,
418    pub y: i32,
419    pub z: i32,
420}
421vec3_impl!(BlockPos, i32);
422
423impl BlockPos {
424    /// Get the absolute center of a block position by adding 0.5 to each
425    /// coordinate.
426    pub fn center(&self) -> Vec3 {
427        Vec3 {
428            x: self.x as f64 + 0.5,
429            y: self.y as f64 + 0.5,
430            z: self.z as f64 + 0.5,
431        }
432    }
433
434    /// Get the center of the bottom of a block position by adding 0.5 to the x
435    /// and z coordinates.
436    pub fn center_bottom(&self) -> Vec3 {
437        Vec3 {
438            x: self.x as f64 + 0.5,
439            y: self.y as f64,
440            z: self.z as f64 + 0.5,
441        }
442    }
443
444    /// Convert the block position into a Vec3 without centering it.
445    pub fn to_vec3_floored(&self) -> Vec3 {
446        Vec3 {
447            x: self.x as f64,
448            y: self.y as f64,
449            z: self.z as f64,
450        }
451    }
452
453    /// Get the distance of this vector from the origin by doing `x + y + z`.
454    pub fn length_manhattan(&self) -> u32 {
455        (self.x.abs() + self.y.abs() + self.z.abs()) as u32
456    }
457
458    /// Add or subtract `1` to one of this position's coordinates, depending on
459    /// the direction.
460    ///
461    /// ```
462    /// # use azalea_core::{position::BlockPos, direction::Direction};
463    /// let pos = BlockPos::new(10, 10, 10);
464    /// assert_eq!(
465    ///     pos.offset_with_direction(Direction::North),
466    ///     BlockPos::new(10, 10, 9)
467    /// );
468    /// ```
469    pub fn offset_with_direction(self, direction: Direction) -> Self {
470        self + direction.normal()
471    }
472
473    /// Get the distance (as an f64) of this BlockPos to the origin by
474    /// doing `sqrt(x^2 + y^2 + z^2)`.
475    pub fn length(&self) -> f64 {
476        f64::sqrt((self.x * self.x + self.y * self.y + self.z * self.z) as f64)
477    }
478
479    /// Get the distance (as an f64) from this position to another position.
480    /// Equivalent to `(self - other).length()`.
481    ///
482    /// Note that if you're using this in a hot path, it may be more performant
483    /// to use [`BlockPos::distance_squared_to`] instead (by squaring the other
484    /// side in the comparison).
485    pub fn distance_to(self, other: Self) -> f64 {
486        (self - other).length()
487    }
488}
489#[cfg(feature = "serde")]
490impl serde::Serialize for BlockPos {
491    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
492    where
493        S: Serializer,
494    {
495        // makes sure it gets serialized correctly for the checksum
496
497        use crate::codec_utils::IntArray;
498        IntArray([self.x, self.y, self.z]).serialize(serializer)
499    }
500}
501#[cfg(feature = "serde")]
502impl<'de> serde::Deserialize<'de> for BlockPos {
503    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
504    where
505        D: serde::Deserializer<'de>,
506    {
507        let [x, y, z] = <[i32; 3]>::deserialize(deserializer)?;
508        Ok(BlockPos { x, y, z })
509    }
510}
511
512/// An arbitrary position that's represented as 32-bit integers.
513///
514/// This is similar to [`BlockPos`], but isn't limited to representing block
515/// positions and can represent a larger range of numbers.
516#[derive(AzBuf, Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
517pub struct Vec3i {
518    #[var]
519    pub x: i32,
520    #[var]
521    pub y: i32,
522    #[var]
523    pub z: i32,
524}
525vec3_impl!(Vec3i, i32);
526impl simdnbt::FromNbtTag for Vec3i {
527    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
528        let pos = tag.list()?.ints()?;
529        let [x, y, z] = <[i32; 3]>::try_from(pos).ok()?;
530        Some(Self { x, y, z })
531    }
532}
533
534/// Chunk coordinates are used to represent where a chunk is in the world.
535///
536/// You can convert the x and z to block coordinates by multiplying them by 16.
537#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
538pub struct ChunkPos {
539    pub x: i32,
540    pub z: i32,
541}
542impl ChunkPos {
543    pub fn new(x: i32, z: i32) -> Self {
544        ChunkPos { x, z }
545    }
546}
547impl Add<ChunkPos> for ChunkPos {
548    type Output = Self;
549
550    fn add(self, rhs: Self) -> Self::Output {
551        Self {
552            x: self.x + rhs.x,
553            z: self.z + rhs.z,
554        }
555    }
556}
557impl Add<ChunkBlockPos> for ChunkPos {
558    type Output = BlockPos;
559
560    fn add(self, rhs: ChunkBlockPos) -> Self::Output {
561        BlockPos {
562            x: self.x * 16 + rhs.x as i32,
563            y: rhs.y,
564            z: self.z * 16 + rhs.z as i32,
565        }
566    }
567}
568
569// reading ChunkPos is done in reverse, so z first and then x
570// ........
571// mojang why
572impl From<ChunkPos> for u64 {
573    #[inline]
574    fn from(pos: ChunkPos) -> Self {
575        (pos.x as u64) | ((pos.z as u64) << 32)
576    }
577}
578impl From<u64> for ChunkPos {
579    #[inline]
580    fn from(pos: u64) -> Self {
581        ChunkPos {
582            x: (pos) as i32,
583            z: (pos >> 32) as i32,
584        }
585    }
586}
587impl AzBuf for ChunkPos {
588    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
589        let long = u64::azalea_read(buf)?;
590        Ok(ChunkPos::from(long))
591    }
592    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
593        u64::from(*self).azalea_write(buf)?;
594        Ok(())
595    }
596}
597
598impl Hash for ChunkPos {
599    #[inline]
600    fn hash<H: Hasher>(&self, state: &mut H) {
601        // optimized hash that only calls hash once
602        u64::from(*self).hash(state);
603    }
604}
605/// `nohash_hasher` lets us have IntMap<ChunkPos, _> which is significantly
606/// faster than a normal HashMap
607impl nohash_hasher::IsEnabled for ChunkPos {}
608
609/// The coordinates of a chunk section in the world.
610#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
611pub struct ChunkSectionPos {
612    pub x: i32,
613    pub y: i32,
614    pub z: i32,
615}
616vec3_impl!(ChunkSectionPos, i32);
617
618impl ChunkSectionPos {
619    pub fn block_to_section_coord(block: i32) -> i32 {
620        block >> 4
621    }
622}
623
624/// The coordinates of a block inside a chunk.
625#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
626pub struct ChunkBlockPos {
627    pub x: u8,
628    pub y: i32,
629    pub z: u8,
630}
631
632impl ChunkBlockPos {
633    pub fn new(x: u8, y: i32, z: u8) -> Self {
634        ChunkBlockPos { x, y, z }
635    }
636}
637
638impl Hash for ChunkBlockPos {
639    // optimized hash that only calls hash once
640    #[inline]
641    fn hash<H: Hasher>(&self, state: &mut H) {
642        u64::from(*self).hash(state);
643    }
644}
645impl From<ChunkBlockPos> for u64 {
646    #[inline]
647    fn from(pos: ChunkBlockPos) -> Self {
648        // convert to u64
649        let mut val: u64 = 0;
650        // first 32 bits are y
651        val |= pos.y as u64;
652        // next 8 bits are z
653        val |= (pos.z as u64) << 32;
654        // last 8 bits are x
655        val |= (pos.x as u64) << 40;
656        val
657    }
658}
659impl nohash_hasher::IsEnabled for ChunkBlockPos {}
660
661/// The coordinates of a block inside of a chunk section.
662///
663/// Each coordinate should be in the range 0..=15.
664#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
665pub struct ChunkSectionBlockPos {
666    pub x: u8,
667    pub y: u8,
668    pub z: u8,
669}
670vec3_impl!(ChunkSectionBlockPos, u8);
671
672/// The coordinates of a biome inside of a chunk section.
673///
674/// Each coordinate should be in the range 0..=3.
675#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
676pub struct ChunkSectionBiomePos {
677    pub x: u8,
678    pub y: u8,
679    pub z: u8,
680}
681impl From<&ChunkBiomePos> for ChunkSectionBiomePos {
682    #[inline]
683    fn from(pos: &ChunkBiomePos) -> Self {
684        ChunkSectionBiomePos {
685            x: pos.x,
686            y: (pos.y & 0b11) as u8,
687            z: pos.z,
688        }
689    }
690}
691impl From<ChunkBiomePos> for ChunkSectionBiomePos {
692    #[inline]
693    fn from(pos: ChunkBiomePos) -> Self {
694        Self::from(&pos)
695    }
696}
697vec3_impl!(ChunkSectionBiomePos, u8);
698
699/// The coordinates of a biome inside a chunk.
700///
701/// Biomes are 4x4 blocks.
702#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
703pub struct ChunkBiomePos {
704    pub x: u8,
705    pub y: i32,
706    pub z: u8,
707}
708impl From<&BlockPos> for ChunkBiomePos {
709    #[inline]
710    fn from(pos: &BlockPos) -> Self {
711        ChunkBiomePos::from(&ChunkBlockPos::from(pos))
712    }
713}
714impl From<BlockPos> for ChunkBiomePos {
715    #[inline]
716    fn from(pos: BlockPos) -> Self {
717        ChunkBiomePos::from(&ChunkBlockPos::from(pos))
718    }
719}
720impl From<&ChunkBlockPos> for ChunkBiomePos {
721    #[inline]
722    fn from(pos: &ChunkBlockPos) -> Self {
723        ChunkBiomePos {
724            x: pos.x >> 2,
725            y: pos.y >> 2,
726            z: pos.z >> 2,
727        }
728    }
729}
730
731impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
732    type Output = BlockPos;
733
734    fn add(self, rhs: ChunkSectionBlockPos) -> Self::Output {
735        BlockPos::new(
736            self.x * 16 + rhs.x as i32,
737            self.y * 16 + rhs.y as i32,
738            self.z * 16 + rhs.z as i32,
739        )
740    }
741}
742impl Hash for ChunkSectionBlockPos {
743    // optimized hash that only calls hash once
744    #[inline]
745    fn hash<H: Hasher>(&self, state: &mut H) {
746        u16::from(*self).hash(state);
747    }
748}
749
750impl From<ChunkSectionBlockPos> for u16 {
751    #[inline]
752    fn from(pos: ChunkSectionBlockPos) -> Self {
753        // (pos.z as u16) | ((pos.y as u16) << 4) | ((pos.x as u16) << 8)
754        ((((pos.y as u16) << 4) | pos.z as u16) << 4) | pos.x as u16
755    }
756}
757impl nohash_hasher::IsEnabled for ChunkSectionBlockPos {}
758
759/// A block pos with an attached world
760#[cfg_attr(feature = "serde", derive(serde::Serialize))]
761#[derive(Clone, Debug, PartialEq)]
762pub struct GlobalPos {
763    // this is actually a ResourceKey in Minecraft, but i don't think it matters?
764    pub dimension: Identifier,
765    pub pos: BlockPos,
766}
767
768impl From<&BlockPos> for ChunkPos {
769    #[inline]
770    fn from(pos: &BlockPos) -> Self {
771        ChunkPos {
772            x: pos.x >> 4,
773            z: pos.z >> 4,
774        }
775    }
776}
777impl From<BlockPos> for ChunkPos {
778    #[inline]
779    fn from(pos: BlockPos) -> Self {
780        ChunkPos {
781            x: pos.x >> 4,
782            z: pos.z >> 4,
783        }
784    }
785}
786
787impl From<BlockPos> for ChunkSectionPos {
788    #[inline]
789    fn from(pos: BlockPos) -> Self {
790        ChunkSectionPos {
791            x: pos.x >> 4,
792            y: pos.y >> 4,
793            z: pos.z >> 4,
794        }
795    }
796}
797impl From<&BlockPos> for ChunkSectionPos {
798    #[inline]
799    fn from(pos: &BlockPos) -> Self {
800        ChunkSectionPos {
801            x: pos.x >> 4,
802            y: pos.y >> 4,
803            z: pos.z >> 4,
804        }
805    }
806}
807
808impl From<ChunkSectionPos> for ChunkPos {
809    fn from(pos: ChunkSectionPos) -> Self {
810        ChunkPos { x: pos.x, z: pos.z }
811    }
812}
813impl From<&Vec3> for ChunkSectionPos {
814    fn from(pos: &Vec3) -> Self {
815        ChunkSectionPos::from(&BlockPos::from(pos))
816    }
817}
818impl From<Vec3> for ChunkSectionPos {
819    fn from(pos: Vec3) -> Self {
820        ChunkSectionPos::from(&pos)
821    }
822}
823
824impl From<&BlockPos> for ChunkBlockPos {
825    #[inline]
826    fn from(pos: &BlockPos) -> Self {
827        ChunkBlockPos {
828            x: (pos.x & 0xF) as u8,
829            y: pos.y,
830            z: (pos.z & 0xF) as u8,
831        }
832    }
833}
834impl From<BlockPos> for ChunkBlockPos {
835    #[inline]
836    fn from(pos: BlockPos) -> Self {
837        ChunkBlockPos {
838            x: (pos.x & 0xF) as u8,
839            y: pos.y,
840            z: (pos.z & 0xF) as u8,
841        }
842    }
843}
844
845impl From<BlockPos> for ChunkSectionBlockPos {
846    #[inline]
847    fn from(pos: BlockPos) -> Self {
848        ChunkSectionBlockPos {
849            x: (pos.x & 0xF) as u8,
850            y: (pos.y & 0xF) as u8,
851            z: (pos.z & 0xF) as u8,
852        }
853    }
854}
855
856impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
857    #[inline]
858    fn from(pos: &ChunkBlockPos) -> Self {
859        ChunkSectionBlockPos {
860            x: pos.x,
861            y: (pos.y & 0xF) as u8,
862            z: pos.z,
863        }
864    }
865}
866impl From<&Vec3> for BlockPos {
867    #[inline]
868    fn from(pos: &Vec3) -> Self {
869        BlockPos {
870            x: pos.x.floor() as i32,
871            y: pos.y.floor() as i32,
872            z: pos.z.floor() as i32,
873        }
874    }
875}
876impl From<Vec3> for BlockPos {
877    #[inline]
878    fn from(pos: Vec3) -> Self {
879        BlockPos::from(&pos)
880    }
881}
882
883impl From<&Vec3> for ChunkPos {
884    fn from(pos: &Vec3) -> Self {
885        ChunkPos::from(&BlockPos::from(pos))
886    }
887}
888impl From<Vec3> for ChunkPos {
889    fn from(pos: Vec3) -> Self {
890        ChunkPos::from(&pos)
891    }
892}
893
894impl From<&Vec3> for ChunkBlockPos {
895    fn from(pos: &Vec3) -> Self {
896        ChunkBlockPos::from(&BlockPos::from(pos))
897    }
898}
899impl From<Vec3> for ChunkBlockPos {
900    fn from(pos: Vec3) -> Self {
901        ChunkBlockPos::from(&pos)
902    }
903}
904
905impl fmt::Display for BlockPos {
906    /// Display a block position as `x y z`.
907    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
908        write!(f, "{} {} {}", self.x, self.y, self.z)
909    }
910}
911impl fmt::Display for Vec3 {
912    /// Display a position as `x y z`.
913    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
914        write!(f, "{} {} {}", self.x, self.y, self.z)
915    }
916}
917
918/// A 2D vector.
919#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
920#[derive(AzBuf, Clone, Copy, Debug, Default, PartialEq)]
921pub struct Vec2 {
922    pub x: f32,
923    pub y: f32,
924}
925impl Vec2 {
926    const ZERO: Vec2 = Vec2 { x: 0.0, y: 0.0 };
927
928    #[inline]
929    pub fn new(x: f32, y: f32) -> Self {
930        Vec2 { x, y }
931    }
932    #[inline]
933    pub fn scale(&self, amount: f32) -> Self {
934        Vec2 {
935            x: self.x * amount,
936            y: self.y * amount,
937        }
938    }
939    #[inline]
940    pub fn dot(&self, other: Vec2) -> f32 {
941        self.x * other.x + self.y * other.y
942    }
943    #[inline]
944    pub fn normalized(&self) -> Self {
945        let length = (self.x * self.x + self.y * self.y).sqrt();
946        if length < 1e-4 {
947            return Vec2::ZERO;
948        }
949        Vec2 {
950            x: self.x / length,
951            y: self.y / length,
952        }
953    }
954    #[inline]
955    pub fn length_squared(&self) -> f32 {
956        self.x * self.x + self.y * self.y
957    }
958    #[inline]
959    pub fn length(&self) -> f32 {
960        self.length_squared().sqrt()
961    }
962}
963impl Mul<f32> for Vec2 {
964    type Output = Self;
965
966    #[inline]
967    fn mul(self, rhs: f32) -> Self::Output {
968        self.scale(rhs)
969    }
970}
971impl MulAssign<f32> for Vec2 {
972    #[inline]
973    fn mul_assign(&mut self, rhs: f32) {
974        *self = self.scale(rhs);
975    }
976}
977
978const PACKED_X_LENGTH: u64 = 1 + 25; // minecraft does something a bit more complicated to get this 25
979const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
980const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
981const PACKED_X_MASK: u64 = (1 << PACKED_X_LENGTH) - 1;
982const PACKED_Y_MASK: u64 = (1 << PACKED_Y_LENGTH) - 1;
983const PACKED_Z_MASK: u64 = (1 << PACKED_Z_LENGTH) - 1;
984const Z_OFFSET: u64 = PACKED_Y_LENGTH;
985const X_OFFSET: u64 = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
986
987impl AzBuf for BlockPos {
988    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
989        let val = i64::azalea_read(buf)?;
990        let x = (val << (64 - X_OFFSET - PACKED_X_LENGTH) >> (64 - PACKED_X_LENGTH)) as i32;
991        let y = (val << (64 - PACKED_Y_LENGTH) >> (64 - PACKED_Y_LENGTH)) as i32;
992        let z = (val << (64 - Z_OFFSET - PACKED_Z_LENGTH) >> (64 - PACKED_Z_LENGTH)) as i32;
993        Ok(BlockPos { x, y, z })
994    }
995    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
996        let mut val: u64 = 0;
997        val |= ((self.x as u64) & PACKED_X_MASK) << X_OFFSET;
998        val |= (self.y as u64) & PACKED_Y_MASK;
999        val |= ((self.z as u64) & PACKED_Z_MASK) << Z_OFFSET;
1000        val.azalea_write(buf)
1001    }
1002}
1003
1004impl AzBuf for GlobalPos {
1005    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
1006        Ok(GlobalPos {
1007            dimension: Identifier::azalea_read(buf)?,
1008            pos: BlockPos::azalea_read(buf)?,
1009        })
1010    }
1011    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
1012        Identifier::azalea_write(&self.dimension, buf)?;
1013        BlockPos::azalea_write(&self.pos, buf)?;
1014
1015        Ok(())
1016    }
1017}
1018
1019impl AzBuf for ChunkSectionPos {
1020    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
1021        let long = i64::azalea_read(buf)?;
1022        Ok(ChunkSectionPos {
1023            x: (long >> 42) as i32,
1024            y: (long << 44 >> 44) as i32,
1025            z: (long << 22 >> 42) as i32,
1026        })
1027    }
1028    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
1029        let long = (((self.x & 0x3FFFFF) as i64) << 42)
1030            | (self.y & 0xFFFFF) as i64
1031            | (((self.z & 0x3FFFFF) as i64) << 20);
1032        long.azalea_write(buf)?;
1033        Ok(())
1034    }
1035}
1036
1037fn parse_three_values<T>(s: &str) -> Result<[T; 3], &'static str>
1038where
1039    T: FromStr,
1040    <T as FromStr>::Err: fmt::Debug,
1041{
1042    let parts = s.split_whitespace().collect::<Vec<_>>();
1043    if parts.len() != 3 {
1044        return Err("Expected three values");
1045    }
1046
1047    let x = parts[0].parse().map_err(|_| "Invalid X value")?;
1048    let y = parts[1].parse().map_err(|_| "Invalid Y value")?;
1049    let z = parts[2].parse().map_err(|_| "Invalid Z value")?;
1050
1051    Ok([x, y, z])
1052}
1053
1054/// Parses a string in the format "X Y Z" into a BlockPos.
1055///
1056/// The input string should contain three integer values separated by spaces,
1057/// representing the x, y, and z components of the vector respectively.
1058/// This can be used to parse user input or from `BlockPos::to_string`.
1059impl FromStr for BlockPos {
1060    type Err = &'static str;
1061
1062    fn from_str(s: &str) -> Result<Self, Self::Err> {
1063        let [x, y, z] = parse_three_values::<i32>(s)?;
1064        Ok(BlockPos { x, y, z })
1065    }
1066}
1067
1068/// Parses a string in the format "X Y Z" into a Vec3.
1069///
1070/// The input string should contain three floating-point values separated by
1071/// spaces, representing the x, y, and z components of the vector respectively.
1072/// This can be used to parse user input or from `Vec3::to_string`.
1073impl FromStr for Vec3 {
1074    type Err = &'static str;
1075
1076    fn from_str(s: &str) -> Result<Self, Self::Err> {
1077        let [x, y, z] = parse_three_values::<f64>(s)?;
1078        Ok(Vec3 { x, y, z })
1079    }
1080}
1081
1082#[cfg(test)]
1083mod tests {
1084    use super::*;
1085
1086    #[test]
1087    fn test_from_block_pos_to_chunk_pos() {
1088        let block_pos = BlockPos::new(5, 78, -2);
1089        let chunk_pos = ChunkPos::from(&block_pos);
1090        assert_eq!(chunk_pos, ChunkPos::new(0, -1));
1091    }
1092
1093    #[test]
1094    fn test_from_block_pos_to_chunk_block_pos() {
1095        let block_pos = BlockPos::new(5, 78, -2);
1096        let chunk_block_pos = ChunkBlockPos::from(&block_pos);
1097        assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14));
1098    }
1099
1100    #[test]
1101    fn test_from_entity_pos_to_block_pos() {
1102        let entity_pos = Vec3 {
1103            x: 31.5,
1104            y: 80.0,
1105            z: -16.1,
1106        };
1107        let block_pos = BlockPos::from(&entity_pos);
1108        assert_eq!(block_pos, BlockPos::new(31, 80, -17));
1109    }
1110
1111    #[test]
1112    fn test_from_entity_pos_to_chunk_pos() {
1113        let entity_pos = Vec3 {
1114            x: 31.5,
1115            y: 80.0,
1116            z: -16.1,
1117        };
1118        let chunk_pos = ChunkPos::from(&entity_pos);
1119        assert_eq!(chunk_pos, ChunkPos::new(1, -2));
1120    }
1121
1122    #[test]
1123    fn test_read_blockpos_from() {
1124        let mut buf = Vec::new();
1125        13743895338965u64.azalea_write(&mut buf).unwrap();
1126        let mut buf = Cursor::new(&buf[..]);
1127        let block_pos = BlockPos::azalea_read(&mut buf).unwrap();
1128        assert_eq!(block_pos, BlockPos::new(49, -43, -3));
1129    }
1130
1131    #[test]
1132    fn test_into_chunk_section_block_pos() {
1133        let block_pos = BlockPos::new(0, -60, 0);
1134        assert_eq!(
1135            ChunkSectionBlockPos::from(block_pos),
1136            ChunkSectionBlockPos::new(0, 4, 0)
1137        );
1138    }
1139
1140    #[test]
1141    fn test_read_chunk_pos_from() {
1142        let mut buf = Vec::new();
1143        ChunkPos::new(2, -1).azalea_write(&mut buf).unwrap();
1144        let mut buf = Cursor::new(&buf[..]);
1145        let chunk_pos = ChunkPos::from(u64::azalea_read(&mut buf).unwrap());
1146        assert_eq!(chunk_pos, ChunkPos::new(2, -1));
1147    }
1148}