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};
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
31impl TorchBlock {
32 #[must_use]
34 pub const fn new(block: BlockRef) -> Self {
35 Self { block }
36 }
37}
38
39impl BlockBehavior for TorchBlock {
40 fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
43 let below_pos = pos.below();
44 let below_state = world.get_block_state(below_pos);
45 world.is_face_sturdy_for(below_state, below_pos, Direction::Up, SupportType::Center)
46 }
47
48 fn update_shape(
49 &self,
50 state: BlockStateId,
51 world: &dyn ScheduledTickAccess,
52 pos: BlockPos,
53 direction: Direction,
54 _neighbor_pos: BlockPos,
55 _neighbor_state: BlockStateId,
56 ) -> BlockStateId {
57 if direction == Direction::Down && !self.can_survive(state, world, pos) {
59 return REGISTRY.blocks.get_default_state_id(&vanilla_blocks::AIR);
60 }
61 state
62 }
63
64 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
65 let default_state = self.block.default_state();
66 if !self.can_survive(default_state, context.world, context.place_pos()) {
68 return None;
69 }
70
71 Some(default_state)
72 }
73}
74
75#[block_behavior]
80pub struct WallTorchBlock {
81 block: BlockRef,
82}
83
84impl WallTorchBlock {
85 #[must_use]
87 pub const fn new(block: BlockRef) -> Self {
88 Self { block }
89 }
90}
91
92impl BlockBehavior for WallTorchBlock {
93 fn can_survive(&self, state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
96 let facing: Direction = state.get_value(&BlockStateProperties::HORIZONTAL_FACING);
97 let attach_direction = facing.opposite();
98 let attach_pos = attach_direction.relative(pos);
99 let attach_state = world.get_block_state(attach_pos);
100 world.is_face_sturdy(attach_state, attach_pos, facing)
101 }
102
103 fn update_shape(
104 &self,
105 state: BlockStateId,
106 world: &dyn ScheduledTickAccess,
107 pos: BlockPos,
108 direction: Direction,
109 _neighbor_pos: BlockPos,
110 _neighbor_state: BlockStateId,
111 ) -> BlockStateId {
112 let facing: Direction = state.get_value(&BlockStateProperties::HORIZONTAL_FACING);
114 let attach_direction = facing.opposite();
115
116 if direction == attach_direction && !self.can_survive(state, world, pos) {
117 return REGISTRY.blocks.get_default_state_id(&vanilla_blocks::AIR);
118 }
119 state
120 }
121
122 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
123 for direction in context.get_nearest_looking_directions() {
126 if direction.is_horizontal() {
127 let facing = direction.opposite();
128 let state = self
129 .block
130 .default_state()
131 .set_value(&BlockStateProperties::HORIZONTAL_FACING, facing);
132 if self.can_survive(state, context.world, context.place_pos()) {
133 return Some(state);
134 }
135 }
136 }
137
138 None
139 }
140}