Skip to main content

steel_core/behavior/blocks/vegetation/
grass_block.rs

1use steel_macros::block_behavior;
2use steel_registry::blocks::BlockRef;
3use steel_registry::vanilla_blocks;
4use steel_utils::{BlockPos, BlockStateId, Direction};
5
6use super::snowy_block::{snowy_placement_state, update_snowy_shape};
7use super::spreading_grass_block::SpreadingGrassBlock;
8use crate::behavior::block::BlockBehavior;
9use crate::behavior::context::BlockPlaceContext;
10use crate::world::{ScheduledTickAccess, World};
11use std::sync::Arc;
12
13/// Behavior for grass blocks.
14// TODO: Implement bonemeal behavior.
15#[block_behavior]
16pub struct GrassBlock {
17    block: BlockRef,
18}
19
20impl GrassBlock {
21    /// Creates a new grass block behavior.
22    #[must_use]
23    pub const fn new(block: BlockRef) -> Self {
24        Self { block }
25    }
26}
27
28impl BlockBehavior for GrassBlock {
29    fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
30        Some(snowy_placement_state(self.block, context))
31    }
32
33    fn update_shape(
34        &self,
35        state: BlockStateId,
36        _world: &dyn ScheduledTickAccess,
37        _pos: BlockPos,
38        direction: Direction,
39        _neighbor_pos: BlockPos,
40        neighbor_state: BlockStateId,
41    ) -> BlockStateId {
42        update_snowy_shape(state, direction, neighbor_state)
43    }
44
45    fn random_tick(&self, state: BlockStateId, world: &Arc<World>, pos: BlockPos) {
46        SpreadingGrassBlock::random_tick(
47            &vanilla_blocks::GRASS_BLOCK,
48            &vanilla_blocks::DIRT,
49            state,
50            world,
51            pos,
52        );
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use steel_registry::blocks::block_state_ext::BlockStateExt;
59    use steel_registry::blocks::properties::BlockStateProperties;
60    use steel_registry::{init_vanilla_registry, vanilla_blocks};
61    use steel_utils::{BlockPos, Direction};
62
63    use super::*;
64    use crate::behavior::init_behaviors;
65    use crate::test_support::TestLevel;
66
67    #[test]
68    fn grass_block_updates_snowy_state() {
69        init_vanilla_registry();
70        init_behaviors();
71
72        let level = TestLevel::default();
73        let pos = BlockPos::new(0, 64, 0);
74        let behavior = GrassBlock::new(&vanilla_blocks::GRASS_BLOCK);
75
76        let non_snowy = vanilla_blocks::GRASS_BLOCK.default_state();
77        let snowy = behavior.update_shape(
78            non_snowy,
79            &level,
80            pos,
81            Direction::Up,
82            pos.above(),
83            vanilla_blocks::SNOW.default_state(),
84        );
85        assert!(snowy.get_value(&BlockStateProperties::SNOWY));
86
87        let cleared = behavior.update_shape(
88            snowy,
89            &level,
90            pos,
91            Direction::Up,
92            pos.above(),
93            vanilla_blocks::AIR.default_state(),
94        );
95        assert!(!cleared.get_value(&BlockStateProperties::SNOWY));
96    }
97}