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