steel_core/player/player_inventory/
container.rs1use std::sync::LazyLock;
2
3use steel_registry::item_stack::ItemStack;
4use steel_utils::types::InteractionHand;
5
6use crate::inventory::{
7 container::Container,
8 equipment::{EntityEquipment, EquipmentSlot},
9};
10
11use super::core::PlayerInventory;
12
13const fn slot_to_equipment(slot: usize) -> Option<EquipmentSlot> {
15 match slot {
16 36 => Some(EquipmentSlot::Feet),
17 37 => Some(EquipmentSlot::Legs),
18 38 => Some(EquipmentSlot::Chest),
19 39 => Some(EquipmentSlot::Head),
20 40 => Some(EquipmentSlot::OffHand),
21 41 => Some(EquipmentSlot::Body),
22 42 => Some(EquipmentSlot::Saddle),
23 _ => None,
24 }
25}
26
27pub(crate) const fn armor_equipment(index: usize) -> EquipmentSlot {
34 slot_to_equipment(index).expect("armor sections only cover armor indices")
35}
36
37impl PlayerInventory {
38 pub fn apply_filled_result(
45 &mut self,
46 hand: InteractionHand,
47 mut result_stack: ItemStack,
48 has_infinite_materials: bool,
49 limit_creative_stack_size: bool,
50 ) -> ItemStack {
51 if limit_creative_stack_size && has_infinite_materials {
52 if !self.contains_stack(&result_stack) {
53 let _ = self.add(&mut result_stack);
54 }
55 return ItemStack::empty();
56 }
57
58 if !has_infinite_materials {
59 self.shrink_item_in_hand(hand, 1);
60 }
61
62 if self.get_item_in_hand(hand).is_empty() {
63 self.set_item_in_hand(hand, result_stack);
64 return ItemStack::empty();
65 }
66
67 let added = self.add(&mut result_stack);
68 if added {
69 ItemStack::empty()
70 } else {
71 result_stack
72 }
73 }
74
75 pub fn add_or_return(&mut self, mut stack: ItemStack) -> ItemStack {
78 if self.add(&mut stack) {
79 ItemStack::empty()
80 } else {
81 stack
82 }
83 }
84}
85
86static EMPTY_ITEM: LazyLock<ItemStack> = LazyLock::new(ItemStack::empty);
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq)]
91pub struct InvalidHotbarSlot;
92
93impl Container for PlayerInventory {
94 fn items(&self) -> &[ItemStack] {
95 &self.items
96 }
97
98 fn items_mut(&mut self) -> &mut [ItemStack] {
99 &mut self.items
100 }
101
102 fn get_container_size(&self) -> usize {
103 Self::CONTAINER_SIZE
104 }
105
106 fn add(&mut self, stack: &mut ItemStack) -> bool {
112 if stack.is_empty() {
113 return true;
114 }
115
116 let max_size = self.get_max_stack_size_for_item(stack);
117 let mut changed = false;
118
119 if stack.is_stackable() {
122 let selected = self.selected as usize;
123 for slot in [selected, Self::SLOT_OFFHAND] {
124 if stack.is_empty() {
125 if changed {
126 self.set_changed();
127 }
128 return true;
129 }
130 let existing = &mut self.items[slot];
131 if !existing.is_empty() && ItemStack::is_same_item_same_components(existing, stack)
132 {
133 let space = max_size - existing.count();
134 if space > 0 {
135 let to_add = stack.count().min(space);
136 existing.grow(to_add);
137 stack.shrink(to_add);
138 changed = true;
139 }
140 }
141 }
142
143 for slot in 0..Self::INVENTORY_SIZE {
144 if stack.is_empty() {
145 if changed {
146 self.set_changed();
147 }
148 return true;
149 }
150 if slot == selected {
151 continue;
152 }
153 let existing = &mut self.items[slot];
154 if !existing.is_empty() && ItemStack::is_same_item_same_components(existing, stack)
155 {
156 let space = max_size - existing.count();
157 if space > 0 {
158 let to_add = stack.count().min(space);
159 existing.grow(to_add);
160 stack.shrink(to_add);
161 changed = true;
162 }
163 }
164 }
165 }
166
167 for slot in 0..Self::INVENTORY_SIZE {
169 if stack.is_empty() {
170 if changed {
171 self.set_changed();
172 }
173 return true;
174 }
175 if self.items[slot].is_empty() {
176 let to_place = stack.count().min(max_size);
177 self.items[slot] = stack.split(to_place);
178 changed = true;
179 }
180 }
181
182 if changed {
183 self.set_changed();
184 }
185 stack.is_empty()
186 }
187
188 fn get_item(&self, slot: usize) -> &ItemStack {
189 if slot < Self::CONTAINER_SIZE {
190 &self.items[slot]
191 } else {
192 &EMPTY_ITEM
193 }
194 }
195
196 fn get_item_mut(&mut self, slot: usize) -> &mut ItemStack {
197 assert!(slot < Self::CONTAINER_SIZE, "Invalid slot index: {slot}");
198 &mut self.items[slot]
199 }
200
201 fn set_item(&mut self, slot: usize, stack: ItemStack) {
202 if slot == self.selected as usize {
203 let _ = EntityEquipment::set(self, EquipmentSlot::MainHand, stack);
204 return;
205 }
206 if let Some(equipment_slot) = slot_to_equipment(slot) {
207 let _ = EntityEquipment::set(self, equipment_slot, stack);
208 return;
209 }
210 if slot < Self::INVENTORY_SIZE {
211 self.items[slot] = stack;
212 }
213 self.set_changed();
214 }
215
216 fn is_empty(&self) -> bool {
217 self.items.iter().all(ItemStack::is_empty)
218 }
219
220 fn set_changed(&mut self) {
221 self.times_changed = self.times_changed.wrapping_add(1);
222 }
223
224 fn clear_content(&mut self) -> i32 {
225 let mut count = 0;
226 for item in &mut self.items {
227 count += item.count();
228 *item = ItemStack::empty();
229 }
230 if count > 0 {
231 self.set_changed();
232 }
233 count
234 }
235
236 fn clear_content_matching(&mut self, predicate: &mut dyn FnMut(&mut ItemStack) -> bool) -> i32 {
237 let mut count = 0;
238 for item in &mut self.items {
239 if predicate(item) {
240 count += item.count();
241 *item = ItemStack::empty();
242 }
243 }
244 if count > 0 {
245 self.set_changed();
246 }
247 count
248 }
249}