Skip to main content

steel_core/behavior/blocks/vegetation/
bush_block.rs

1use rand::Rng;
2use steel_macros::block_behavior;
3use steel_utils::types::UpdateFlags;
4use steel_utils::{BlockPos, BlockStateId, Direction};
5
6use super::{BlockRef, default_surviving_state};
7use crate::behavior::blocks::vegetation::Vegetation;
8use crate::behavior::{
9    block::BlockBehavior,
10    blocks::vegetation::vegetation_block::{survival_update_shape, vegetation_can_survive},
11};
12use crate::behavior::{
13    blocks::vegetation::bonemealable::{
14        Bonemealable, find_spreadable_neighbor_pos, has_spreadable_neighbor_pos,
15    },
16    context::BlockPlaceContext,
17};
18use crate::world::{LevelReader, ScheduledTickAccess, World};
19use std::sync::Arc;
20
21/// Vanilla `BushBlock` survival.
22#[block_behavior]
23pub struct BushBlock {
24    block: BlockRef,
25}
26
27impl BushBlock {
28    /// Creates a new bush block behavior.
29    #[must_use]
30    pub const fn new(block: BlockRef) -> Self {
31        Self { block }
32    }
33}
34
35impl BlockBehavior for BushBlock {
36    fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
37        vegetation_can_survive(self, state, world, pos)
38    }
39
40    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
41        default_surviving_state(self.block, self, context)
42    }
43    fn update_shape(
44        &self,
45        state: BlockStateId,
46        world: &dyn ScheduledTickAccess,
47        pos: BlockPos,
48        _direction: Direction,
49        _neighbor_pos: BlockPos,
50        _neighbor_state: BlockStateId,
51    ) -> BlockStateId {
52        survival_update_shape(self, state, world, pos)
53    }
54    fn as_bonemealable(&self) -> Option<&dyn Bonemealable> {
55        Some(self)
56    }
57}
58impl Vegetation for BushBlock {}
59impl Bonemealable for BushBlock {
60    fn is_valid_bonemeal_target(
61        &self,
62        state: BlockStateId,
63        world: &dyn LevelReader,
64        pos: BlockPos,
65    ) -> bool {
66        has_spreadable_neighbor_pos(world, pos, state)
67    }
68    fn perform_bonemeal(
69        &self,
70        state: BlockStateId,
71        world: &Arc<World>,
72        _rng: &mut dyn Rng,
73        pos: BlockPos,
74    ) {
75        let Some(block_pos) = find_spreadable_neighbor_pos(world, pos, state) else {
76            return;
77        };
78        world.set_block(
79            block_pos,
80            self.block.default_state(),
81            UpdateFlags::UPDATE_ALL,
82        );
83    }
84}