Skip to main content

steel_core/worldgen/feature/features/
simple_block.rs

1use 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}