Skip to main content

yog_core/
cells.rs

1//! Positions as mirror cells (`yog_mirror::Cell`): a row of a column is
2//! `[x, y, z]`; a block's key in `yog:keys/block` is its packed position.
3
4use yog_mirror::{Cell, Kind};
5
6use crate::{BlockPos, Point};
7
8/// The game's packed block position (`BlockPos.asLong`): x and z 26 bits,
9/// y 12, as `x | z | y` from the top.
10const XZ_BITS: u32 = 26;
11const Y_BITS: u32 = 12;
12const X_SHIFT: u32 = Y_BITS + XZ_BITS;
13const Z_SHIFT: u32 = Y_BITS;
14
15const fn mask(bits: u32) -> i64 {
16    (1 << bits) - 1
17}
18
19/// The signed `bits`-wide field at `shift` of `p`: shifted to the top,
20/// then back, so the sign comes along.
21const fn field(p: i64, shift: u32, bits: u32) -> i32 {
22    ((p << (i64::BITS - shift - bits)) >> (i64::BITS - bits)) as i32
23}
24
25impl BlockPos {
26    /// Its packed form: the game's `BlockPos.asLong`, its key in `yog:keys/block`.
27    pub const fn packed(self) -> u64 {
28        (((self.x as i64 & mask(XZ_BITS)) << X_SHIFT)
29            | ((self.z as i64 & mask(XZ_BITS)) << Z_SHIFT)
30            | (self.y as i64 & mask(Y_BITS))) as u64
31    }
32
33    /// The position `packed` holds.
34    pub const fn unpacked(packed: u64) -> BlockPos {
35        let p = packed as i64;
36        BlockPos::new(
37            field(p, X_SHIFT, XZ_BITS),
38            field(p, 0, Y_BITS),
39            field(p, Z_SHIFT, XZ_BITS),
40        )
41    }
42}
43
44impl Cell for Point {
45    const KIND: Kind = Kind::F64;
46    const COUNT: u32 = 3;
47
48    #[inline]
49    fn put(&self, out: &mut [u8]) {
50        [self.x, self.y, self.z].put(out);
51    }
52
53    #[inline]
54    fn take(bytes: &[u8]) -> Self {
55        let [x, y, z] = <[f64; 3]>::take(bytes);
56        Point { x, y, z }
57    }
58}
59
60impl Cell for BlockPos {
61    const KIND: Kind = Kind::I32;
62    const COUNT: u32 = 3;
63
64    #[inline]
65    fn put(&self, out: &mut [u8]) {
66        <[i32; 3]>::from(*self).put(out);
67    }
68
69    #[inline]
70    fn take(bytes: &[u8]) -> Self {
71        <[i32; 3]>::take(bytes).into()
72    }
73}
74
75#[cfg(test)]
76mod tests;