azalea/pathfinder/
positions.rs

1use std::{
2    cmp,
3    hash::{Hash, Hasher},
4    mem::{self, transmute},
5    ops::{Add, Mul},
6};
7
8use azalea_core::position::BlockPos;
9
10/// An offset from a block position.
11///
12/// This fits in 64 bits, so it's more efficient than a BlockPos in some cases.
13///
14/// The X and Z are limited to ±32k.
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16#[repr(C)]
17pub struct RelBlockPos {
18    /// The actual non-relative Y coordinate of the block.
19    pub y: i32,
20    /// The X coordinate of the block, relative to some origin.
21    pub x: i16,
22    /// The Y coordinate of the block, relative to some origin.
23    pub z: i16,
24}
25
26impl RelBlockPos {
27    pub fn get_origin(origin: BlockPos) -> Self {
28        Self::new(0, origin.y, 0)
29    }
30
31    #[inline]
32    pub const fn new(x: i16, y: i32, z: i16) -> Self {
33        Self { x, y, z }
34    }
35
36    #[inline]
37    pub fn apply(self, origin: BlockPos) -> BlockPos {
38        BlockPos::new(origin.x + self.x as i32, self.y, origin.z + self.z as i32)
39    }
40
41    /// Create a new [`RelBlockPos`] from a given origin and new position.
42    #[inline]
43    pub fn from_origin(origin: BlockPos, new: BlockPos) -> Self {
44        Self {
45            x: (new.x - origin.x) as i16,
46            y: new.y,
47            z: (new.z - origin.z) as i16,
48        }
49    }
50
51    #[inline]
52    pub fn up(&self, y: i32) -> Self {
53        Self {
54            x: self.x,
55            y: self.y + y,
56            z: self.z,
57        }
58    }
59    #[inline]
60    pub fn down(&self, y: i32) -> Self {
61        Self {
62            x: self.x,
63            y: self.y - y,
64            z: self.z,
65        }
66    }
67    #[inline]
68    pub fn north(&self, z: i16) -> Self {
69        Self {
70            x: self.x,
71            y: self.y,
72            z: self.z - z,
73        }
74    }
75    #[inline]
76    pub fn south(&self, z: i16) -> Self {
77        Self {
78            x: self.x,
79            y: self.y,
80            z: self.z + z,
81        }
82    }
83    #[inline]
84    pub fn east(&self, x: i16) -> Self {
85        Self {
86            x: self.x + x,
87            y: self.y,
88            z: self.z,
89        }
90    }
91    #[inline]
92    pub fn west(&self, x: i16) -> Self {
93        Self {
94            x: self.x - x,
95            y: self.y,
96            z: self.z,
97        }
98    }
99
100    #[inline]
101    pub fn as_u64(self) -> u64 {
102        // SAFETY: RelBlockPos can be represented as a u64
103        unsafe { transmute::<Self, u64>(self) }
104    }
105}
106
107impl Add<RelBlockPos> for RelBlockPos {
108    type Output = RelBlockPos;
109
110    fn add(self, rhs: RelBlockPos) -> Self::Output {
111        Self {
112            x: self.x + rhs.x,
113            y: self.y + rhs.y,
114            z: self.z + rhs.z,
115        }
116    }
117}
118impl Mul<i16> for RelBlockPos {
119    type Output = RelBlockPos;
120
121    fn mul(self, rhs: i16) -> Self::Output {
122        Self {
123            x: self.x * rhs,
124            y: self.y * rhs as i32,
125            z: self.z * rhs,
126        }
127    }
128}
129
130impl Hash for RelBlockPos {
131    fn hash<H: Hasher>(&self, state: &mut H) {
132        self.as_u64().hash(state);
133    }
134}
135
136/// Similar to [`ChunkSectionPos`] but fits in 64 bits.
137///
138/// [`ChunkSectionPos`]: azalea_core::position::ChunkSectionPos
139#[derive(Clone, Copy, PartialEq, Eq)]
140#[repr(C)]
141pub struct SmallChunkSectionPos {
142    pub y: i32,
143    pub x: i16,
144    pub z: i16,
145}
146impl SmallChunkSectionPos {
147    pub fn as_u64(self) -> u64 {
148        unsafe { mem::transmute::<_, u64>(self) }
149    }
150}
151impl From<BlockPos> for SmallChunkSectionPos {
152    #[inline]
153    fn from(pos: BlockPos) -> Self {
154        Self {
155            x: (pos.x >> 4) as i16,
156            y: pos.y >> 4,
157            z: (pos.z >> 4) as i16,
158        }
159    }
160}
161impl PartialOrd for SmallChunkSectionPos {
162    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
163        Some(self.cmp(other))
164    }
165}
166impl Ord for SmallChunkSectionPos {
167    fn cmp(&self, other: &Self) -> cmp::Ordering {
168        self.as_u64().cmp(&other.as_u64())
169    }
170}