2023-01-27 21:51:54 +01:00
|
|
|
use std::{
|
|
|
|
fmt::Debug,
|
2023-02-13 00:02:43 +01:00
|
|
|
iter::FusedIterator,
|
2023-02-12 23:07:55 +01:00
|
|
|
ops::{Index, IndexMut},
|
2023-01-27 21:51:54 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
use itertools::iproduct;
|
2023-02-25 23:23:00 +01:00
|
|
|
use serde::{Deserialize, Serialize};
|
2023-01-27 21:21:09 +01:00
|
|
|
|
2023-08-02 00:14:37 +02:00
|
|
|
pub mod axis {
|
|
|
|
pub const X: u8 = 0;
|
|
|
|
pub const Y: u8 = 1;
|
|
|
|
pub const Z: u8 = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! coord_type {
|
2023-02-13 00:02:43 +01:00
|
|
|
($t:ident, $max:expr) => {
|
2023-08-02 00:14:37 +02:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub struct $t<const AXIS: u8>(pub u8);
|
|
|
|
|
|
|
|
impl<const AXIS: u8> $t<AXIS> {
|
|
|
|
const MAX: usize = $max;
|
|
|
|
|
|
|
|
/// Constructs a new value
|
|
|
|
///
|
|
|
|
/// Will panic if the value is not in the valid range
|
|
|
|
pub fn new<T: TryInto<u8>>(value: T) -> Self {
|
|
|
|
Self(
|
|
|
|
value
|
|
|
|
.try_into()
|
|
|
|
.ok()
|
|
|
|
.filter(|&v| (v as usize) < Self::MAX)
|
|
|
|
.expect("coordinate should be in the valid range"),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-02-13 00:02:43 +01:00
|
|
|
/// Returns an iterator over all possible values of the type
|
2023-08-02 00:14:37 +02:00
|
|
|
pub fn iter() -> impl Iterator<Item = $t<AXIS>>
|
2023-02-13 00:02:43 +01:00
|
|
|
+ DoubleEndedIterator
|
|
|
|
+ ExactSizeIterator
|
|
|
|
+ FusedIterator
|
|
|
|
+ Clone
|
|
|
|
+ Debug {
|
2023-08-02 00:14:37 +02:00
|
|
|
(0..Self::MAX as u8).map($t)
|
2023-02-13 00:02:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-12 20:17:20 +01:00
|
|
|
pub const BLOCKS_PER_CHUNK: usize = 16;
|
2023-08-02 00:14:37 +02:00
|
|
|
coord_type!(BlockCoord, BLOCKS_PER_CHUNK);
|
2023-02-12 12:17:46 +01:00
|
|
|
|
|
|
|
/// A block X coordinate relative to a chunk
|
2023-08-02 00:14:37 +02:00
|
|
|
pub type BlockX = BlockCoord<{ axis::X }>;
|
2023-02-12 12:17:46 +01:00
|
|
|
|
|
|
|
/// A block Y coordinate relative to a chunk section
|
2023-08-02 00:14:37 +02:00
|
|
|
pub type BlockY = BlockCoord<{ axis::Y }>;
|
2023-02-12 12:17:46 +01:00
|
|
|
|
|
|
|
/// A block Z coordinate relative to a chunk
|
2023-08-02 00:14:37 +02:00
|
|
|
pub type BlockZ = BlockCoord<{ axis::Z }>;
|
2023-02-12 12:17:46 +01:00
|
|
|
|
2023-02-15 00:33:58 +01:00
|
|
|
/// X and Z coordinates of a block in a chunk
|
2023-02-12 17:56:44 +01:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
2023-02-15 00:33:58 +01:00
|
|
|
pub struct LayerBlockCoords {
|
2023-02-12 12:17:46 +01:00
|
|
|
pub x: BlockX,
|
|
|
|
pub z: BlockZ,
|
|
|
|
}
|
|
|
|
|
2023-02-15 00:33:58 +01:00
|
|
|
impl Debug for LayerBlockCoords {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "({}, {})", self.x.0, self.z.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-08 10:59:20 +02:00
|
|
|
impl LayerBlockCoords {
|
|
|
|
/// Computes a block's offset in various data structures
|
|
|
|
///
|
|
|
|
/// Many chunk data structures store block and biome data in the same
|
|
|
|
/// order. This method computes the offset at which the data for the
|
|
|
|
/// block at a given coordinate is stored.
|
|
|
|
pub fn offset(&self) -> usize {
|
|
|
|
use BLOCKS_PER_CHUNK as N;
|
|
|
|
let x = self.x.0 as usize;
|
|
|
|
let z = self.z.0 as usize;
|
|
|
|
N * z + x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 00:38:12 +01:00
|
|
|
/// Generic array for data stored per block of a chunk layer
|
|
|
|
///
|
|
|
|
/// Includes various convenient iteration functions.
|
2023-02-25 23:23:00 +01:00
|
|
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
2023-02-15 00:38:12 +01:00
|
|
|
pub struct LayerBlockArray<T>(pub [[T; BLOCKS_PER_CHUNK]; BLOCKS_PER_CHUNK]);
|
|
|
|
|
|
|
|
impl<T> Index<LayerBlockCoords> for LayerBlockArray<T> {
|
|
|
|
type Output = T;
|
|
|
|
|
|
|
|
fn index(&self, index: LayerBlockCoords) -> &Self::Output {
|
|
|
|
&self.0[index.z.0 as usize][index.x.0 as usize]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> IndexMut<LayerBlockCoords> for LayerBlockArray<T> {
|
|
|
|
fn index_mut(&mut self, index: LayerBlockCoords) -> &mut Self::Output {
|
|
|
|
&mut self.0[index.z.0 as usize][index.x.0 as usize]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 00:33:58 +01:00
|
|
|
/// X, Y and Z coordinates of a block in a chunk section
|
|
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
|
|
|
pub struct SectionBlockCoords {
|
|
|
|
pub xz: LayerBlockCoords,
|
|
|
|
pub y: BlockY,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SectionBlockCoords {
|
2023-02-12 20:59:23 +01:00
|
|
|
/// Computes a block's offset in various data structures
|
|
|
|
///
|
|
|
|
/// Many chunk data structures store block and biome data in the same
|
2023-02-18 11:07:29 +01:00
|
|
|
/// order. This method computes the offset at which the data for the
|
|
|
|
/// block at a given coordinate is stored.
|
2023-02-12 12:17:46 +01:00
|
|
|
pub fn offset(&self) -> usize {
|
2023-02-12 20:17:20 +01:00
|
|
|
use BLOCKS_PER_CHUNK as N;
|
2023-02-12 12:17:46 +01:00
|
|
|
let y = self.y.0 as usize;
|
2023-04-08 10:59:20 +02:00
|
|
|
N * N * y + self.xz.offset()
|
2023-02-12 12:17:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 00:33:58 +01:00
|
|
|
impl Debug for SectionBlockCoords {
|
2023-02-12 12:17:46 +01:00
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2023-02-15 00:33:58 +01:00
|
|
|
write!(f, "({}, {}, {})", self.xz.x.0, self.y.0, self.xz.z.0)
|
2023-02-12 12:17:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A section Y coordinate
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
|
|
pub struct SectionY(pub i32);
|
|
|
|
|
2023-02-12 20:17:20 +01:00
|
|
|
pub const CHUNKS_PER_REGION: usize = 32;
|
2023-08-02 00:14:37 +02:00
|
|
|
coord_type!(ChunkCoord, CHUNKS_PER_REGION);
|
2023-01-25 21:41:08 +01:00
|
|
|
|
|
|
|
/// A chunk X coordinate relative to a region
|
2023-08-02 00:14:37 +02:00
|
|
|
pub type ChunkX = ChunkCoord<{ axis::X }>;
|
2023-01-25 21:41:08 +01:00
|
|
|
|
|
|
|
/// A chunk Z coordinate relative to a region
|
2023-08-02 00:14:37 +02:00
|
|
|
pub type ChunkZ = ChunkCoord<{ axis::Z }>;
|
2023-01-27 21:21:09 +01:00
|
|
|
|
|
|
|
/// A pair of chunk coordinates relative to a region
|
2023-02-12 17:56:44 +01:00
|
|
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
2023-01-27 21:21:09 +01:00
|
|
|
pub struct ChunkCoords {
|
|
|
|
pub x: ChunkX,
|
|
|
|
pub z: ChunkZ,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for ChunkCoords {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "({}, {})", self.x.0, self.z.0)
|
|
|
|
}
|
|
|
|
}
|
2023-01-27 21:51:54 +01:00
|
|
|
|
2023-02-12 20:59:23 +01:00
|
|
|
/// Generic array for data stored per chunk of a region
|
|
|
|
///
|
|
|
|
/// Includes various convenient iteration functions.
|
2023-02-25 23:23:00 +01:00
|
|
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
2023-02-12 20:17:20 +01:00
|
|
|
pub struct ChunkArray<T>(pub [[T; CHUNKS_PER_REGION]; CHUNKS_PER_REGION]);
|
2023-01-27 21:51:54 +01:00
|
|
|
|
|
|
|
impl<T> ChunkArray<T> {
|
2023-02-15 00:47:59 +01:00
|
|
|
pub fn keys() -> impl Iterator<Item = ChunkCoords> + Clone + Debug {
|
2023-02-13 00:02:43 +01:00
|
|
|
iproduct!(ChunkZ::iter(), ChunkX::iter()).map(|(z, x)| ChunkCoords { x, z })
|
2023-01-27 21:51:54 +01:00
|
|
|
}
|
|
|
|
|
2023-02-15 00:47:59 +01:00
|
|
|
pub fn values(&self) -> impl Iterator<Item = &T> + Clone + Debug {
|
2023-01-27 21:51:54 +01:00
|
|
|
Self::keys().map(|k| &self[k])
|
|
|
|
}
|
|
|
|
|
2023-02-15 00:47:59 +01:00
|
|
|
pub fn iter(&self) -> impl Iterator<Item = (ChunkCoords, &T)> + Clone + Debug {
|
2023-01-27 21:51:54 +01:00
|
|
|
Self::keys().map(|k| (k, &self[k]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> Index<ChunkCoords> for ChunkArray<T> {
|
|
|
|
type Output = T;
|
|
|
|
|
|
|
|
fn index(&self, index: ChunkCoords) -> &Self::Output {
|
|
|
|
&self.0[index.z.0 as usize][index.x.0 as usize]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> IndexMut<ChunkCoords> for ChunkArray<T> {
|
|
|
|
fn index_mut(&mut self, index: ChunkCoords) -> &mut Self::Output {
|
|
|
|
&mut self.0[index.z.0 as usize][index.x.0 as usize]
|
|
|
|
}
|
|
|
|
}
|