steel_core/behavior/blocks/decoration/
torch_block.rs1use steel_macros::block_behavior;
10use steel_registry::REGISTRY;
11use steel_registry::blocks::BlockRef;
12use steel_registry::blocks::block_state_ext::BlockStateExt;
13use steel_registry::blocks::properties::{BlockStateProperties, Direction, EnumProperty};
14use steel_registry::blocks::shapes::SupportType;
15use steel_registry::vanilla_blocks;
16use steel_utils::{BlockPos, BlockStateId};
17
18use crate::behavior::block::BlockBehavior;
19use crate::behavior::context::BlockPlaceContext;
20use crate::world::{LevelReader, ScheduledTickAccess};
21
22#[block_behavior]
27pub struct TorchBlock {
28 block: BlockRef,
29}
30
31const HORIZONTAL_FACING: &EnumProperty<Direction> = &BlockStateProperties::HORIZONTAL_FACING;
32
33impl TorchBlock {
34 #[must_use]
36 pub const fn new(block: BlockRef) -> Self {
37 Self { block }
38 }
39}
40
41impl BlockBehavior for TorchBlock {
42 fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
45 let below_pos = pos.below();
46 let below_state = world.get_block_state(below_pos);
47 world.is_face_sturdy_for(below_state, below_pos, Direction::Up, SupportType::Center)
48 }
49
50 fn update_shape(
51 &self,
52 state: BlockStateId,
53 world: &dyn ScheduledTickAccess,
54 pos: BlockPos,
55 direction: Direction,
56 _neighbor_pos: BlockPos,
57 _neighbor_state: BlockStateId,
58 ) -> BlockStateId {
59 if direction == Direction::Down && !self.can_survive(state, world, pos) {
61 return REGISTRY.blocks.get_default_state_id(&vanilla_blocks::AIR);
62 }
63 state
64 }
65
66 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
67 let default_state = self.block.default_state();
68 if !self.can_survive(default_state, context.world, context.place_pos()) {
70 return None;
71 }
72
73 Some(default_state)
74 }
75}
76
77#[block_behavior]
82pub struct WallTorchBlock {
83 block: BlockRef,
84}
85
86impl WallTorchBlock {
87 #[must_use]
89 pub const fn new(block: BlockRef) -> Self {
90 Self { block }
91 }
92}
93
94impl BlockBehavior for WallTorchBlock {
95 fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
98 let facing: Direction = state.get_value(HORIZONTAL_FACING);
99 let attach_direction = facing.opposite();
100 let attach_pos = attach_direction.relative(pos);
101 let attach_state = world.get_block_state(attach_pos);
102 world.is_face_sturdy(attach_state, attach_pos, facing)
103 }
104
105 fn update_shape(
106 &self,
107 state: BlockStateId,
108 world: &dyn ScheduledTickAccess,
109 pos: BlockPos,
110 direction: Direction,
111 _neighbor_pos: BlockPos,
112 _neighbor_state: BlockStateId,
113 ) -> BlockStateId {
114 let facing: Direction = state.get_value(HORIZONTAL_FACING);
116 let attach_direction = facing.opposite();
117
118 if direction == attach_direction && !self.can_survive(state, world, pos) {
119 return REGISTRY.blocks.get_default_state_id(&vanilla_blocks::AIR);
120 }
121 state
122 }
123
124 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
125 for direction in context.get_nearest_looking_directions() {
128 if direction.is_horizontal() {
129 let facing = direction.opposite();
130 let state = self
131 .block
132 .default_state()
133 .set_value(HORIZONTAL_FACING, facing);
134 if self.can_survive(state, context.world, context.place_pos()) {
135 return Some(state);
136 }
137 }
138 }
139
140 None
141 }
142}