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