2022-09-08 21:39:08 -07:00
|
|
|
use std::io::Write;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
|
|
|
use anyhow::bail;
|
2022-07-02 10:27:54 -07:00
|
|
|
use vek::Vec3;
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-09-13 21:30:45 -04:00
|
|
|
use crate::client::BlockFace;
|
2022-08-31 19:20:49 -07:00
|
|
|
use crate::protocol::{Decode, Encode};
|
2022-04-14 14:55:45 -07:00
|
|
|
|
2022-09-12 20:20:58 -07:00
|
|
|
/// Represents an absolute block position in world space.
|
2022-04-14 14:55:45 -07:00
|
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Debug)]
|
2022-04-29 00:48:41 -07:00
|
|
|
pub struct BlockPos {
|
|
|
|
pub x: i32,
|
|
|
|
pub y: i32,
|
|
|
|
pub z: i32,
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
2022-04-29 00:48:41 -07:00
|
|
|
impl BlockPos {
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Constructs a new block position.
|
2022-04-29 00:48:41 -07:00
|
|
|
pub const fn new(x: i32, y: i32, z: i32) -> Self {
|
|
|
|
Self { x, y, z }
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
2022-07-02 10:27:54 -07:00
|
|
|
|
2022-07-11 05:08:02 -07:00
|
|
|
/// Returns the block position a point is contained within.
|
2022-07-02 10:27:54 -07:00
|
|
|
pub fn at(pos: impl Into<Vec3<f64>>) -> Self {
|
|
|
|
pos.into().floor().as_::<i32>().into()
|
|
|
|
}
|
2022-09-13 21:30:45 -04:00
|
|
|
|
|
|
|
/// Get a new [`BlockPos`] that is adjacent to this position in `dir`
|
|
|
|
/// direction.
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use valence::block::BlockPos;
|
|
|
|
/// use valence::client::BlockFace;
|
|
|
|
///
|
|
|
|
/// let pos = BlockPos::new(0, 0, 0);
|
|
|
|
/// let adj = pos.get_in_direction(BlockFace::South);
|
|
|
|
/// assert_eq!(adj, BlockPos::new(0, 0, 1));
|
|
|
|
/// ```
|
|
|
|
pub fn get_in_direction(self, dir: BlockFace) -> BlockPos {
|
|
|
|
match dir {
|
|
|
|
BlockFace::Bottom => BlockPos::new(self.x, self.y - 1, self.z),
|
|
|
|
BlockFace::Top => BlockPos::new(self.x, self.y + 1, self.z),
|
|
|
|
BlockFace::North => BlockPos::new(self.x, self.y, self.z - 1),
|
|
|
|
BlockFace::South => BlockPos::new(self.x, self.y, self.z + 1),
|
|
|
|
BlockFace::West => BlockPos::new(self.x - 1, self.y, self.z),
|
|
|
|
BlockFace::East => BlockPos::new(self.x + 1, self.y, self.z),
|
|
|
|
}
|
|
|
|
}
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Encode for BlockPos {
|
|
|
|
fn encode(&self, w: &mut impl Write) -> anyhow::Result<()> {
|
2022-04-29 00:48:41 -07:00
|
|
|
match (self.x, self.y, self.z) {
|
2022-04-14 14:55:45 -07:00
|
|
|
(-0x2000000..=0x1ffffff, -0x800..=0x7ff, -0x2000000..=0x1ffffff) => {
|
2022-04-29 00:48:41 -07:00
|
|
|
let (x, y, z) = (self.x as u64, self.y as u64, self.z as u64);
|
2022-04-14 14:55:45 -07:00
|
|
|
(x << 38 | z << 38 >> 26 | y & 0xfff).encode(w)
|
|
|
|
}
|
2022-07-14 03:40:26 -07:00
|
|
|
_ => bail!("out of range: {self:?}"),
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
}
|
2022-10-19 01:52:02 -07:00
|
|
|
|
|
|
|
fn encoded_len(&self) -> usize {
|
|
|
|
8
|
|
|
|
}
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Decode for BlockPos {
|
2022-09-08 21:39:08 -07:00
|
|
|
fn decode(r: &mut &[u8]) -> anyhow::Result<Self> {
|
2022-04-14 14:55:45 -07:00
|
|
|
// Use arithmetic right shift to determine sign.
|
|
|
|
let val = i64::decode(r)?;
|
|
|
|
let x = val >> 38;
|
|
|
|
let z = val << 26 >> 38;
|
|
|
|
let y = val << 52 >> 52;
|
2022-04-29 00:48:41 -07:00
|
|
|
Ok(Self {
|
|
|
|
x: x as i32,
|
|
|
|
y: y as i32,
|
|
|
|
z: z as i32,
|
|
|
|
})
|
2022-04-14 14:55:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 02:36:14 -07:00
|
|
|
impl From<(i32, i32, i32)> for BlockPos {
|
|
|
|
fn from((x, y, z): (i32, i32, i32)) -> Self {
|
|
|
|
BlockPos::new(x, y, z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-22 08:06:54 -07:00
|
|
|
impl From<BlockPos> for (i32, i32, i32) {
|
|
|
|
fn from(pos: BlockPos) -> Self {
|
|
|
|
(pos.x, pos.y, pos.z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 02:36:14 -07:00
|
|
|
impl From<[i32; 3]> for BlockPos {
|
|
|
|
fn from([x, y, z]: [i32; 3]) -> Self {
|
|
|
|
BlockPos::new(x, y, z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-22 08:06:54 -07:00
|
|
|
impl From<BlockPos> for [i32; 3] {
|
|
|
|
fn from(pos: BlockPos) -> Self {
|
|
|
|
[pos.x, pos.y, pos.z]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-02 10:27:54 -07:00
|
|
|
impl From<Vec3<i32>> for BlockPos {
|
|
|
|
fn from(pos: Vec3<i32>) -> Self {
|
|
|
|
Self::new(pos.x, pos.y, pos.z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<BlockPos> for Vec3<i32> {
|
|
|
|
fn from(pos: BlockPos) -> Self {
|
|
|
|
Vec3::new(pos.x, pos.y, pos.z)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-14 14:55:45 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn position() {
|
|
|
|
let xzs = [
|
|
|
|
(-33554432, true),
|
|
|
|
(-33554433, false),
|
|
|
|
(33554431, true),
|
|
|
|
(33554432, false),
|
|
|
|
(0, true),
|
|
|
|
(1, true),
|
|
|
|
(-1, true),
|
|
|
|
];
|
|
|
|
let ys = [
|
|
|
|
(-2048, true),
|
|
|
|
(-2049, false),
|
|
|
|
(2047, true),
|
|
|
|
(2048, false),
|
|
|
|
(0, true),
|
|
|
|
(1, true),
|
|
|
|
(-1, true),
|
|
|
|
];
|
|
|
|
|
|
|
|
let mut buf = [0; 8];
|
|
|
|
|
|
|
|
for (x, x_valid) in xzs {
|
|
|
|
for (y, y_valid) in ys {
|
|
|
|
for (z, z_valid) in xzs {
|
2022-04-29 00:48:41 -07:00
|
|
|
let pos = BlockPos::new(x, y, z);
|
2022-04-14 14:55:45 -07:00
|
|
|
if x_valid && y_valid && z_valid {
|
|
|
|
pos.encode(&mut &mut buf[..]).unwrap();
|
|
|
|
assert_eq!(BlockPos::decode(&mut &buf[..]).unwrap(), pos);
|
|
|
|
} else {
|
|
|
|
assert!(pos.encode(&mut &mut buf[..]).is_err());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|