steel_core/inventory/menu/kinds/
crafting_menu.rs1use crate::inventory::container::CraftingContainer;
10use crate::inventory::container::ResultContainer;
11use crate::inventory::prelude::*;
12use crate::inventory::slots::CraftingHandler;
13use crate::player::player_inventory::PlayerInventory;
14use steel_registry::blocks::block_state_ext::BlockStateExt;
15use steel_registry::item_stack::ItemStack;
16use steel_registry::vanilla_blocks;
17use steel_registry::vanilla_menu_types;
18use steel_utils::BlockPos;
19use steel_utils::locks::IntoShared;
20use steel_utils::locks::Shared;
21
22#[must_use]
24pub fn crafting(inventory: Shared<PlayerInventory>, container_id: u8, block_pos: BlockPos) -> Menu {
25 let crafting_container = CraftingContainer::new(3, 3).into_shared();
26 let result_container = ResultContainer::new().into_shared();
27
28 let handler = CraftingHandler::new(crafting_container.clone(), result_container.clone(), 3);
29
30 let mut builder = MenuBuilder::new(&vanilla_menu_types::CRAFTING, container_id);
31 let result = builder.result_slot(handler.clone());
32 let grid = builder.section_all(crafting_container);
33 let player = builder.player_inventory(&inventory);
34
35 builder.route(result, player.all(), FillDirection::Backward);
36 builder.route(grid, player.all(), FillDirection::Forward);
37 builder.route(
38 player.main(),
39 [grid, player.hotbar()],
40 FillDirection::Forward,
41 );
42 builder.route(
43 player.hotbar(),
44 [grid, player.main()],
45 FillDirection::Forward,
46 );
47 builder.drain(grid);
48
49 builder.build(CraftingKind {
50 result_container,
51 result,
52 block_pos,
53 handler,
54 })
55}
56
57pub struct CraftingKind {
59 result_container: Shared<ResultContainer>,
61 result: Section,
63 block_pos: BlockPos,
65 handler: CraftingHandler,
66}
67
68unsafe impl steel_utils::DowncastType for CraftingKind {
71 const TYPE_KEY: steel_utils::DowncastTypeKey =
72 steel_utils::DowncastTypeKey::new("steel:menu/crafting");
73}
74
75impl MenuKind for CraftingKind {
76 fn can_take_item_for_pick_all(&self, _carried: &ItemStack, slot_index: usize) -> bool {
78 !self.result.contains(slot_index)
79 }
80
81 fn still_valid(&self, _behavior: &MenuBehavior, player: &Player) -> bool {
84 let world = player.get_world();
85 world.get_block_state(self.block_pos).get_block() == &vanilla_blocks::CRAFTING_TABLE
86 && player.is_within_block_interaction_range_with_buffer(self.block_pos, 4.0)
87 }
88
89 fn removed(&mut self, _behavior: &mut MenuBehavior, _player: &Player) {
91 self.result_container.lock().set_item(0, ItemStack::empty());
92 }
93
94 fn slots_changed(
95 &mut self,
96 _behavior: &mut MenuBehavior,
97 guard: &mut ContainerLockGuard,
98 _player: &Player,
99 ) {
100 self.handler.update_result(guard);
101 }
102}
103
104#[cfg(test)]
105mod tests;