steel_core/behavior/blocks/decoration/
cake_block.rs1use std::sync::Arc;
2
3use steel_macros::block_behavior;
4use steel_registry::{
5 blocks::{BlockRef, block_state_ext::BlockStateExt, properties::BlockStateProperties},
6 items::item::BlockHitResult,
7 sound_events, vanilla_blocks,
8 vanilla_item_tags::ItemTag,
9};
10use steel_utils::{
11 BlockPos, BlockStateId, Direction,
12 types::{InteractionHand, UpdateFlags},
13};
14
15use crate::{
16 behavior::{
17 BlockBehavior, BlockPlaceContext, InteractionResult, InventoryAccess, candle_cakes,
18 },
19 entity::Entity,
20 player::Player,
21 world::{LevelReader, ScheduledTickAccess, World},
22};
23
24#[block_behavior]
30pub struct CakeBlock {
31 block: BlockRef,
32}
33
34impl CakeBlock {
35 #[must_use]
37 pub const fn new(block: BlockRef) -> Self {
38 Self { block }
39 }
40
41 pub fn eat(
43 world: &Arc<World>,
44 pos: BlockPos,
45 state: BlockStateId,
46 player: &Player,
47 ) -> InteractionResult {
48 if player.can_eat(false) {
49 let mut food_data = player.food_data.lock();
50 food_data.eat(2, 0.1);
51 let bites = state.get_value(&BlockStateProperties::BITES);
52 let new_state = if bites < 6 {
53 state.set_value(&BlockStateProperties::BITES, bites + 1)
54 } else {
55 vanilla_blocks::AIR.default_state()
56 };
57 world.set_block(pos, new_state, UpdateFlags::UPDATE_ALL);
58 return InteractionResult::Success;
59 }
60 InteractionResult::Pass
61 }
62
63 #[must_use]
65 pub const fn analog_output_signal(bites: i32) -> i32 {
66 (7 - bites) * 2
67 }
68}
69
70impl BlockBehavior for CakeBlock {
71 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
72 if context
73 .world
74 .get_block_state(context.place_pos().below())
75 .is_solid()
76 {
77 Some(self.block.default_state())
78 } else {
79 None
80 }
81 }
82
83 fn can_survive(&self, _state: BlockStateId, world: &dyn LevelReader, pos: BlockPos) -> bool {
84 world.get_block_state(pos.below()).is_solid()
85 }
86
87 fn update_shape(
88 &self,
89 state: BlockStateId,
90 world: &dyn ScheduledTickAccess,
91 pos: BlockPos,
92 direction: Direction,
93 _neighbor_pos: BlockPos,
94 _neighbor_state: BlockStateId,
95 ) -> BlockStateId {
96 if direction == Direction::Down && !self.can_survive(state, world, pos) {
97 vanilla_blocks::AIR.default_state()
98 } else {
99 state
100 }
101 }
102
103 fn use_without_item(
104 &self,
105 state: BlockStateId,
106 world: &Arc<World>,
107 pos: BlockPos,
108 player: &Player,
109 _hit_result: &BlockHitResult,
110 _inv: &mut InventoryAccess,
111 ) -> InteractionResult {
112 if Self::eat(world, pos, state, player).consumes_action() {
113 return InteractionResult::Success;
114 }
115
116 InteractionResult::Pass
117 }
118
119 fn use_item_on(
120 &self,
121 state: BlockStateId,
122 world: &Arc<World>,
123 pos: BlockPos,
124 player: &Player,
125 _hand: InteractionHand,
126 _hit_result: &BlockHitResult,
127 inv: &mut InventoryAccess,
128 ) -> InteractionResult {
129 if state.get_value(&BlockStateProperties::BITES) == 0 {
130 let candle_cake = inv.with_item(|item_stack| {
131 let item = item_stack.item();
132 if !item.has_tag(&ItemTag::CANDLES) {
133 return None;
134 }
135 let candle_cake = candle_cakes::candle_to_candle_cake(item)?;
136 if !player.has_infinite_materials() {
137 item_stack.shrink(1);
138 }
139 Some(candle_cake)
140 });
141 let Some(candle_cake) = candle_cake else {
142 return InteractionResult::TryEmptyHandInteraction;
143 };
144 world.play_block_sound(
145 &sound_events::BLOCK_CAKE_ADD_CANDLE,
146 pos,
147 1.0,
148 1.0,
149 Some(player.id()),
150 );
151 world.set_block(pos, candle_cake.default_state(), UpdateFlags::UPDATE_ALL);
152 return InteractionResult::Success;
153 }
154 InteractionResult::TryEmptyHandInteraction
155 }
156
157 fn get_analog_output_signal(
158 &self,
159 state: BlockStateId,
160 _world: &dyn LevelReader,
161 _pos: BlockPos,
162 _direction: Direction,
163 ) -> i32 {
164 Self::analog_output_signal(i32::from(state.get_value(&BlockStateProperties::BITES)))
165 }
166
167 fn has_analog_output_signal(&self, _state: BlockStateId) -> bool {
168 true
169 }
170}