//! Core data structures representing the voxel world. use bytemuck::{Pod, Zeroable}; use serde::{Deserialize, Serialize}; /// The size of a chunk along one axis in blocks. pub const CHUNK_SIZE: usize = 32; /// The total number of blocks within a single chunk. pub const CHUNK_VOLUME: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; /// A unique identifier representing a type of block in the world. #[repr(transparent)] #[derive( Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Pod, Zeroable, )] pub struct BlockId(pub u16); impl BlockId { /// The block identifier representing empty space. pub const AIR: BlockId = BlockId(0); } /// A spatial volume containing voxel data. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Chunk { /// The array of blocks contained within the chunk. pub blocks: Box<[BlockId]>, } impl Chunk { /// Calculates the one-dimensional index for a three-dimensional block coordinate. #[inline] #[must_use] pub const fn index(x: usize, y: usize, z: usize) -> usize { (x * CHUNK_SIZE * CHUNK_SIZE) + (z * CHUNK_SIZE) + y } /// Retrieves the block identifier at the specified coordinates. #[must_use] pub fn get(&self, x: usize, y: usize, z: usize) -> BlockId { self.blocks[Self::index(x, y, z)] } /// Sets the block identifier at the specified coordinates. pub fn set(&mut self, x: usize, y: usize, z: usize, block: BlockId) { self.blocks[Self::index(x, y, z)] = block; } } impl Default for Chunk { fn default() -> Self { Self { blocks: vec![BlockId::AIR; CHUNK_VOLUME].into_boxed_slice(), } } } /// The three-dimensional spatial coordinates of a chunk in the world. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ChunkPos { /// The X coordinate of the chunk. pub x: i32, /// The Y coordinate of the chunk. pub y: i32, /// The Z coordinate of the chunk. pub z: i32, } impl ChunkPos { /// Initializes a new chunk position. #[must_use] pub fn new(x: i32, y: i32, z: i32) -> Self { Self { x, y, z } } }