Skip to main content

steel_core/behavior/blocks/vegetation/
huge_mushroom_block.rs

1use steel_macros::block_behavior;
2use steel_registry::blocks::block_state_ext::BlockStateExt;
3use steel_registry::blocks::properties::Direction;
4use steel_utils::{BlockPos, BlockStateId};
5
6use crate::behavior::block::BlockBehavior;
7use crate::behavior::blocks::utils::multiface_face_property;
8use crate::behavior::context::BlockPlaceContext;
9use crate::world::{LevelReader, ScheduledTickAccess};
10
11use super::BlockRef;
12
13/// Vanilla huge mushroom cap and stem behavior.
14#[block_behavior]
15pub struct HugeMushroomBlock {
16    block: BlockRef,
17}
18
19impl HugeMushroomBlock {
20    /// Creates a huge mushroom block behavior.
21    #[must_use]
22    pub const fn new(block: BlockRef) -> Self {
23        Self { block }
24    }
25
26    fn placement_state(&self, world: &dyn LevelReader, pos: BlockPos) -> BlockStateId {
27        let mut state = self.block.default_state();
28        for direction in Direction::ALL {
29            let exposed = world.get_block_state(pos.relative(direction)).get_block() != self.block;
30            state = state.set_value(multiface_face_property(direction), exposed);
31        }
32        state
33    }
34}
35
36impl BlockBehavior for HugeMushroomBlock {
37    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
38        Some(self.placement_state(context.world, context.place_pos()))
39    }
40
41    fn update_shape(
42        &self,
43        state: BlockStateId,
44        _world: &dyn ScheduledTickAccess,
45        _pos: BlockPos,
46        direction: Direction,
47        _neighbor_pos: BlockPos,
48        neighbor_state: BlockStateId,
49    ) -> BlockStateId {
50        if neighbor_state.get_block() == self.block {
51            state.set_value(multiface_face_property(direction), false)
52        } else {
53            state
54        }
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use crate::test_support::TestLevel;
61    use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty};
62    use steel_registry::{init_vanilla_registry, vanilla_blocks};
63
64    use super::*;
65
66    const DOWN: &BoolProperty = &BlockStateProperties::DOWN;
67    const EAST: &BoolProperty = &BlockStateProperties::EAST;
68    const NORTH: &BoolProperty = &BlockStateProperties::NORTH;
69    const SOUTH: &BoolProperty = &BlockStateProperties::SOUTH;
70    const UP: &BoolProperty = &BlockStateProperties::UP;
71    const WEST: &BoolProperty = &BlockStateProperties::WEST;
72
73    #[test]
74    fn placement_hides_only_faces_joined_to_the_same_mushroom_block() {
75        init_vanilla_registry();
76        let pos = BlockPos::new(0, 64, 0);
77        let level = TestLevel::default()
78            .with_block(
79                pos.below(),
80                vanilla_blocks::BROWN_MUSHROOM_BLOCK.default_state(),
81            )
82            .with_block(
83                pos.above(),
84                vanilla_blocks::BROWN_MUSHROOM_BLOCK.default_state(),
85            )
86            .with_block(
87                pos.north(),
88                vanilla_blocks::BROWN_MUSHROOM_BLOCK.default_state(),
89            )
90            .with_block(
91                pos.south(),
92                vanilla_blocks::RED_MUSHROOM_BLOCK.default_state(),
93            );
94        let behavior = HugeMushroomBlock::new(&vanilla_blocks::BROWN_MUSHROOM_BLOCK);
95
96        let state = behavior.placement_state(&level, pos);
97
98        assert!(!state.get_value(DOWN));
99        assert!(!state.get_value(UP));
100        assert!(!state.get_value(NORTH));
101        assert!(state.get_value(SOUTH));
102        assert!(state.get_value(WEST));
103        assert!(state.get_value(EAST));
104    }
105
106    #[test]
107    fn matching_neighbor_hides_the_joined_face() {
108        init_vanilla_registry();
109        let behavior = HugeMushroomBlock::new(&vanilla_blocks::MUSHROOM_STEM);
110        let state = vanilla_blocks::MUSHROOM_STEM.default_state();
111        let level = TestLevel::default();
112
113        let updated = behavior.update_shape(
114            state,
115            &level,
116            BlockPos::ZERO,
117            Direction::East,
118            BlockPos::ZERO.east(),
119            vanilla_blocks::MUSHROOM_STEM.default_state(),
120        );
121
122        assert!(!updated.get_value(EAST));
123    }
124
125    #[test]
126    fn removing_a_neighbor_does_not_restore_a_hidden_face() {
127        init_vanilla_registry();
128        let behavior = HugeMushroomBlock::new(&vanilla_blocks::RED_MUSHROOM_BLOCK);
129        let state = vanilla_blocks::RED_MUSHROOM_BLOCK
130            .default_state()
131            .set_value(WEST, false);
132        let level = TestLevel::default();
133
134        let updated = behavior.update_shape(
135            state,
136            &level,
137            BlockPos::ZERO,
138            Direction::West,
139            BlockPos::ZERO.west(),
140            vanilla_blocks::AIR.default_state(),
141        );
142
143        assert!(!updated.get_value(WEST));
144    }
145}