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) = 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}