Skip to main content

steel_core/behavior/block/
registry.rs

1use super::{
2    BlockBehavior, BlockPlaceContext, BlockPos, BlockRef, BlockStateId, Direction, REGISTRY,
3    RegistryEntry, RegistryExt, ScheduledTickAccess, schedule_water_tick_if_waterlogged,
4};
5
6/// Default placement plus the common water tick used by unported waterlogged blocks.
7pub struct DefaultBlockBehavior {
8    block: BlockRef,
9}
10
11impl DefaultBlockBehavior {
12    /// Creates a new default block behavior for the given block.
13    #[must_use]
14    pub const fn new(block: BlockRef) -> Self {
15        Self { block }
16    }
17}
18
19impl BlockBehavior for DefaultBlockBehavior {
20    fn update_shape(
21        &self,
22        state: BlockStateId,
23        world: &dyn ScheduledTickAccess,
24        pos: BlockPos,
25        _direction: Direction,
26        _neighbor_pos: BlockPos,
27        _neighbor_state: BlockStateId,
28    ) -> BlockStateId {
29        schedule_water_tick_if_waterlogged(state, world, pos);
30        state
31    }
32
33    // This fallback only preserves generic block placement. Blocks with
34    // class-specific placement rules still need their own behavior.
35    fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
36        Some(self.block.default_state())
37    }
38}
39
40/// Registry for block behaviors.
41///
42/// Created after the main registry is frozen. All blocks are initialized with
43/// default behaviors, then custom behaviors are registered for specific blocks.
44pub struct BlockBehaviorRegistry {
45    behaviors: Vec<Box<dyn BlockBehavior>>,
46}
47
48impl BlockBehaviorRegistry {
49    /// Get all behaviors.
50    #[cfg(feature = "flint")]
51    #[must_use]
52    pub fn get_behaviors(&self) -> &[Box<dyn BlockBehavior>] {
53        &self.behaviors
54    }
55
56    /// Creates a new behavior registry with default behaviors for all blocks.
57    #[must_use]
58    pub fn new() -> Self {
59        let block_count = REGISTRY.blocks.len();
60        let mut behaviors: Vec<Box<dyn BlockBehavior>> = Vec::with_capacity(block_count);
61
62        // Initialize all blocks with default behavior
63        for (_, block) in REGISTRY.blocks.iter() {
64            behaviors.push(Box::new(DefaultBlockBehavior::new(block)));
65        }
66
67        Self { behaviors }
68    }
69
70    /// Sets a custom behavior for a block.
71    pub fn set_behavior(&mut self, block: BlockRef, behavior: Box<dyn BlockBehavior>) {
72        let id = block.id();
73        self.behaviors[id] = behavior;
74    }
75
76    /// Gets the behavior for a block.
77    #[must_use]
78    pub fn get_behavior(&self, block: BlockRef) -> &dyn BlockBehavior {
79        let id = block.id();
80        self.behaviors[id].as_ref()
81    }
82
83    /// Gets the behavior for a block state.
84    #[must_use]
85    pub fn get_behavior_for_state(&self, state: BlockStateId) -> Option<&dyn BlockBehavior> {
86        let block = REGISTRY.blocks.by_state_id(state)?;
87        Some(self.get_behavior(block))
88    }
89}
90
91impl Default for BlockBehaviorRegistry {
92    fn default() -> Self {
93        Self::new()
94    }
95}