steel_core/worldgen/feature/features/
chorus_plant.rs1use 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}