steel_core/behavior/blocks/container/
barrel_block.rs1use std::sync::{Arc, Weak};
6
7use steel_macros::block_behavior;
8use steel_registry::blocks::BlockRef;
9use steel_registry::blocks::block_state_ext::BlockStateExt;
10use steel_registry::blocks::properties::{BlockStateProperties, Direction};
11use steel_registry::vanilla_block_entity_types;
12use steel_utils::{BlockPos, BlockStateId, translations};
13use text_components::TextComponent;
14
15use crate::behavior::InventoryAccess;
16use crate::behavior::block::{BlockBehavior, BlockEntityCreation};
17use crate::behavior::context::{BlockHitResult, BlockPlaceContext, InteractionResult};
18use crate::block_entity::BLOCK_ENTITIES;
19use crate::inventory::container::calculate_redstone_signal_from_container;
20use crate::inventory::lock::{ContainerLockGuard, ContainerRef};
21use crate::inventory::menu::kinds::chest;
22use crate::player::Player;
23use crate::world::{LevelReader, World};
24
25#[block_behavior]
30pub struct BarrelBlock {
31 block: BlockRef,
32}
33
34impl BarrelBlock {
35 #[must_use]
37 pub const fn new(block: BlockRef) -> Self {
38 Self { block }
39 }
40}
41
42impl BlockBehavior for BarrelBlock {
43 fn get_state_for_placement(&self, context: &BlockPlaceContext<'_>) -> Option<BlockStateId> {
44 let facing = context.get_nearest_looking_direction().opposite();
46
47 Some(
48 self.block
49 .default_state()
50 .set_value(&BlockStateProperties::FACING, facing),
51 )
52 }
53
54 fn use_without_item(
55 &self,
56 _state: BlockStateId,
57 world: &Arc<World>,
58 pos: BlockPos,
59 player: &Player,
60 _hit_result: &BlockHitResult,
61 _inv: &mut InventoryAccess,
62 ) -> InteractionResult {
63 let Some(block_entity) = world.get_block_entity(pos) else {
65 return InteractionResult::Pass;
66 };
67
68 let Some(container_ref) = ContainerRef::from_block_entity(block_entity) else {
70 return InteractionResult::Pass;
71 };
72
73 let inventory = player.inventory.clone();
75 player.open_menu(
76 TextComponent::translated(translations::CONTAINER_BARREL.msg()),
77 move |context| chest(inventory, context.container_id, container_ref, 3),
78 );
79
80 InteractionResult::Success
87 }
88
89 fn new_block_entity(
90 &self,
91 level: Weak<World>,
92 pos: BlockPos,
93 state: BlockStateId,
94 ) -> BlockEntityCreation {
95 BlockEntityCreation::from_registered_factory(BLOCK_ENTITIES.create(
96 &vanilla_block_entity_types::BARREL,
97 level,
98 pos,
99 state,
100 ))
101 }
102
103 fn has_analog_output_signal(&self, _state: BlockStateId) -> bool {
104 true
105 }
106
107 fn get_analog_output_signal(
108 &self,
109 _state: BlockStateId,
110 world: &dyn LevelReader,
111 pos: BlockPos,
112 _direction: Direction,
113 ) -> i32 {
114 let Some(container_ref) = world
116 .get_block_entity(pos)
117 .and_then(ContainerRef::from_block_entity)
118 else {
119 return 0;
120 };
121 let guard = ContainerLockGuard::lock_all(&[&container_ref]);
122 guard
123 .get(container_ref.container_id())
124 .map_or(0, |container| {
125 calculate_redstone_signal_from_container(container)
126 })
127 }
128}