Skip to main content

steel_core/behavior/blocks/vegetation/
cactus_flower_block.rs

1//! Cactus flower block behavior.
2//!
3//! Cactus flower is a vegetation block that can be placed on cactus, farmland,
4//! or any block with a sturdy center face on top.
5
6use steel_macros::block_behavior;
7use steel_registry::blocks::BlockRef;
8use steel_registry::blocks::block_state_ext::BlockStateExt;
9use steel_registry::blocks::properties::Direction;
10use steel_registry::blocks::shapes::SupportType;
11use steel_registry::vanilla_block_tags::BlockTag;
12use steel_registry::vanilla_blocks;
13use steel_utils::{BlockPos, BlockStateId};
14
15use crate::behavior::block::BlockBehavior;
16use crate::behavior::context::BlockPlaceContext;
17use crate::world::{LevelReader, ScheduledTickAccess};
18
19/// Behavior for cactus flower blocks.
20#[block_behavior]
21pub struct CactusFlowerBlock {
22    block: BlockRef,
23}
24
25impl CactusFlowerBlock {
26    /// Creates a new cactus flower block behavior.
27    #[must_use]
28    pub const fn new(block: BlockRef) -> Self {
29        Self { block }
30    }
31}
32
33impl BlockBehavior for CactusFlowerBlock {
34    /// Checks if the block below can support a cactus flower.
35    ///
36    /// Vanilla `CactusFlowerBlock.mayPlaceOn`: accepts the support-override tag
37    /// or any block with a sturdy center face on top.
38    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
39        let below_pos = pos.below();
40        let below = world.get_block_state(below_pos);
41        below
42            .get_block()
43            .has_tag(&BlockTag::SUPPORT_OVERRIDE_CACTUS_FLOWER)
44            || world.is_face_sturdy_for(below, below_pos, Direction::Up, SupportType::Center)
45    }
46
47    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
48        let state = self.block.default_state();
49        self.can_survive(state, context.world, context.place_pos())
50            .then_some(state)
51    }
52
53    fn update_shape(
54        &self,
55        state: BlockStateId,
56        world: &dyn ScheduledTickAccess,
57        pos: BlockPos,
58        _direction: Direction,
59        _neighbor_pos: BlockPos,
60        _neighbor_state: BlockStateId,
61    ) -> BlockStateId {
62        if self.can_survive(state, world, pos) {
63            state
64        } else {
65            vanilla_blocks::AIR.default_state()
66        }
67    }
68}