steel_core/worldgen/feature/
predicates.rs1use 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}