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