Skip to main content

steel_core/behavior/blocks/vegetation/
mushroom_block.rs

1use steel_macros::block_behavior;
2use steel_registry::blocks::block_state_ext::BlockStateExt;
3use steel_registry::blocks::properties::Direction;
4use steel_registry::vanilla_block_tags::BlockTag;
5use steel_registry::vanilla_blocks;
6use steel_utils::{BlockPos, BlockStateId};
7
8use crate::behavior::block::BlockBehavior;
9use crate::behavior::context::BlockPlaceContext;
10use crate::world::{LevelReader, ScheduledTickAccess};
11
12use super::{BlockRef, default_surviving_state};
13
14/// Vanilla `MushroomBlock` survival.
15// TODO: Implement full vanilla behavior beyond can_survive.
16#[block_behavior]
17pub struct MushroomBlock {
18    block: BlockRef,
19}
20
21impl MushroomBlock {
22    /// Creates a new mushroom block behavior.
23    #[must_use]
24    pub const fn new(block: BlockRef) -> Self {
25        Self { block }
26    }
27}
28
29impl BlockBehavior for MushroomBlock {
30    fn update_shape(
31        &self,
32        state: BlockStateId,
33        world: &dyn ScheduledTickAccess,
34        pos: BlockPos,
35        _direction: Direction,
36        _neighbor_pos: BlockPos,
37        _neighbor_state: BlockStateId,
38    ) -> BlockStateId {
39        if self.can_survive(state, world, pos) {
40            state
41        } else {
42            vanilla_blocks::AIR.default_state()
43        }
44    }
45
46    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
47        let below_pos = pos.below();
48        let below = world.get_block_state(below_pos);
49        if below
50            .get_block()
51            .has_tag(&BlockTag::OVERRIDES_MUSHROOM_LIGHT_REQUIREMENT)
52        {
53            return true;
54        }
55
56        world.raw_brightness(pos, 0) < 13 && below.is_solid_render()
57    }
58
59    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
60        default_surviving_state(self.block, self, context)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use steel_registry::{REGISTRY, init_vanilla_registry, vanilla_blocks};
67
68    use crate::test_support::TestLevel;
69
70    use super::*;
71
72    fn single_support_level(support: BlockStateId, raw_brightness: u8) -> TestLevel {
73        TestLevel::default()
74            .with_block(BlockPos::ZERO.below(), support)
75            .with_raw_brightness(raw_brightness)
76    }
77
78    #[test]
79    fn mushroom_survival_uses_solid_render_support() {
80        init_vanilla_registry();
81
82        let mushroom = MushroomBlock::new(&vanilla_blocks::BROWN_MUSHROOM);
83        let state = REGISTRY
84            .blocks
85            .get_default_state_id(&vanilla_blocks::BROWN_MUSHROOM);
86        let pos = BlockPos::new(0, 0, 0);
87
88        let grass_block = REGISTRY
89            .blocks
90            .get_default_state_id(&vanilla_blocks::GRASS_BLOCK);
91        assert!(mushroom.can_survive(state, &single_support_level(grass_block, 12), pos));
92        assert!(!mushroom.can_survive(state, &single_support_level(grass_block, 13), pos));
93
94        let oak_leaves = REGISTRY
95            .blocks
96            .get_default_state_id(&vanilla_blocks::OAK_LEAVES);
97        assert!(!mushroom.can_survive(state, &single_support_level(oak_leaves, 0), pos));
98
99        let podzol = REGISTRY
100            .blocks
101            .get_default_state_id(&vanilla_blocks::PODZOL);
102        assert!(mushroom.can_survive(state, &single_support_level(podzol, 15), pos));
103    }
104}