steel_core/behavior/blocks/decoration/
lantern_block.rs1use steel_macros::block_behavior;
2use steel_registry::{
3 blocks::{
4 BlockRef,
5 block_state_ext::BlockStateExt,
6 properties::{BlockStateProperties, BoolProperty},
7 shapes::SupportType,
8 },
9 vanilla_blocks,
10};
11use steel_utils::{BlockPos, BlockStateId, Direction, axis::Axis};
12
13use crate::{
14 behavior::{BlockBehavior, BlockPlaceContext, block::schedule_water_tick_if_waterlogged},
15 entity::ai::path::PathComputationType,
16 world::{LevelReader, ScheduledTickAccess},
17};
18
19#[block_behavior]
21pub struct LanternBlock {
22 block: BlockRef,
23}
24
25const HANGING: &BoolProperty = &BlockStateProperties::HANGING;
26const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
27
28impl LanternBlock {
29 #[must_use]
31 pub const fn new(block: BlockRef) -> Self {
32 Self { block }
33 }
34
35 fn get_connected_dir(state: BlockStateId) -> Direction {
36 if state.get_value(HANGING) {
37 return Direction::Down;
38 }
39 Direction::Up
40 }
41}
42
43impl BlockBehavior for LanternBlock {
44 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
45 for dir in context.get_nearest_looking_directions() {
46 if dir.axis() == Axis::Y {
47 let state = self
48 .block
49 .default_state()
50 .set_value(HANGING, dir == Direction::Up);
51 if self.can_survive(state, context.world, context.place_pos()) {
52 return Some(state.set_value(WATERLOGGED, context.is_water_source()));
53 }
54 }
55 }
56 None
57 }
58
59 fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
60 let dir = Self::get_connected_dir(state).opposite();
61 let relative_pos = pos.relative(dir);
62 world.is_face_sturdy_for(
63 world.get_block_state(relative_pos),
64 relative_pos,
65 dir.opposite(),
66 SupportType::Center,
67 )
68 }
69
70 fn update_shape(
71 &self,
72 state: BlockStateId,
73 world: &dyn ScheduledTickAccess,
74 pos: BlockPos,
75 direction: Direction,
76 _neighbor_pos: BlockPos,
77 _neighbor_state: BlockStateId,
78 ) -> BlockStateId {
79 schedule_water_tick_if_waterlogged(state, world, pos);
80
81 if Self::get_connected_dir(state).opposite() == direction
82 && !self.can_survive(state, world, pos)
83 {
84 return vanilla_blocks::AIR.default_state();
85 }
86 state
87 }
88
89 fn is_pathfindable(
90 &self,
91 _state: BlockStateId,
92 _computation_type: PathComputationType,
93 ) -> bool {
94 false
95 }
96}