steel_core/inventory/slots/
furnace_slots.rs1use steel_registry::item_stack::ItemStack;
4use steel_registry::vanilla_items;
5use steel_utils::{DowncastType, DowncastTypeKey};
6
7use crate::block_entity::entities::{FurnaceContainer, pop_furnace_experience};
8use crate::entity::Entity as _;
9use crate::inventory::fuel_values::VANILLA_FUEL_VALUES;
10use crate::inventory::lock::{ContainerLockGuard, ContainerRef};
11use crate::inventory::slots::{NormalSlot, Slot, SlotStorage};
12use crate::player::Player;
13
14pub struct FurnaceFuelSlot {
16 base: NormalSlot,
17}
18
19unsafe impl DowncastType for FurnaceFuelSlot {
21 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:slot/furnace_fuel");
22}
23
24impl FurnaceFuelSlot {
25 #[must_use]
27 pub fn new(container: impl Into<ContainerRef>, index: usize) -> Self {
28 Self {
29 base: NormalSlot::new(container, index),
30 }
31 }
32}
33
34impl Slot for FurnaceFuelSlot {
35 fn storage(&self) -> &SlotStorage {
36 self.base.storage()
37 }
38
39 fn get_item<'a>(&self, guard: &'a ContainerLockGuard) -> &'a ItemStack {
40 self.base.get_item(guard)
41 }
42
43 fn get_item_mut<'a>(&self, guard: &'a mut ContainerLockGuard) -> &'a mut ItemStack {
44 self.base.get_item_mut(guard)
45 }
46
47 fn set_item(&self, guard: &mut ContainerLockGuard, stack: ItemStack) {
48 self.base.set_item(guard, stack);
49 }
50
51 fn may_place(&self, stack: &ItemStack) -> bool {
52 VANILLA_FUEL_VALUES.is_fuel(stack.item()) || stack.is(&vanilla_items::BUCKET)
53 }
54
55 fn get_max_stack_size(&self, guard: &ContainerLockGuard) -> i32 {
56 self.base.get_max_stack_size(guard)
57 }
58
59 fn get_max_stack_size_for_item(&self, guard: &ContainerLockGuard, stack: &ItemStack) -> i32 {
60 if stack.is(&vanilla_items::BUCKET) {
61 1
62 } else {
63 self.base.get_max_stack_size_for_item(guard, stack)
64 }
65 }
66
67 fn set_changed(&self, guard: &mut ContainerLockGuard) {
68 self.base.set_changed(guard);
69 }
70
71 fn get_container_slot(&self) -> usize {
72 self.base.get_container_slot()
73 }
74}
75
76pub struct FurnaceResultSlot {
78 base: NormalSlot,
79}
80
81unsafe impl DowncastType for FurnaceResultSlot {
83 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:slot/furnace_result");
84}
85
86impl FurnaceResultSlot {
87 #[must_use]
89 pub fn new(container: impl Into<ContainerRef>, index: usize) -> Self {
90 Self {
91 base: NormalSlot::new(container, index),
92 }
93 }
94}
95
96impl Slot for FurnaceResultSlot {
97 fn storage(&self) -> &SlotStorage {
98 self.base.storage()
99 }
100
101 fn get_item<'a>(&self, guard: &'a ContainerLockGuard) -> &'a ItemStack {
102 self.base.get_item(guard)
103 }
104
105 fn get_item_mut<'a>(&self, guard: &'a mut ContainerLockGuard) -> &'a mut ItemStack {
106 self.base.get_item_mut(guard)
107 }
108
109 fn set_item(&self, guard: &mut ContainerLockGuard, stack: ItemStack) {
110 self.base.set_item(guard, stack);
111 }
112
113 fn may_place(&self, _stack: &ItemStack) -> bool {
114 false
115 }
116
117 fn get_max_stack_size(&self, guard: &ContainerLockGuard) -> i32 {
118 self.base.get_max_stack_size(guard)
119 }
120
121 fn set_changed(&self, guard: &mut ContainerLockGuard) {
122 self.base.set_changed(guard);
123 }
124
125 fn get_container_slot(&self) -> usize {
126 self.base.get_container_slot()
127 }
128
129 fn on_take(
130 &self,
131 guard: &mut ContainerLockGuard,
132 _stack: &ItemStack,
133 player: &Player,
134 ) -> Option<ItemStack> {
135 let (container, _) = self.storage().physical_backing()?;
137 let container_id = container.container_id();
138 let recipes = guard
139 .get_typed_mut::<FurnaceContainer>(container_id)
140 .map(FurnaceContainer::take_recipes_used);
141 self.base.set_changed(guard);
142 if let Some(recipes) = recipes {
143 guard.run_unlocked(|| {
144 pop_furnace_experience(&player.get_world(), player.position(), recipes);
145 });
146 }
147 None
148 }
149}