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