azalea/pathfinder/
rel_block_pos.rs

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