Skip to main content

steel_core/behavior/blocks/vegetation/
spreading_grass_block.rs

1use super::snowy_block::is_snowy_setting;
2use crate::behavior::BlockRef;
3use crate::chunk::light::{MAX_LIGHT_LEVEL, get_light_block_into};
4use crate::world::{LevelReader, World};
5use std::sync::Arc;
6use steel_registry::blocks::properties::BlockStateProperties;
7use steel_registry::entity_data::Direction;
8use steel_registry::vanilla_blocks;
9use steel_registry::{blocks::block_state_ext::BlockStateExt, vanilla_fluid_tags::FluidTag};
10use steel_utils::types::UpdateFlags;
11use steel_utils::{BlockPos, BlockStateId};
12
13/// A structure implementing the spreading of grass blocks and its variants
14pub struct SpreadingGrassBlock {}
15
16impl SpreadingGrassBlock {
17    fn can_stay_alive(state: BlockStateId, level: &Arc<World>, pos: BlockPos) -> bool {
18        let above = pos.above();
19        let above_state: BlockStateId = level.get_block_state(above);
20        if above_state.get_block() == &vanilla_blocks::SNOW
21            && above_state.get_value(&BlockStateProperties::LAYERS) == 1
22        {
23            return true;
24        }
25        if above_state.get_fluid_state().is_full() {
26            return false;
27        }
28
29        let light_dampening_top_face = get_light_block_into(
30            state,
31            above_state,
32            Direction::Up,
33            above_state.get_light_dampening(),
34        );
35        light_dampening_top_face < MAX_LIGHT_LEVEL
36    }
37    fn can_propagate(state: BlockStateId, level: &Arc<World>, pos: BlockPos) -> bool {
38        Self::can_stay_alive(state, level, pos)
39            && !level
40                .get_block_state(pos.above())
41                .get_fluid_state()
42                .fluid_id
43                .has_tag(&FluidTag::WATER)
44    }
45
46    /// Implements random tick for grass block and its variants (like mycelium)
47    /// It allows blocks to spread to base blocks, and will make them disappear if there is any block ontop of them
48    pub fn random_tick(
49        own: BlockRef,
50        base: BlockRef,
51        state: BlockStateId,
52        world: &Arc<World>,
53        pos: BlockPos,
54    ) {
55        if !Self::can_stay_alive(state, world, pos) {
56            world.set_block(pos, base.default_state(), UpdateFlags::UPDATE_ALL);
57        } else if world.max_local_raw_brightness(pos.above(), world.sky_darkening()) >= 9 {
58            let default_block_state = own.default_state();
59
60            for _ in 0..4 {
61                let test_pos = pos.offset(
62                    rand::random_range(-1..2),
63                    rand::random_range(-3..2),
64                    rand::random_range(-1..2),
65                );
66                if world.get_block_state(test_pos).get_block() == base
67                    && Self::can_propagate(default_block_state, world, test_pos)
68                {
69                    world.set_block(
70                        test_pos,
71                        default_block_state.set_value(
72                            &BlockStateProperties::SNOWY,
73                            is_snowy_setting(world.get_block_state(test_pos.above())),
74                        ),
75                        UpdateFlags::UPDATE_ALL,
76                    );
77                }
78            }
79        }
80    }
81}