steel_core/worldgen/feature/features/
simple_block.rs1use super::super::prelude::*;
2use super::super::runner::FeatureDecorationRunner;
3use crate::behavior::blocks::MossyCarpetBlock;
4
5impl FeatureDecorationRunner {
6 pub(in crate::worldgen::feature) fn place_simple_block_feature(
7 region: &mut WorldGenRegion<'_>,
8 registry: &Registry,
9 random: &mut WorldgenRandom,
10 config: &SimpleBlockConfiguration,
11 origin: BlockPos,
12 ) -> bool {
13 let Some(state_to_place) =
14 BlockStateProviderEvaluator::sample_block_state_provider_optional(
15 region,
16 registry,
17 random,
18 &config.to_place,
19 origin,
20 )
21 else {
22 return false;
23 };
24 let behavior = BLOCK_BEHAVIORS.get_behavior(state_to_place.get_block());
25 if !behavior.can_survive(state_to_place, region, origin) {
26 return false;
27 }
28
29 if Self::is_double_plant_block(state_to_place.get_block()) {
30 let above_state = region.block_state(origin.above());
31 if !above_state.is_air()
32 && (state_to_place.get_fluid_state() != above_state.get_fluid_state()
33 || !above_state.is_replaceable())
34 {
35 return false;
36 }
37 Self::place_double_plant(region, state_to_place, origin);
38 } else if state_to_place.get_block() == &vanilla_blocks::PALE_MOSS_CARPET {
39 Self::place_mossy_carpet(region, origin);
40 } else {
41 let _ = region.set_block_state(origin, state_to_place, UpdateFlags::UPDATE_CLIENTS);
42 }
43
44 if config.schedule_tick {
45 let placed_state = region.block_state(origin);
46 let _ = region.schedule_block_tick_default(origin, placed_state.get_block(), 1);
47 }
48
49 true
50 }
51
52 pub(in crate::worldgen::feature) fn is_double_plant_block(block: BlockRef) -> bool {
53 block == &vanilla_blocks::SUNFLOWER
54 || block == &vanilla_blocks::LILAC
55 || block == &vanilla_blocks::ROSE_BUSH
56 || block == &vanilla_blocks::PEONY
57 || block == &vanilla_blocks::TALL_GRASS
58 || block == &vanilla_blocks::LARGE_FERN
59 || block == &vanilla_blocks::TALL_SEAGRASS
60 || block == &vanilla_blocks::PITCHER_PLANT
61 || block == &vanilla_blocks::SMALL_DRIPLEAF
62 }
63
64 pub(in crate::worldgen::feature) fn place_double_plant(
65 region: &mut WorldGenRegion<'_>,
66 state: BlockStateId,
67 lower_pos: BlockPos,
68 ) {
69 let upper_pos = lower_pos.above();
70 let lower_state = Self::copy_waterlogged_from(
71 region,
72 lower_pos,
73 state.set_value(
74 &BlockStateProperties::DOUBLE_BLOCK_HALF,
75 DoubleBlockHalf::Lower,
76 ),
77 );
78 let upper_state = Self::copy_waterlogged_from(
79 region,
80 upper_pos,
81 state.set_value(
82 &BlockStateProperties::DOUBLE_BLOCK_HALF,
83 DoubleBlockHalf::Upper,
84 ),
85 );
86 let _ = region.set_block_state(lower_pos, lower_state, UpdateFlags::UPDATE_CLIENTS);
87 let _ = region.set_block_state(upper_pos, upper_state, UpdateFlags::UPDATE_CLIENTS);
88 }
89
90 pub(in crate::worldgen::feature) fn copy_waterlogged_from(
91 region: &impl LevelReader,
92 pos: BlockPos,
93 state: BlockStateId,
94 ) -> BlockStateId {
95 if state
96 .try_get_value(&BlockStateProperties::WATERLOGGED)
97 .is_none()
98 {
99 return state;
100 }
101
102 let waterlogged = get_fluid_state_from_block(region.get_block_state(pos)).is_water();
103 state.set_value(&BlockStateProperties::WATERLOGGED, waterlogged)
104 }
105
106 pub(in crate::worldgen::feature) fn place_mossy_carpet(
107 region: &mut WorldGenRegion<'_>,
108 pos: BlockPos,
109 ) {
110 let simple_carpet_layer = vanilla_blocks::PALE_MOSS_CARPET.default_state();
111 let adjusted_carpet_layer =
112 MossyCarpetBlock::updated_state(simple_carpet_layer, region, pos, true);
113 let _ = region.set_block_state(pos, adjusted_carpet_layer, UpdateFlags::UPDATE_CLIENTS);
114
115 let topper = Self::create_mossy_carpet_topper(region, pos);
116 if !topper.is_air() {
117 let _ = region.set_block_state(pos.above(), topper, UpdateFlags::UPDATE_CLIENTS);
118 let update_bottom =
119 MossyCarpetBlock::updated_state(adjusted_carpet_layer, region, pos, true);
120 let _ = region.set_block_state(pos, update_bottom, UpdateFlags::UPDATE_CLIENTS);
121 }
122 }
123
124 pub(in crate::worldgen::feature) fn create_mossy_carpet_topper(
125 region: &mut WorldGenRegion<'_>,
126 pos: BlockPos,
127 ) -> BlockStateId {
128 let above = pos.above();
129 let above_previous_state = region.block_state(above);
130 let is_mossy_carpet_above =
131 above_previous_state.get_block() == &vanilla_blocks::PALE_MOSS_CARPET;
132 if (!is_mossy_carpet_above
133 || !above_previous_state.get_value(&BlockStateProperties::BOTTOM))
134 && (is_mossy_carpet_above || above_previous_state.is_replaceable())
135 {
136 let no_base_state = vanilla_blocks::PALE_MOSS_CARPET
137 .default_state()
138 .set_value(&BlockStateProperties::BOTTOM, false);
139 let mut above_state =
140 MossyCarpetBlock::updated_state(no_base_state, region, above, true);
141
142 for direction in MossyCarpetBlock::HORIZONTAL_DIRECTIONS {
143 let property = MossyCarpetBlock::wall_property(direction);
144 if above_state.get_value(property) != WallSide::None
145 && !region.random_mut().next_bool()
146 {
147 above_state = above_state.set_value(property, WallSide::None);
148 }
149 }
150
151 if MossyCarpetBlock::has_faces(above_state) && above_state != above_previous_state {
152 above_state
153 } else {
154 vanilla_blocks::AIR.default_state()
155 }
156 } else {
157 vanilla_blocks::AIR.default_state()
158 }
159 }
160
161 pub(in crate::worldgen::feature) fn can_attach_to_multiface(
162 region: &WorldGenRegion<'_>,
163 pos: BlockPos,
164 direction_towards_neighbor: Direction,
165 ) -> bool {
166 let neighbor_pos = pos.relative(direction_towards_neighbor);
167 let neighbor_state = region.block_state(neighbor_pos);
168 let support_direction = direction_towards_neighbor.opposite();
169 shapes::is_offset_face_full(
170 neighbor_state.get_support_shape_at(neighbor_pos),
171 support_direction,
172 ) || shapes::is_offset_face_full(
173 neighbor_state.get_collision_shape_at(neighbor_pos),
174 support_direction,
175 )
176 }
177}