Skip to main content

steel_core/worldgen/feature/
predicates.rs

1use glam::IVec3;
2
3use super::prelude::*;
4use super::runner::FeatureDecorationRunner;
5
6impl FeatureDecorationRunner {
7    pub(super) fn test_optional_block_predicate(
8        region: &WorldGenRegion<'_>,
9        registry: &Registry,
10        predicate: Option<&BlockPredicate>,
11        origin: BlockPos,
12    ) -> bool {
13        predicate
14            .is_none_or(|predicate| Self::test_block_predicate(region, registry, predicate, origin))
15    }
16
17    pub(super) fn biome_allows_feature(
18        region: &WorldGenRegion<'_>,
19        registry: &Registry,
20        biome_zoom_seed: i64,
21        origin: BlockPos,
22        biome_filter_feature_key: Option<&Identifier>,
23    ) -> bool {
24        let biome_id = fuzzed_biome_at_block(biome_zoom_seed, origin, |quart| {
25            region.noise_biome_id(quart.x, quart.y, quart.z)
26        });
27        let Some(biome) = registry.biomes.by_id(usize::from(biome_id)) else {
28            panic!("biome filter resolved unknown biome id {biome_id}");
29        };
30        let Some(target_feature_key) = biome_filter_feature_key else {
31            panic!(
32                "Tried to biome check an unregistered feature, or a feature that should not restrict the biome"
33            );
34        };
35
36        biome
37            .features
38            .iter()
39            .flatten()
40            .any(|feature_key| feature_key == target_feature_key)
41    }
42
43    pub(super) fn test_block_predicate(
44        region: &WorldGenRegion<'_>,
45        registry: &Registry,
46        predicate: &BlockPredicate,
47        origin: BlockPos,
48    ) -> bool {
49        match predicate {
50            BlockPredicate::True => true,
51            BlockPredicate::AllOf { predicates } => predicates
52                .iter()
53                .all(|predicate| Self::test_block_predicate(region, registry, predicate, origin)),
54            BlockPredicate::AnyOf { predicates } => predicates
55                .iter()
56                .any(|predicate| Self::test_block_predicate(region, registry, predicate, origin)),
57            BlockPredicate::Not { predicate } => {
58                !Self::test_block_predicate(region, registry, predicate, origin)
59            }
60            BlockPredicate::MatchingBlockTag { tag, offset } => {
61                let state = region.block_state(Self::offset(origin, offset));
62                state.get_block().has_tag(tag)
63            }
64            BlockPredicate::MatchingBlocks { blocks, offset } => {
65                let state = region.block_state(Self::offset(origin, offset));
66                blocks.0.contains(&state.get_block())
67            }
68            BlockPredicate::MatchingFluids { fluids, offset } => {
69                let state = region.block_state(Self::offset(origin, offset));
70                let fluid_state = get_fluid_state_from_block(state);
71                fluids.0.contains(&fluid_state.fluid_id)
72            }
73            BlockPredicate::Solid { offset } => {
74                region.block_state(Self::offset(origin, offset)).is_solid()
75            }
76            BlockPredicate::WouldSurvive { state, offset } => {
77                let state = Self::block_state_from_data(registry, state);
78                let behavior = BLOCK_BEHAVIORS.get_behavior(state.get_block());
79                behavior.can_survive(state, region, Self::offset(origin, offset))
80            }
81            BlockPredicate::Replaceable { offset } => region
82                .block_state(Self::offset(origin, offset))
83                .is_replaceable(),
84            BlockPredicate::HasSturdyFace { direction, offset } => {
85                let position = Self::offset(origin, offset);
86                region
87                    .block_state(position)
88                    .is_face_sturdy_at(position, *direction)
89            }
90            BlockPredicate::InsideWorldBounds { offset } => {
91                let position = Self::offset(origin, offset);
92                !region.is_outside_build_height(position.y())
93            }
94        }
95    }
96
97    pub(super) fn offset(origin: BlockPos, offset: &IVec3) -> BlockPos {
98        BlockPos(origin.0 + offset)
99    }
100}