Skip to main content

steel_core/block_state_provider/
predicates.rs

1use super::BlockStateProviderEvaluator;
2use crate::{
3    behavior::BLOCK_BEHAVIORS, fluid::state::get_fluid_state_from_block, world::LevelReader,
4};
5use glam::IVec3;
6use steel_registry::{
7    Registry, blocks::block_state_ext::BlockStateExt as _, feature::BlockPredicate,
8};
9use steel_utils::BlockPos;
10
11impl BlockStateProviderEvaluator {
12    pub(crate) fn test_block_predicate(
13        level: &dyn LevelReader,
14        registry: &Registry,
15        predicate: &BlockPredicate,
16        origin: BlockPos,
17    ) -> bool {
18        match predicate {
19            BlockPredicate::True => true,
20            BlockPredicate::AllOf { predicates } => predicates
21                .iter()
22                .all(|predicate| Self::test_block_predicate(level, registry, predicate, origin)),
23            BlockPredicate::AnyOf { predicates } => predicates
24                .iter()
25                .any(|predicate| Self::test_block_predicate(level, registry, predicate, origin)),
26            BlockPredicate::Not { predicate } => {
27                !Self::test_block_predicate(level, registry, predicate, origin)
28            }
29            BlockPredicate::MatchingBlockTag { tag, offset } => {
30                let state = level.get_block_state(Self::offset(origin, offset));
31                state.get_block().has_tag(tag)
32            }
33            BlockPredicate::MatchingBlocks { blocks, offset } => {
34                let state = level.get_block_state(Self::offset(origin, offset));
35                blocks.0.contains(&state.get_block())
36            }
37            BlockPredicate::MatchingFluids { fluids, offset } => {
38                let state = level.get_block_state(Self::offset(origin, offset));
39                let fluid_state = get_fluid_state_from_block(state);
40                fluids.0.contains(&fluid_state.fluid_id)
41            }
42            BlockPredicate::Solid { offset } => level
43                .get_block_state(Self::offset(origin, offset))
44                .is_solid(),
45            BlockPredicate::WouldSurvive { state, offset } => {
46                let state = Self::block_state_from_data(registry, state);
47                let behavior = BLOCK_BEHAVIORS.get_behavior(state.get_block());
48                behavior.can_survive(state, level, Self::offset(origin, offset))
49            }
50            BlockPredicate::Replaceable { offset } => level
51                .get_block_state(Self::offset(origin, offset))
52                .is_replaceable(),
53            BlockPredicate::HasSturdyFace { direction, offset } => {
54                let position = Self::offset(origin, offset);
55                level
56                    .get_block_state(position)
57                    .is_face_sturdy_at(position, *direction)
58            }
59            BlockPredicate::InsideWorldBounds { offset } => {
60                let position = Self::offset(origin, offset);
61                !level.is_outside_build_height(position.y())
62            }
63            BlockPredicate::HeightRange {
64                min_inclusive,
65                max_inclusive,
66            } => {
67                let min_y =
68                    min_inclusive.resolve_y(level.min_y(), level.height(), level.sea_level());
69                let max_y =
70                    max_inclusive.resolve_y(level.min_y(), level.height(), level.sea_level());
71
72                (min_y..=max_y).contains(&origin.y())
73            }
74            BlockPredicate::VolumeMatch { min, max, matches } => {
75                for x in min.x..=max.x {
76                    for y in min.y..=max.y {
77                        for z in min.z..=max.z {
78                            if !Self::test_block_predicate(
79                                level,
80                                registry,
81                                matches,
82                                Self::offset(origin, &IVec3::new(x, y, z)),
83                            ) {
84                                return false;
85                            }
86                        }
87                    }
88                }
89
90                true
91            }
92        }
93    }
94
95    pub(crate) fn offset(origin: BlockPos, offset: &IVec3) -> BlockPos {
96        BlockPos(origin.0 + offset)
97    }
98}