Files
gaym/src/world/chunk.rs
T
2025-04-27 19:22:16 +03:00

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
}
}