use std::{ cmp, hash::{Hash, Hasher}, mem::{self, transmute}, ops::{Add, Mul}, }; use azalea_core::position::BlockPos; /// An offset from a block position. /// /// This fits in 64 bits, so it's more efficient than a BlockPos in some cases. /// /// The X and Z are limited to ±32k. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[repr(C)] pub struct RelBlockPos { /// The actual non-relative Y coordinate of the block. pub y: i32, /// The X coordinate of the block, relative to some origin. pub x: i16, /// The Y coordinate of the block, relative to some origin. pub z: i16, } impl RelBlockPos { pub fn get_origin(origin: BlockPos) -> Self { Self::new(0, origin.y, 0) } #[inline] pub const fn new(x: i16, y: i32, z: i16) -> Self { Self { x, y, z } } #[inline] pub fn apply(self, origin: BlockPos) -> BlockPos { BlockPos::new(origin.x + self.x as i32, self.y, origin.z + self.z as i32) } /// Create a new [`RelBlockPos`] from a given origin and new position. #[inline] pub fn from_origin(origin: BlockPos, new: BlockPos) -> Self { Self { x: (new.x - origin.x) as i16, y: new.y, z: (new.z - origin.z) as i16, } } #[inline] pub fn up(&self, y: i32) -> Self { Self { x: self.x, y: self.y + y, z: self.z, } } #[inline] pub fn down(&self, y: i32) -> Self { Self { x: self.x, y: self.y - y, z: self.z, } } #[inline] pub fn north(&self, z: i16) -> Self { Self { x: self.x, y: self.y, z: self.z - z, } } #[inline] pub fn south(&self, z: i16) -> Self { Self { x: self.x, y: self.y, z: self.z + z, } } #[inline] pub fn east(&self, x: i16) -> Self { Self { x: self.x + x, y: self.y, z: self.z, } } #[inline] pub fn west(&self, x: i16) -> Self { Self { x: self.x - x, y: self.y, z: self.z, } } #[inline] pub fn as_u64(self) -> u64 { // SAFETY: RelBlockPos can be represented as a u64 unsafe { transmute::(self) } } } impl Add for RelBlockPos { type Output = RelBlockPos; fn add(self, rhs: RelBlockPos) -> Self::Output { Self { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z, } } } impl Mul for RelBlockPos { type Output = RelBlockPos; fn mul(self, rhs: i16) -> Self::Output { Self { x: self.x * rhs, y: self.y * rhs as i32, z: self.z * rhs, } } } impl Hash for RelBlockPos { fn hash(&self, state: &mut H) { self.as_u64().hash(state); } } /// Similar to [`ChunkSectionPos`] but fits in 64 bits. /// /// [`ChunkSectionPos`]: azalea_core::position::ChunkSectionPos #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[repr(C)] pub struct SmallChunkSectionPos { pub y: i32, pub x: i16, pub z: i16, } impl SmallChunkSectionPos { pub fn as_u64(self) -> u64 { unsafe { mem::transmute::<_, u64>(self) } } } impl From for SmallChunkSectionPos { #[inline] fn from(pos: BlockPos) -> Self { Self { x: (pos.x >> 4) as i16, y: pos.y >> 4, z: (pos.z >> 4) as i16, } } } impl PartialOrd for SmallChunkSectionPos { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for SmallChunkSectionPos { fn cmp(&self, other: &Self) -> cmp::Ordering { self.as_u64().cmp(&other.as_u64()) } }