Skip to main content

steel_core/behavior/blocks/vegetation/
flower_bed_block.rs

1use crate::behavior::BlockPlaceContext;
2use crate::behavior::blocks::vegetation::segmentable_block::{
3    segmentable_can_be_replaced, segmentable_get_state_for_placement,
4};
5use crate::world::{ScheduledTickAccess, World};
6use rand::prelude::Rng;
7use std::sync::Arc;
8use steel_macros::block_behavior;
9use steel_registry::REGISTRY;
10use steel_registry::blocks::{
11    block_state_ext::BlockStateExt,
12    properties::{BlockStateProperties, IntProperty},
13};
14use steel_registry::item_stack::ItemStack;
15use steel_registry::vanilla_block_tags::BlockTag;
16use steel_utils::{BlockPos, BlockStateId, Direction, types::UpdateFlags};
17
18use crate::behavior::block::BlockBehavior;
19use crate::behavior::blocks::vegetation::bonemealable::Bonemealable;
20use crate::world::LevelReader;
21
22use super::{BlockRef, survives_on_tag, vegetation_block::survival_update_shape};
23
24const SEGMENT_PROPERTY: IntProperty = BlockStateProperties::FLOWER_AMOUNT;
25
26/// Vanilla `FlowerBedBlock` survival.
27#[block_behavior]
28pub struct FlowerBedBlock {
29    block: BlockRef,
30}
31
32impl FlowerBedBlock {
33    /// Creates a new flower-bed block behavior.
34    #[must_use]
35    pub const fn new(block: BlockRef) -> Self {
36        Self { block }
37    }
38}
39
40impl BlockBehavior for FlowerBedBlock {
41    fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
42        survives_on_tag(world, pos, &BlockTag::SUPPORTS_VEGETATION)
43    }
44
45    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
46        Some(segmentable_get_state_for_placement(
47            self.block,
48            &SEGMENT_PROPERTY,
49            context,
50        ))
51    }
52
53    fn can_be_replaced(&self, state: BlockStateId, context: &BlockPlaceContext<'_>) -> bool {
54        segmentable_can_be_replaced(&SEGMENT_PROPERTY, state, context)
55    }
56
57    fn update_shape(
58        &self,
59        state: BlockStateId,
60        world: &dyn ScheduledTickAccess,
61        pos: BlockPos,
62        _direction: Direction,
63        _neighbor_pos: BlockPos,
64        _neighbor_state: BlockStateId,
65    ) -> BlockStateId {
66        survival_update_shape(self, state, world, pos)
67    }
68
69    fn as_bonemealable(&self) -> Option<&dyn Bonemealable> {
70        Some(self)
71    }
72}
73
74impl Bonemealable for FlowerBedBlock {
75    fn is_valid_bonemeal_target(
76        &self,
77        _state: BlockStateId,
78        _world: &dyn LevelReader,
79        _pos: BlockPos,
80    ) -> bool {
81        true
82    }
83
84    fn perform_bonemeal(
85        &self,
86        state: BlockStateId,
87        world: &Arc<World>,
88        _rng: &mut dyn Rng,
89        pos: BlockPos,
90    ) {
91        let amount = state.get_value(&SEGMENT_PROPERTY);
92        if amount < 4 {
93            world.set_block(
94                pos,
95                state.set_value(&SEGMENT_PROPERTY, amount + 1),
96                UpdateFlags::UPDATE_CLIENTS,
97            );
98        } else {
99            world.pop_resource(pos, ItemStack::new(REGISTRY.items.by_block(self.block)));
100        }
101    }
102}