120 lines
3.3 KiB
Rust
120 lines
3.3 KiB
Rust
use super::NeighborQuery;
|
|
|
|
pub struct Chunk {
|
|
blocks: [u8; Self::SIZE * Self::SIZE * Self::HEIGHT],
|
|
height_map: [u32; Self::SIZE * Self::SIZE],
|
|
dirty: bool,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct ChunkCoords {
|
|
pub x: i32,
|
|
pub z: i32,
|
|
}
|
|
|
|
impl ChunkCoords {
|
|
#[inline]
|
|
pub const fn new(x: i32, z: i32) -> Self {
|
|
Self { x, z }
|
|
}
|
|
|
|
pub fn origin_block(self) -> (i32, i32) {
|
|
(self.x * Chunk::SIZE as i32, self.z * Chunk::SIZE as i32)
|
|
}
|
|
|
|
pub fn block_coords(self, x: u32, z: u32) -> (i32, i32) {
|
|
let (cx, cz) = self.origin_block();
|
|
(cx + x as i32, cz + z as i32)
|
|
}
|
|
|
|
pub fn from_block_coords(x: i32, z: i32) -> Self {
|
|
let cx = if x < 0 { x - Chunk::SIZE as i32 + 1 } else { x } / Chunk::SIZE as i32;
|
|
let cz = if z < 0 { z - Chunk::SIZE as i32 + 1 } else { z } / Chunk::SIZE as i32;
|
|
Self::new(cx, cz)
|
|
}
|
|
}
|
|
|
|
impl Chunk {
|
|
pub const SIZE: usize = 32;
|
|
pub const HEIGHT: usize = 128;
|
|
|
|
pub fn empty() -> Self {
|
|
Self {
|
|
blocks: [0; Self::SIZE * Self::SIZE * Self::HEIGHT],
|
|
height_map: [0; Self::SIZE * Self::SIZE],
|
|
dirty: false,
|
|
}
|
|
}
|
|
|
|
pub fn clear_dirty(&mut self) -> bool {
|
|
let dirty = self.dirty;
|
|
self.dirty = false;
|
|
dirty
|
|
}
|
|
|
|
pub fn fill_layer<F: Fn(u32, u32) -> u8>(&mut self, y: u32, f: F) {
|
|
for x in 0..Self::SIZE as u32 {
|
|
for z in 0..Self::SIZE as u32 {
|
|
self.set_id(x, y, z, f(x, z));
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn get_id(&self, x: u32, y: u32, z: u32) -> u8 {
|
|
self.blocks[Self::to_index(x, y, z)]
|
|
}
|
|
|
|
pub fn set_id(&mut self, x: u32, y: u32, z: u32, id: u8) {
|
|
if x >= Self::SIZE as u32 || z >= Self::SIZE as u32 || y >= Self::HEIGHT as u32 {
|
|
panic!("Invalid coords: {x}, {y}, {z}");
|
|
}
|
|
|
|
self.blocks[Self::to_index(x, y, z)] = id;
|
|
self.dirty = true;
|
|
|
|
if id != 0 && y >= self.top_height_at(x, z) {
|
|
self.set_top_height_at(x, z, y + 1);
|
|
}
|
|
}
|
|
|
|
pub fn set_top_height_at(&mut self, x: u32, z: u32, h: u32) {
|
|
self.height_map[Self::to_height_index(x, z)] = h;
|
|
}
|
|
|
|
pub fn top_height_at(&self, x: u32, z: u32) -> u32 {
|
|
self.height_map[Self::to_height_index(x, z)]
|
|
}
|
|
|
|
pub fn neighbor_query(&self, x: u32, y: u32, z: u32) -> NeighborQuery {
|
|
let mut q = NeighborQuery::empty();
|
|
if z != 0 && self.get_id(x, y, z - 1) != 0 {
|
|
q |= NeighborQuery::FRONT;
|
|
}
|
|
if x != 0 && self.get_id(x - 1, y, z) != 0 {
|
|
q |= NeighborQuery::LEFT;
|
|
}
|
|
if z as usize != Self::SIZE - 1 && self.get_id(x, y, z + 1) != 0 {
|
|
q |= NeighborQuery::BACK;
|
|
}
|
|
if x as usize != Self::SIZE - 1 && self.get_id(x + 1, y, z) != 0 {
|
|
q |= NeighborQuery::RIGHT;
|
|
}
|
|
if y != 0 && self.get_id(x, y - 1, z) != 0 {
|
|
q |= NeighborQuery::BOTTOM;
|
|
}
|
|
if y as usize != Self::HEIGHT - 1 && self.get_id(x, y + 1, z) != 0 {
|
|
q |= NeighborQuery::TOP;
|
|
}
|
|
q
|
|
}
|
|
|
|
const fn to_index(x: u32, y: u32, z: u32) -> usize {
|
|
x as usize + (z as usize + y as usize * Self::SIZE) * Self::SIZE
|
|
}
|
|
|
|
const fn to_height_index(x: u32, z: u32) -> usize {
|
|
x as usize + z as usize * Self::SIZE
|
|
}
|
|
}
|
|
|