Skip to main content

basalt_api/world/
block_entity.rs

1//! Block entities — persistent per-block state.
2//!
3//! Block entities store data that standard block states cannot represent,
4//! such as chest inventories, furnace cook progress, or sign text.
5//! They are keyed by absolute world position and persisted with the chunk.
6
7use basalt_types::Slot;
8
9/// A block entity with typed data.
10///
11/// Each variant holds the state specific to that block type.
12/// New variants are added as more interactive blocks are implemented.
13#[derive(Debug, Clone)]
14pub enum BlockEntity {
15    /// A chest with 27 item slots (3 rows of 9).
16    Chest {
17        /// The 27 inventory slots.
18        slots: Box<[Slot; 27]>,
19    },
20}
21
22/// Type discriminator for [`BlockEntity`].
23///
24/// A small `Copy`/`Eq`/`Hash` enum used to identify the kind of a
25/// block entity without owning its data. Use [`BlockEntity::kind`] to
26/// extract the discriminator.
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum BlockEntityKind {
29    /// A chest block entity.
30    Chest,
31}
32
33impl BlockEntity {
34    /// Creates a new empty chest block entity.
35    pub fn empty_chest() -> Self {
36        Self::Chest {
37            slots: Box::new(std::array::from_fn(|_| Slot::empty())),
38        }
39    }
40
41    /// Returns the [`BlockEntityKind`] discriminator.
42    pub fn kind(&self) -> BlockEntityKind {
43        match self {
44            Self::Chest { .. } => BlockEntityKind::Chest,
45        }
46    }
47}
48
49impl From<&BlockEntity> for BlockEntityKind {
50    fn from(be: &BlockEntity) -> Self {
51        be.kind()
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn empty_chest_has_27_empty_slots() {
61        let be = BlockEntity::empty_chest();
62        match &be {
63            BlockEntity::Chest { slots } => {
64                assert_eq!(slots.len(), 27);
65                assert!(slots.iter().all(|s| s.is_empty()));
66            }
67        }
68    }
69
70    #[test]
71    fn empty_chest_has_chest_kind() {
72        let be = BlockEntity::empty_chest();
73        assert_eq!(be.kind(), BlockEntityKind::Chest);
74        assert_eq!(BlockEntityKind::from(&be), BlockEntityKind::Chest);
75    }
76}