steel_core/behavior/blocks/building/
barrier_block.rs1use steel_macros::block_behavior;
2use steel_registry::blocks::BlockRef;
3use steel_registry::blocks::block_state_ext::BlockStateExt as _;
4use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty, Direction};
5use steel_registry::fluid::FluidRef;
6use steel_registry::vanilla_fluids;
7use steel_utils::types::GameType;
8use steel_utils::{BlockPos, BlockStateId};
9
10use crate::behavior::block::schedule_water_tick_if_waterlogged;
11use crate::behavior::{BlockBehavior, BlockPlaceContext};
12use crate::player::Player;
13use crate::world::ScheduledTickAccess;
14
15#[block_behavior]
17pub struct BarrierBlock {
18 block: BlockRef,
19}
20
21const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
22
23impl BarrierBlock {
24 #[must_use]
26 pub const fn new(block: BlockRef) -> Self {
27 Self { block }
28 }
29}
30
31impl BlockBehavior for BarrierBlock {
32 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
33 Some(
34 self.block
35 .default_state()
36 .set_value(WATERLOGGED, context.is_water_source()),
37 )
38 }
39
40 fn update_shape(
41 &self,
42 state: BlockStateId,
43 world: &dyn ScheduledTickAccess,
44 pos: BlockPos,
45 _direction: Direction,
46 _neighbor_pos: BlockPos,
47 _neighbor_state: BlockStateId,
48 ) -> BlockStateId {
49 schedule_water_tick_if_waterlogged(state, world, pos);
50
51 state
52 }
53
54 fn can_place_liquid(&self, _state: BlockStateId, _fluid: FluidRef) -> bool {
55 false
56 }
57
58 fn can_place_liquid_with_player(
59 &self,
60 state: BlockStateId,
61 fluid: FluidRef,
62 player: Option<&Player>,
63 ) -> bool {
64 player.is_some_and(|player| player.game_mode() == GameType::Creative)
65 && state.try_get_value(WATERLOGGED).is_some()
66 && fluid == &vanilla_fluids::WATER
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::behavior::{BLOCK_BEHAVIORS, init_behaviors};
74 use crate::test_support::TestLevel;
75 use steel_registry::{init_vanilla_registry, vanilla_blocks};
76
77 #[test]
78 fn registered_barrier_rejects_no_user_liquid_placement() {
79 init_vanilla_registry();
80 init_behaviors();
81 let behavior = BLOCK_BEHAVIORS.get_behavior(&vanilla_blocks::BARRIER);
82 let dry_barrier = vanilla_blocks::BARRIER
83 .default_state()
84 .set_value(WATERLOGGED, false);
85
86 assert!(behavior.is_liquid_container(dry_barrier));
87 assert!(!behavior.can_place_liquid(dry_barrier, &vanilla_fluids::WATER));
88 }
89
90 #[test]
91 fn waterlogged_barrier_update_shape_schedules_water_tick() {
92 init_vanilla_registry();
93
94 let behavior = BarrierBlock::new(&vanilla_blocks::BARRIER);
95 let state = vanilla_blocks::BARRIER
96 .default_state()
97 .set_value(WATERLOGGED, true);
98 let level = TestLevel::default();
99
100 let updated = behavior.update_shape(
101 state,
102 &level,
103 BlockPos::ZERO,
104 Direction::North,
105 Direction::North.relative(BlockPos::ZERO),
106 vanilla_blocks::AIR.default_state(),
107 );
108
109 assert_eq!(updated, state);
110 assert!(level.scheduled_water_tick());
111 }
112}