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(Clone, Copy, Debug, Default, PartialEq, AzBuf, serde::Deserialize, 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()?.doubles()?;
318        let [x, y, z] = <[f64; 3]>::try_from(pos).ok()?;
319        Some(Self { x, y, z })
320    }
321}
322
323impl Vec3 {
324    /// Get the distance of this vector to the origin by doing
325    /// `sqrt(x^2 + y^2 + z^2)`.
326    pub fn length(&self) -> f64 {
327        f64::sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
328    }
329
330    /// Get the distance from this position to another position.
331    /// Equivalent to `(self - other).length()`.
332    pub fn distance_to(self, other: Self) -> f64 {
333        (self - other).length()
334    }
335
336    pub fn x_rot(self, radians: f32) -> Vec3 {
337        let x_delta = math::cos(radians);
338        let y_delta = math::sin(radians);
339        let x = self.x;
340        let y = self.y * (x_delta as f64) + self.z * (y_delta as f64);
341        let z = self.z * (x_delta as f64) - self.y * (y_delta as f64);
342        Vec3 { x, y, z }
343    }
344    pub fn y_rot(self, radians: f32) -> Vec3 {
345        let x_delta = math::cos(radians);
346        let y_delta = math::sin(radians);
347        let x = self.x * (x_delta as f64) + self.z * (y_delta as f64);
348        let y = self.y;
349        let z = self.z * (x_delta as f64) - self.x * (y_delta as f64);
350        Vec3 { x, y, z }
351    }
352
353    pub fn to_block_pos_floor(&self) -> BlockPos {
354        BlockPos {
355            x: self.x.floor() as i32,
356            y: self.y.floor() as i32,
357            z: self.z.floor() as i32,
358        }
359    }
360    pub fn to_block_pos_ceil(&self) -> BlockPos {
361        BlockPos {
362            x: self.x.ceil() as i32,
363            y: self.y.ceil() as i32,
364            z: self.z.ceil() as i32,
365        }
366    }
367
368    /// Whether the distance between this point and `other` is less than
369    /// `range`.
370    pub fn closer_than(&self, other: Vec3, range: f64) -> bool {
371        self.distance_squared_to(other) < range.powi(2)
372    }
373}
374
375/// A lower precision [`Vec3`], used for some fields in entity metadata.
376#[derive(Clone, Copy, Debug, Default, PartialEq, AzBuf)]
377pub struct Vec3f32 {
378    pub x: f32,
379    pub y: f32,
380    pub z: f32,
381}
382impl From<Vec3f32> for Vec3 {
383    fn from(v: Vec3f32) -> Self {
384        Vec3 {
385            x: v.x as f64,
386            y: v.y as f64,
387            z: v.z as f64,
388        }
389    }
390}
391impl From<Vec3> for Vec3f32 {
392    fn from(v: Vec3) -> Self {
393        Vec3f32 {
394            x: v.x as f32,
395            y: v.y as f32,
396            z: v.z as f32,
397        }
398    }
399}
400
401/// The coordinates of a block in the world.
402///
403/// For entities (if the coordinates are floating-point), use [`Vec3`] instead.
404#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
405pub struct BlockPos {
406    pub x: i32,
407    pub y: i32,
408    pub z: i32,
409}
410vec3_impl!(BlockPos, i32);
411
412impl BlockPos {
413    /// Get the absolute center of a block position by adding 0.5 to each
414    /// coordinate.
415    pub fn center(&self) -> Vec3 {
416        Vec3 {
417            x: self.x as f64 + 0.5,
418            y: self.y as f64 + 0.5,
419            z: self.z as f64 + 0.5,
420        }
421    }
422
423    /// Get the center of the bottom of a block position by adding 0.5 to the x
424    /// and z coordinates.
425    pub fn center_bottom(&self) -> Vec3 {
426        Vec3 {
427            x: self.x as f64 + 0.5,
428            y: self.y as f64,
429            z: self.z as f64 + 0.5,
430        }
431    }
432
433    /// Convert the block position into a Vec3 without centering it.
434    pub fn to_vec3_floored(&self) -> Vec3 {
435        Vec3 {
436            x: self.x as f64,
437            y: self.y as f64,
438            z: self.z as f64,
439        }
440    }
441
442    /// Get the distance of this vector from the origin by doing `x + y + z`.
443    pub fn length_manhattan(&self) -> u32 {
444        (self.x.abs() + self.y.abs() + self.z.abs()) as u32
445    }
446
447    pub fn offset_with_direction(self, direction: Direction) -> Self {
448        self + direction.normal()
449    }
450
451    /// Get the distance (as an f64) of this BlockPos to the origin by
452    /// doing `sqrt(x^2 + y^2 + z^2)`.
453    pub fn length(&self) -> f64 {
454        f64::sqrt((self.x * self.x + self.y * self.y + self.z * self.z) as f64)
455    }
456
457    /// Get the distance (as an f64) from this position to another position.
458    /// Equivalent to `(self - other).length()`.
459    ///
460    /// Note that if you're using this in a hot path, it may be more performant
461    /// to use [`BlockPos::distance_squared_to`] instead (by squaring the other
462    /// side in the comparison).
463    pub fn distance_to(self, other: Self) -> f64 {
464        (self - other).length()
465    }
466}
467impl serde::Serialize for BlockPos {
468    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
469    where
470        S: Serializer,
471    {
472        // makes sure it gets serialized correctly for the checksum
473        IntArray([self.x, self.y, self.z]).serialize(serializer)
474    }
475}
476impl<'de> serde::Deserialize<'de> for BlockPos {
477    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
478    where
479        D: serde::Deserializer<'de>,
480    {
481        let [x, y, z] = <[i32; 3]>::deserialize(deserializer)?;
482        Ok(BlockPos { x, y, z })
483    }
484}
485
486/// An arbitrary position that's represented as 32-bit integers.
487///
488/// This is similar to [`BlockPos`], but isn't limited to representing block
489/// positions and can represent a larger range of numbers.
490#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, AzBuf)]
491pub struct Vec3i {
492    #[var]
493    pub x: i32,
494    #[var]
495    pub y: i32,
496    #[var]
497    pub z: i32,
498}
499vec3_impl!(Vec3i, i32);
500impl simdnbt::FromNbtTag for Vec3i {
501    fn from_nbt_tag(tag: NbtTag) -> Option<Self> {
502        let pos = tag.list()?.ints()?;
503        let [x, y, z] = <[i32; 3]>::try_from(pos).ok()?;
504        Some(Self { x, y, z })
505    }
506}
507
508/// Chunk coordinates are used to represent where a chunk is in the world.
509///
510/// You can convert the x and z to block coordinates by multiplying them by 16.
511#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
512pub struct ChunkPos {
513    pub x: i32,
514    pub z: i32,
515}
516impl ChunkPos {
517    pub fn new(x: i32, z: i32) -> Self {
518        ChunkPos { x, z }
519    }
520}
521impl Add<ChunkPos> for ChunkPos {
522    type Output = Self;
523
524    fn add(self, rhs: Self) -> Self::Output {
525        Self {
526            x: self.x + rhs.x,
527            z: self.z + rhs.z,
528        }
529    }
530}
531impl Add<ChunkBlockPos> for ChunkPos {
532    type Output = BlockPos;
533
534    fn add(self, rhs: ChunkBlockPos) -> Self::Output {
535        BlockPos {
536            x: self.x * 16 + rhs.x as i32,
537            y: rhs.y,
538            z: self.z * 16 + rhs.z as i32,
539        }
540    }
541}
542
543// reading ChunkPos is done in reverse, so z first and then x
544// ........
545// mojang why
546impl From<ChunkPos> for u64 {
547    #[inline]
548    fn from(pos: ChunkPos) -> Self {
549        (pos.x as u64) | ((pos.z as u64) << 32)
550    }
551}
552impl From<u64> for ChunkPos {
553    #[inline]
554    fn from(pos: u64) -> Self {
555        ChunkPos {
556            x: (pos) as i32,
557            z: (pos >> 32) as i32,
558        }
559    }
560}
561impl AzaleaRead for ChunkPos {
562    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
563        let long = u64::azalea_read(buf)?;
564        Ok(ChunkPos::from(long))
565    }
566}
567impl AzaleaWrite for ChunkPos {
568    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
569        u64::from(*self).azalea_write(buf)?;
570        Ok(())
571    }
572}
573
574impl Hash for ChunkPos {
575    #[inline]
576    fn hash<H: Hasher>(&self, state: &mut H) {
577        // optimized hash that only calls hash once
578        u64::from(*self).hash(state);
579    }
580}
581/// `nohash_hasher` lets us have IntMap<ChunkPos, _> which is significantly
582/// faster than a normal HashMap
583impl nohash_hasher::IsEnabled for ChunkPos {}
584
585/// The coordinates of a chunk section in the world.
586#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
587pub struct ChunkSectionPos {
588    pub x: i32,
589    pub y: i32,
590    pub z: i32,
591}
592vec3_impl!(ChunkSectionPos, i32);
593
594impl ChunkSectionPos {
595    pub fn block_to_section_coord(block: i32) -> i32 {
596        block >> 4
597    }
598}
599
600/// The coordinates of a block inside a chunk.
601#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
602pub struct ChunkBlockPos {
603    pub x: u8,
604    pub y: i32,
605    pub z: u8,
606}
607
608impl ChunkBlockPos {
609    pub fn new(x: u8, y: i32, z: u8) -> Self {
610        ChunkBlockPos { x, y, z }
611    }
612}
613
614impl Hash for ChunkBlockPos {
615    // optimized hash that only calls hash once
616    #[inline]
617    fn hash<H: Hasher>(&self, state: &mut H) {
618        u64::from(*self).hash(state);
619    }
620}
621impl From<ChunkBlockPos> for u64 {
622    #[inline]
623    fn from(pos: ChunkBlockPos) -> Self {
624        // convert to u64
625        let mut val: u64 = 0;
626        // first 32 bits are y
627        val |= pos.y as u64;
628        // next 8 bits are z
629        val |= (pos.z as u64) << 32;
630        // last 8 bits are x
631        val |= (pos.x as u64) << 40;
632        val
633    }
634}
635impl nohash_hasher::IsEnabled for ChunkBlockPos {}
636
637/// The coordinates of a block inside of a chunk section.
638///
639/// Each coordinate should be in the range 0..=15.
640#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
641pub struct ChunkSectionBlockPos {
642    pub x: u8,
643    pub y: u8,
644    pub z: u8,
645}
646vec3_impl!(ChunkSectionBlockPos, u8);
647
648/// The coordinates of a biome inside of a chunk section.
649///
650/// Each coordinate should be in the range 0..=3.
651#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
652pub struct ChunkSectionBiomePos {
653    pub x: u8,
654    pub y: u8,
655    pub z: u8,
656}
657impl From<&ChunkBiomePos> for ChunkSectionBiomePos {
658    #[inline]
659    fn from(pos: &ChunkBiomePos) -> Self {
660        ChunkSectionBiomePos {
661            x: pos.x,
662            y: (pos.y & 0b11) as u8,
663            z: pos.z,
664        }
665    }
666}
667impl From<ChunkBiomePos> for ChunkSectionBiomePos {
668    #[inline]
669    fn from(pos: ChunkBiomePos) -> Self {
670        Self::from(&pos)
671    }
672}
673vec3_impl!(ChunkSectionBiomePos, u8);
674
675/// The coordinates of a biome inside a chunk.
676///
677/// Biomes are 4x4 blocks.
678#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
679pub struct ChunkBiomePos {
680    pub x: u8,
681    pub y: i32,
682    pub z: u8,
683}
684impl From<&BlockPos> for ChunkBiomePos {
685    #[inline]
686    fn from(pos: &BlockPos) -> Self {
687        ChunkBiomePos::from(&ChunkBlockPos::from(pos))
688    }
689}
690impl From<BlockPos> for ChunkBiomePos {
691    #[inline]
692    fn from(pos: BlockPos) -> Self {
693        ChunkBiomePos::from(&ChunkBlockPos::from(pos))
694    }
695}
696impl From<&ChunkBlockPos> for ChunkBiomePos {
697    #[inline]
698    fn from(pos: &ChunkBlockPos) -> Self {
699        ChunkBiomePos {
700            x: pos.x >> 2,
701            y: pos.y >> 2,
702            z: pos.z >> 2,
703        }
704    }
705}
706
707impl Add<ChunkSectionBlockPos> for ChunkSectionPos {
708    type Output = BlockPos;
709
710    fn add(self, rhs: ChunkSectionBlockPos) -> Self::Output {
711        BlockPos::new(
712            self.x * 16 + rhs.x as i32,
713            self.y * 16 + rhs.y as i32,
714            self.z * 16 + rhs.z as i32,
715        )
716    }
717}
718impl Hash for ChunkSectionBlockPos {
719    // optimized hash that only calls hash once
720    #[inline]
721    fn hash<H: Hasher>(&self, state: &mut H) {
722        u16::from(*self).hash(state);
723    }
724}
725
726impl From<ChunkSectionBlockPos> for u16 {
727    #[inline]
728    fn from(pos: ChunkSectionBlockPos) -> Self {
729        // (pos.z as u16) | ((pos.y as u16) << 4) | ((pos.x as u16) << 8)
730        ((((pos.y as u16) << 4) | pos.z as u16) << 4) | pos.x as u16
731    }
732}
733impl nohash_hasher::IsEnabled for ChunkSectionBlockPos {}
734
735/// A block pos with an attached world
736#[derive(Debug, Clone, PartialEq, Serialize)]
737pub struct GlobalPos {
738    // this is actually a ResourceKey in Minecraft, but i don't think it matters?
739    pub dimension: Identifier,
740    pub pos: BlockPos,
741}
742
743impl From<&BlockPos> for ChunkPos {
744    #[inline]
745    fn from(pos: &BlockPos) -> Self {
746        ChunkPos {
747            x: pos.x >> 4,
748            z: pos.z >> 4,
749        }
750    }
751}
752impl From<BlockPos> for ChunkPos {
753    #[inline]
754    fn from(pos: BlockPos) -> Self {
755        ChunkPos {
756            x: pos.x >> 4,
757            z: pos.z >> 4,
758        }
759    }
760}
761
762impl From<BlockPos> for ChunkSectionPos {
763    #[inline]
764    fn from(pos: BlockPos) -> Self {
765        ChunkSectionPos {
766            x: pos.x >> 4,
767            y: pos.y >> 4,
768            z: pos.z >> 4,
769        }
770    }
771}
772impl From<&BlockPos> for ChunkSectionPos {
773    #[inline]
774    fn from(pos: &BlockPos) -> Self {
775        ChunkSectionPos {
776            x: pos.x >> 4,
777            y: pos.y >> 4,
778            z: pos.z >> 4,
779        }
780    }
781}
782
783impl From<ChunkSectionPos> for ChunkPos {
784    fn from(pos: ChunkSectionPos) -> Self {
785        ChunkPos { x: pos.x, z: pos.z }
786    }
787}
788impl From<&Vec3> for ChunkSectionPos {
789    fn from(pos: &Vec3) -> Self {
790        ChunkSectionPos::from(&BlockPos::from(pos))
791    }
792}
793impl From<Vec3> for ChunkSectionPos {
794    fn from(pos: Vec3) -> Self {
795        ChunkSectionPos::from(&pos)
796    }
797}
798
799impl From<&BlockPos> for ChunkBlockPos {
800    #[inline]
801    fn from(pos: &BlockPos) -> Self {
802        ChunkBlockPos {
803            x: (pos.x & 0xF) as u8,
804            y: pos.y,
805            z: (pos.z & 0xF) as u8,
806        }
807    }
808}
809impl From<BlockPos> for ChunkBlockPos {
810    #[inline]
811    fn from(pos: BlockPos) -> Self {
812        ChunkBlockPos {
813            x: (pos.x & 0xF) as u8,
814            y: pos.y,
815            z: (pos.z & 0xF) as u8,
816        }
817    }
818}
819
820impl From<BlockPos> for ChunkSectionBlockPos {
821    #[inline]
822    fn from(pos: BlockPos) -> Self {
823        ChunkSectionBlockPos {
824            x: (pos.x & 0xF) as u8,
825            y: (pos.y & 0xF) as u8,
826            z: (pos.z & 0xF) as u8,
827        }
828    }
829}
830
831impl From<&ChunkBlockPos> for ChunkSectionBlockPos {
832    #[inline]
833    fn from(pos: &ChunkBlockPos) -> Self {
834        ChunkSectionBlockPos {
835            x: pos.x,
836            y: (pos.y & 0xF) as u8,
837            z: pos.z,
838        }
839    }
840}
841impl From<&Vec3> for BlockPos {
842    #[inline]
843    fn from(pos: &Vec3) -> Self {
844        BlockPos {
845            x: pos.x.floor() as i32,
846            y: pos.y.floor() as i32,
847            z: pos.z.floor() as i32,
848        }
849    }
850}
851impl From<Vec3> for BlockPos {
852    #[inline]
853    fn from(pos: Vec3) -> Self {
854        BlockPos::from(&pos)
855    }
856}
857
858impl From<&Vec3> for ChunkPos {
859    fn from(pos: &Vec3) -> Self {
860        ChunkPos::from(&BlockPos::from(pos))
861    }
862}
863impl From<Vec3> for ChunkPos {
864    fn from(pos: Vec3) -> Self {
865        ChunkPos::from(&pos)
866    }
867}
868
869impl From<&Vec3> for ChunkBlockPos {
870    fn from(pos: &Vec3) -> Self {
871        ChunkBlockPos::from(&BlockPos::from(pos))
872    }
873}
874impl From<Vec3> for ChunkBlockPos {
875    fn from(pos: Vec3) -> Self {
876        ChunkBlockPos::from(&pos)
877    }
878}
879
880impl fmt::Display for BlockPos {
881    /// Display a block position as `x y z`.
882    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883        write!(f, "{} {} {}", self.x, self.y, self.z)
884    }
885}
886impl fmt::Display for Vec3 {
887    /// Display a position as `x y z`.
888    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889        write!(f, "{} {} {}", self.x, self.y, self.z)
890    }
891}
892
893/// A 2D vector.
894#[derive(Clone, Copy, Debug, Default, PartialEq, AzBuf, simdnbt::Deserialize, Serialize)]
895pub struct Vec2 {
896    pub x: f32,
897    pub y: f32,
898}
899impl Vec2 {
900    const ZERO: Vec2 = Vec2 { x: 0.0, y: 0.0 };
901
902    #[inline]
903    pub fn new(x: f32, y: f32) -> Self {
904        Vec2 { x, y }
905    }
906    #[inline]
907    pub fn scale(&self, amount: f32) -> Self {
908        Vec2 {
909            x: self.x * amount,
910            y: self.y * amount,
911        }
912    }
913    #[inline]
914    pub fn dot(&self, other: Vec2) -> f32 {
915        self.x * other.x + self.y * other.y
916    }
917    #[inline]
918    pub fn normalized(&self) -> Self {
919        let length = (self.x * self.x + self.y * self.y).sqrt();
920        if length < 1e-4 {
921            return Vec2::ZERO;
922        }
923        Vec2 {
924            x: self.x / length,
925            y: self.y / length,
926        }
927    }
928    #[inline]
929    pub fn length_squared(&self) -> f32 {
930        self.x * self.x + self.y * self.y
931    }
932    #[inline]
933    pub fn length(&self) -> f32 {
934        self.length_squared().sqrt()
935    }
936}
937impl Mul<f32> for Vec2 {
938    type Output = Self;
939
940    #[inline]
941    fn mul(self, rhs: f32) -> Self::Output {
942        self.scale(rhs)
943    }
944}
945impl MulAssign<f32> for Vec2 {
946    #[inline]
947    fn mul_assign(&mut self, rhs: f32) {
948        *self = self.scale(rhs);
949    }
950}
951
952const PACKED_X_LENGTH: u64 = 1 + 25; // minecraft does something a bit more complicated to get this 25
953const PACKED_Z_LENGTH: u64 = PACKED_X_LENGTH;
954const PACKED_Y_LENGTH: u64 = 64 - PACKED_X_LENGTH - PACKED_Z_LENGTH;
955const PACKED_X_MASK: u64 = (1 << PACKED_X_LENGTH) - 1;
956const PACKED_Y_MASK: u64 = (1 << PACKED_Y_LENGTH) - 1;
957const PACKED_Z_MASK: u64 = (1 << PACKED_Z_LENGTH) - 1;
958const Z_OFFSET: u64 = PACKED_Y_LENGTH;
959const X_OFFSET: u64 = PACKED_Y_LENGTH + PACKED_Z_LENGTH;
960
961impl AzaleaRead for BlockPos {
962    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
963        let val = i64::azalea_read(buf)?;
964        let x = (val << (64 - X_OFFSET - PACKED_X_LENGTH) >> (64 - PACKED_X_LENGTH)) as i32;
965        let y = (val << (64 - PACKED_Y_LENGTH) >> (64 - PACKED_Y_LENGTH)) as i32;
966        let z = (val << (64 - Z_OFFSET - PACKED_Z_LENGTH) >> (64 - PACKED_Z_LENGTH)) as i32;
967        Ok(BlockPos { x, y, z })
968    }
969}
970
971impl AzaleaRead for GlobalPos {
972    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
973        Ok(GlobalPos {
974            dimension: Identifier::azalea_read(buf)?,
975            pos: BlockPos::azalea_read(buf)?,
976        })
977    }
978}
979
980impl AzaleaRead for ChunkSectionPos {
981    fn azalea_read(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
982        let long = i64::azalea_read(buf)?;
983        Ok(ChunkSectionPos {
984            x: (long >> 42) as i32,
985            y: (long << 44 >> 44) as i32,
986            z: (long << 22 >> 42) as i32,
987        })
988    }
989}
990
991impl AzaleaWrite for BlockPos {
992    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
993        let mut val: u64 = 0;
994        val |= ((self.x as u64) & PACKED_X_MASK) << X_OFFSET;
995        val |= (self.y as u64) & PACKED_Y_MASK;
996        val |= ((self.z as u64) & PACKED_Z_MASK) << Z_OFFSET;
997        val.azalea_write(buf)
998    }
999}
1000
1001impl AzaleaWrite for GlobalPos {
1002    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
1003        Identifier::azalea_write(&self.dimension, buf)?;
1004        BlockPos::azalea_write(&self.pos, buf)?;
1005
1006        Ok(())
1007    }
1008}
1009
1010impl AzaleaWrite for ChunkSectionPos {
1011    fn azalea_write(&self, buf: &mut impl Write) -> io::Result<()> {
1012        let long = (((self.x & 0x3FFFFF) as i64) << 42)
1013            | (self.y & 0xFFFFF) as i64
1014            | (((self.z & 0x3FFFFF) as i64) << 20);
1015        long.azalea_write(buf)?;
1016        Ok(())
1017    }
1018}
1019
1020fn parse_three_values<T>(s: &str) -> Result<[T; 3], &'static str>
1021where
1022    T: FromStr,
1023    <T as FromStr>::Err: fmt::Debug,
1024{
1025    let parts = s.split_whitespace().collect::<Vec<_>>();
1026    if parts.len() != 3 {
1027        return Err("Expected three values");
1028    }
1029
1030    let x = parts[0].parse().map_err(|_| "Invalid X value")?;
1031    let y = parts[1].parse().map_err(|_| "Invalid Y value")?;
1032    let z = parts[2].parse().map_err(|_| "Invalid Z value")?;
1033
1034    Ok([x, y, z])
1035}
1036
1037/// Parses a string in the format "X Y Z" into a BlockPos.
1038///
1039/// The input string should contain three integer values separated by spaces,
1040/// representing the x, y, and z components of the vector respectively.
1041/// This can be used to parse user input or from `BlockPos::to_string`.
1042impl FromStr for BlockPos {
1043    type Err = &'static str;
1044
1045    fn from_str(s: &str) -> Result<Self, Self::Err> {
1046        let [x, y, z] = parse_three_values::<i32>(s)?;
1047        Ok(BlockPos { x, y, z })
1048    }
1049}
1050
1051/// Parses a string in the format "X Y Z" into a Vec3.
1052///
1053/// The input string should contain three floating-point values separated by
1054/// spaces, representing the x, y, and z components of the vector respectively.
1055/// This can be used to parse user input or from `Vec3::to_string`.
1056impl FromStr for Vec3 {
1057    type Err = &'static str;
1058
1059    fn from_str(s: &str) -> Result<Self, Self::Err> {
1060        let [x, y, z] = parse_three_values::<f64>(s)?;
1061        Ok(Vec3 { x, y, z })
1062    }
1063}
1064
1065#[cfg(test)]
1066mod tests {
1067    use super::*;
1068
1069    #[test]
1070    fn test_from_block_pos_to_chunk_pos() {
1071        let block_pos = BlockPos::new(5, 78, -2);
1072        let chunk_pos = ChunkPos::from(&block_pos);
1073        assert_eq!(chunk_pos, ChunkPos::new(0, -1));
1074    }
1075
1076    #[test]
1077    fn test_from_block_pos_to_chunk_block_pos() {
1078        let block_pos = BlockPos::new(5, 78, -2);
1079        let chunk_block_pos = ChunkBlockPos::from(&block_pos);
1080        assert_eq!(chunk_block_pos, ChunkBlockPos::new(5, 78, 14));
1081    }
1082
1083    #[test]
1084    fn test_from_entity_pos_to_block_pos() {
1085        let entity_pos = Vec3 {
1086            x: 31.5,
1087            y: 80.0,
1088            z: -16.1,
1089        };
1090        let block_pos = BlockPos::from(&entity_pos);
1091        assert_eq!(block_pos, BlockPos::new(31, 80, -17));
1092    }
1093
1094    #[test]
1095    fn test_from_entity_pos_to_chunk_pos() {
1096        let entity_pos = Vec3 {
1097            x: 31.5,
1098            y: 80.0,
1099            z: -16.1,
1100        };
1101        let chunk_pos = ChunkPos::from(&entity_pos);
1102        assert_eq!(chunk_pos, ChunkPos::new(1, -2));
1103    }
1104
1105    #[test]
1106    fn test_read_blockpos_from() {
1107        let mut buf = Vec::new();
1108        13743895338965u64.azalea_write(&mut buf).unwrap();
1109        let mut buf = Cursor::new(&buf[..]);
1110        let block_pos = BlockPos::azalea_read(&mut buf).unwrap();
1111        assert_eq!(block_pos, BlockPos::new(49, -43, -3));
1112    }
1113
1114    #[test]
1115    fn test_into_chunk_section_block_pos() {
1116        let block_pos = BlockPos::new(0, -60, 0);
1117        assert_eq!(
1118            ChunkSectionBlockPos::from(block_pos),
1119            ChunkSectionBlockPos::new(0, 4, 0)
1120        );
1121    }
1122
1123    #[test]
1124    fn test_read_chunk_pos_from() {
1125        let mut buf = Vec::new();
1126        ChunkPos::new(2, -1).azalea_write(&mut buf).unwrap();
1127        let mut buf = Cursor::new(&buf[..]);
1128        let chunk_pos = ChunkPos::from(u64::azalea_read(&mut buf).unwrap());
1129        assert_eq!(chunk_pos, ChunkPos::new(2, -1));
1130    }
1131}