steel_core/behavior/blocks/vegetation/
pumpkin_block.rs1use crate::behavior::block::drop_from_block_interact_loot_table;
2use crate::behavior::{
3 BlockBehavior, BlockPlaceContext, BlockRef, InteractionResult, InventoryAccess,
4};
5use crate::entity::Entity;
6use crate::player::Player;
7use crate::world::World;
8use crate::world::game_event::GameEventContext;
9use glam::DVec3;
10use rand::RngExt;
11use std::sync::Arc;
12use steel_macros::block_behavior;
13use steel_registry::blocks::block_state_ext::BlockStateExt;
14use steel_registry::blocks::properties::BlockStateProperties;
15use steel_registry::items::item::BlockHitResult;
16use steel_registry::{
17 sound_events, vanilla_blocks, vanilla_game_events, vanilla_items, vanilla_loot_tables,
18};
19use steel_utils::axis::Axis;
20use steel_utils::types::{InteractionHand, UpdateFlags};
21use steel_utils::{BlockPos, BlockStateId};
22
23#[block_behavior]
25pub struct PumpkinBlock {
26 block: BlockRef,
27}
28
29impl PumpkinBlock {
30 #[must_use]
32 pub const fn new(block: BlockRef) -> Self {
33 Self { block }
34 }
35}
36
37impl BlockBehavior for PumpkinBlock {
38 fn get_state_for_placement(&self, _context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
39 Some(self.block.default_state())
40 }
41
42 fn use_item_on(
43 &self,
44 state: BlockStateId,
45 world: &Arc<World>,
46 pos: BlockPos,
47 player: &Player,
48 _hand: InteractionHand,
49 hit_result: &BlockHitResult,
50 inv: &mut InventoryAccess,
51 ) -> InteractionResult {
52 let mut rng = rand::rng();
53
54 let Some(drops) = inv.with_item(|item_stack| {
55 if !item_stack.is(&vanilla_items::SHEARS) {
56 return None;
57 }
58
59 Some(drop_from_block_interact_loot_table(
60 &vanilla_loot_tables::CARVE_PUMPKIN,
61 state,
62 world.get_block_entity(pos),
63 Some(item_stack),
64 Some(player),
65 &mut rng,
66 ))
67 }) else {
68 return InteractionResult::TryEmptyHandInteraction;
69 };
70
71 let clicked_direction = hit_result.direction;
72 let direction = if clicked_direction.axis() == Axis::Y {
73 player.direction_yaw().opposite()
74 } else {
75 clicked_direction
76 };
77
78 let (x_offset, z_offset) = {
79 let (x, _, z) = direction.offset();
80 (f64::from(x), f64::from(z))
81 };
82
83 for drop in drops {
84 world.spawn_item_with_velocity(
85 DVec3::new(
86 f64::from(pos.x()) + 0.5 + x_offset * 0.65,
87 f64::from(pos.y()) + 0.1,
88 f64::from(pos.z()) + 0.5 + z_offset * 0.65,
89 ),
90 drop,
91 DVec3::new(
92 0.05 * x_offset + rng.random::<f64>() * 0.02,
93 0.05,
94 0.05 * z_offset + rng.random::<f64>() * 0.02,
95 ),
96 );
97 }
98
99 world.play_block_sound(&sound_events::BLOCK_PUMPKIN_CARVE, pos, 1.0, 1.0, None);
100 world.set_block(
101 pos,
102 vanilla_blocks::CARVED_PUMPKIN
103 .default_state()
104 .set_value(&BlockStateProperties::HORIZONTAL_FACING, direction),
106 UpdateFlags::UPDATE_IMMEDIATE
107 | UpdateFlags::UPDATE_CLIENTS
108 | UpdateFlags::UPDATE_NEIGHBORS,
109 );
110 let has_infinite_materials = player.has_infinite_materials();
111 inv.with_item(|item_stack| item_stack.hurt_and_break(1, has_infinite_materials));
112
113 world.game_event(
114 &vanilla_game_events::SHEAR,
115 pos,
116 &GameEventContext::new(Some(player), None),
117 );
118
119 InteractionResult::Success
122 }
123}