Skip to main content

steel_core/worldgen/feature/features/
chorus_plant.rs

1use steel_registry::vanilla_block_tags::BlockTag;
2
3use crate::behavior::blocks::ChorusPlantBlock;
4
5use super::super::prelude::*;
6use super::super::runner::FeatureDecorationRunner;
7
8impl FeatureDecorationRunner {
9    pub(in crate::worldgen::feature) fn place_chorus_plant_feature(
10        region: &mut WorldGenRegion<'_>,
11        random: &mut WorldgenRandom,
12        origin: BlockPos,
13    ) -> bool {
14        if !region.block_state(origin).is_air()
15            || !region
16                .block_state(origin.below())
17                .get_block()
18                .has_tag(&BlockTag::SUPPORTS_CHORUS_PLANT)
19        {
20            return false;
21        }
22
23        Self::generate_chorus_plant(region, random, origin, 8);
24        true
25    }
26
27    fn generate_chorus_plant(
28        region: &mut WorldGenRegion<'_>,
29        random: &mut WorldgenRandom,
30        target: BlockPos,
31        max_horizontal_spread: i32,
32    ) {
33        let plant = vanilla_blocks::CHORUS_PLANT.default_state();
34        let state = ChorusPlantBlock::state_with_connections(region, target, plant);
35        let _ = region.set_block_state(target, state, UpdateFlags::UPDATE_CLIENTS);
36        Self::grow_chorus_tree_recursive(region, random, target, target, max_horizontal_spread, 0);
37    }
38
39    fn grow_chorus_tree_recursive(
40        region: &mut WorldGenRegion<'_>,
41        random: &mut WorldgenRandom,
42        current: BlockPos,
43        start_pos: BlockPos,
44        max_horizontal_spread: i32,
45        depth: i32,
46    ) {
47        let plant = vanilla_blocks::CHORUS_PLANT.default_state();
48        let mut height = random.next_i32_bounded(4) + 1;
49        if depth == 0 {
50            height += 1;
51        }
52
53        for i in 0..height {
54            let target = current.above_n(i + 1);
55            if !Self::chorus_all_neighbors_empty(region, target, None) {
56                return;
57            }
58
59            let target_state = ChorusPlantBlock::state_with_connections(region, target, plant);
60            let _ = region.set_block_state(target, target_state, UpdateFlags::UPDATE_CLIENTS);
61
62            let below = target.below();
63            let below_state = ChorusPlantBlock::state_with_connections(region, below, plant);
64            let _ = region.set_block_state(below, below_state, UpdateFlags::UPDATE_CLIENTS);
65        }
66
67        let mut placed_stem = false;
68        if depth < 4 {
69            let mut stems = random.next_i32_bounded(4);
70            if depth == 0 {
71                stems += 1;
72            }
73
74            for _ in 0..stems {
75                let direction = Self::random_horizontal_direction(random);
76                let target = current.above_n(height).relative(direction);
77                if (target.x() - start_pos.x()).abs() >= max_horizontal_spread
78                    || (target.z() - start_pos.z()).abs() >= max_horizontal_spread
79                    || !region.block_state(target).is_air()
80                    || !region.block_state(target.below()).is_air()
81                    || !Self::chorus_all_neighbors_empty(region, target, Some(direction.opposite()))
82                {
83                    continue;
84                }
85
86                placed_stem = true;
87                let target_state = ChorusPlantBlock::state_with_connections(region, target, plant);
88                let _ = region.set_block_state(target, target_state, UpdateFlags::UPDATE_CLIENTS);
89
90                let back = target.relative(direction.opposite());
91                let back_state = ChorusPlantBlock::state_with_connections(region, back, plant);
92                let _ = region.set_block_state(back, back_state, UpdateFlags::UPDATE_CLIENTS);
93
94                Self::grow_chorus_tree_recursive(
95                    region,
96                    random,
97                    target,
98                    start_pos,
99                    max_horizontal_spread,
100                    depth + 1,
101                );
102            }
103        }
104
105        if !placed_stem {
106            let flower = vanilla_blocks::CHORUS_FLOWER
107                .default_state()
108                .set_value(&BlockStateProperties::AGE_5, 5);
109            let _ = region.set_block_state(
110                current.above_n(height),
111                flower,
112                UpdateFlags::UPDATE_CLIENTS,
113            );
114        }
115    }
116
117    fn chorus_all_neighbors_empty(
118        region: &WorldGenRegion<'_>,
119        pos: BlockPos,
120        ignore: Option<Direction>,
121    ) -> bool {
122        for direction in Self::VANILLA_HORIZONTAL_DIRECTIONS {
123            if Some(direction) != ignore && !region.block_state(pos.relative(direction)).is_air() {
124                return false;
125            }
126        }
127        true
128    }
129}