the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "net.minecraft.world.entity.player.h"
3#include "net.minecraft.world.item.h"
4#include "net.minecraft.world.level.redstone.h"
5#include "Slot.h"
6#include "AbstractContainerMenu.h"
7
8// 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables
9// TODO Make sure all derived classes also call this
10AbstractContainerMenu::AbstractContainerMenu()
11{
12 containerId = 0;
13
14 changeUid = 0;
15
16 quickcraftType = -1;
17 quickcraftStatus = 0;
18
19 m_bNeedsRendered = false;
20}
21
22AbstractContainerMenu::~AbstractContainerMenu()
23{
24 for( unsigned int i = 0; i < slots.size(); i++ )
25 {
26 delete slots.at(i);
27 }
28}
29
30Slot *AbstractContainerMenu::addSlot(Slot *slot)
31{
32 slot->index = (int)slots.size();
33 slots.push_back(slot);
34 lastSlots.push_back(nullptr);
35 return slot;
36}
37
38
39void AbstractContainerMenu::addSlotListener(ContainerListener *listener)
40{
41 containerListeners.push_back(listener);
42
43 vector<shared_ptr<ItemInstance> > *items = getItems();
44 listener->refreshContainer(this, items);
45 delete items;
46 broadcastChanges();
47}
48
49void AbstractContainerMenu::removeSlotListener(ContainerListener *listener)
50{
51 AUTO_VAR(it, std::find(containerListeners.begin(), containerListeners.end(), listener) );
52 if(it != containerListeners.end()) containerListeners.erase(it);
53}
54
55vector<shared_ptr<ItemInstance> > *AbstractContainerMenu::getItems()
56{
57 vector<shared_ptr<ItemInstance> > *items = new vector<shared_ptr<ItemInstance> >();
58 AUTO_VAR(itEnd, slots.end());
59 for (AUTO_VAR(it, slots.begin()); it != itEnd; it++)
60 {
61 items->push_back((*it)->getItem());
62 }
63 return items;
64}
65
66void AbstractContainerMenu::sendData(int id, int value)
67{
68 AUTO_VAR(itEnd, containerListeners.end());
69 for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++)
70 {
71 (*it)->setContainerData(this, id, value);
72 }
73}
74
75void AbstractContainerMenu::broadcastChanges()
76{
77 for (unsigned int i = 0; i < slots.size(); i++)
78 {
79 shared_ptr<ItemInstance> current = slots.at(i)->getItem();
80 shared_ptr<ItemInstance> expected = lastSlots.at(i);
81 if (!ItemInstance::matches(expected, current))
82 {
83 // 4J Stu - Added 0 count check. There is a bug in the Java with anvils that means this broadcast
84 // happens while we are in the middle of quickmoving, and before the slot properly gets set to null
85 expected = (current == NULL || current->count == 0) ? nullptr : current->copy();
86 lastSlots[i] = expected;
87 m_bNeedsRendered = true;
88
89 AUTO_VAR(itEnd, containerListeners.end());
90 for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++)
91 {
92 (*it)->slotChanged(this, i, expected);
93 }
94 }
95 }
96}
97
98bool AbstractContainerMenu::needsRendered()
99{
100 bool needsRendered = m_bNeedsRendered;
101 m_bNeedsRendered = false;
102
103 for (unsigned int i = 0; i < slots.size(); i++)
104 {
105 shared_ptr<ItemInstance> current = slots.at(i)->getItem();
106 shared_ptr<ItemInstance> expected = lastSlots.at(i);
107 if (!ItemInstance::matches(expected, current))
108 {
109 expected = current == NULL ? nullptr : current->copy();
110 lastSlots[i] = expected;
111 needsRendered = true;
112 }
113 }
114
115 return needsRendered;
116}
117
118bool AbstractContainerMenu::clickMenuButton(shared_ptr<Player> player, int buttonId)
119{
120 return false;
121}
122
123Slot *AbstractContainerMenu::getSlotFor(shared_ptr<Container> c, int index)
124{
125 AUTO_VAR(itEnd, slots.end());
126 for (AUTO_VAR(it, slots.begin()); it != itEnd; it++)
127 {
128 Slot *slot = *it; //slots->at(i);
129 if (slot->isAt(c, index))
130 {
131 return slot;
132 }
133 }
134 return NULL;
135}
136
137Slot *AbstractContainerMenu::getSlot(int index)
138{
139 return slots.at(index);
140}
141
142shared_ptr<ItemInstance> AbstractContainerMenu::quickMoveStack(shared_ptr<Player> player, int slotIndex)
143{
144 Slot *slot = slots.at(slotIndex);
145 if (slot != NULL)
146 {
147 return slot->getItem();
148 }
149 return nullptr;
150}
151
152shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr<Player> player, bool looped) // 4J Added looped param
153{
154 shared_ptr<ItemInstance> clickedEntity = nullptr;
155 shared_ptr<Inventory> inventory = player->inventory;
156
157 if (clickType == CLICK_QUICK_CRAFT)
158 {
159 int expectedStatus = quickcraftStatus;
160 quickcraftStatus = getQuickcraftHeader(buttonNum);
161
162 if ((expectedStatus != QUICKCRAFT_HEADER_CONTINUE || quickcraftStatus != QUICKCRAFT_HEADER_END) && expectedStatus != quickcraftStatus)
163 {
164 resetQuickCraft();
165 }
166 else if (inventory->getCarried() == NULL)
167 {
168 resetQuickCraft();
169 }
170 else if (quickcraftStatus == QUICKCRAFT_HEADER_START)
171 {
172 quickcraftType = getQuickcraftType(buttonNum);
173
174 if (isValidQuickcraftType(quickcraftType))
175 {
176 quickcraftStatus = QUICKCRAFT_HEADER_CONTINUE;
177 quickcraftSlots.clear();
178 }
179 else
180 {
181 resetQuickCraft();
182 }
183 }
184 else if (quickcraftStatus == QUICKCRAFT_HEADER_CONTINUE)
185 {
186 Slot *slot = slots.at(slotIndex);
187
188 if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count > quickcraftSlots.size() && canDragTo(slot))
189 {
190 quickcraftSlots.insert(slot);
191 }
192 }
193 else if (quickcraftStatus == QUICKCRAFT_HEADER_END)
194 {
195 if (!quickcraftSlots.empty())
196 {
197 shared_ptr<ItemInstance> source = inventory->getCarried()->copy();
198 int remaining = inventory->getCarried()->count;
199
200 for(AUTO_VAR(it, quickcraftSlots.begin()); it != quickcraftSlots.end(); ++it)
201 {
202 Slot *slot = *it;
203 if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count >= quickcraftSlots.size() && canDragTo(slot))
204 {
205 shared_ptr<ItemInstance> copy = source->copy();
206 int carry = slot->hasItem() ? slot->getItem()->count : 0;
207 getQuickCraftSlotCount(&quickcraftSlots, quickcraftType, copy, carry);
208
209 if (copy->count > copy->getMaxStackSize()) copy->count = copy->getMaxStackSize();
210 if (copy->count > slot->getMaxStackSize()) copy->count = slot->getMaxStackSize();
211
212 remaining -= copy->count - carry;
213 slot->set(copy);
214 }
215 }
216
217 source->count = remaining;
218 if (source->count <= 0)
219 {
220 source = nullptr;
221 }
222 inventory->setCarried(source);
223 }
224
225 resetQuickCraft();
226 }
227 else
228 {
229 resetQuickCraft();
230 }
231 }
232 else if (quickcraftStatus != QUICKCRAFT_HEADER_START)
233 {
234 resetQuickCraft();
235 }
236 else if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1))
237 {
238 if (slotIndex == SLOT_CLICKED_OUTSIDE)
239 {
240 if (inventory->getCarried() != NULL)
241 {
242 if (slotIndex == SLOT_CLICKED_OUTSIDE)
243 {
244 if (buttonNum == 0)
245 {
246 player->drop(inventory->getCarried());
247 inventory->setCarried(nullptr);
248 }
249 if (buttonNum == 1)
250 {
251 player->drop(inventory->getCarried()->remove(1));
252 if (inventory->getCarried()->count == 0) inventory->setCarried(nullptr);
253 }
254
255 }
256 }
257 }
258 else if (clickType == CLICK_QUICK_MOVE)
259 {
260 if (slotIndex < 0) return nullptr;
261 Slot *slot = slots.at(slotIndex);
262 if(slot != NULL && slot->mayPickup(player))
263 {
264 shared_ptr<ItemInstance> piiClicked = quickMoveStack(player, slotIndex);
265 if (piiClicked != NULL)
266 {
267 int oldType = piiClicked->id;
268
269 // 4J Stu - We ignore the return value for loopClicks, so don't make a copy
270 if(!looped)
271 {
272 clickedEntity = piiClicked->copy();
273 }
274
275 // 4J Stu - Remove the reference to this before we start a recursive loop
276 piiClicked = nullptr;
277
278 if (slot != NULL)
279 {
280 if (slot->getItem() != NULL && slot->getItem()->id == oldType)
281 {
282 if(looped)
283 {
284 // Return a non-null value to indicate that we want to loop more
285 clickedEntity = shared_ptr<ItemInstance>(new ItemInstance(0,1,0));
286 }
287 else
288 {
289 // 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative
290 loopClick(slotIndex, buttonNum, true, player);
291 }
292 }
293 }
294 }
295 }
296 }
297 else
298 {
299 if (slotIndex < 0) return nullptr;
300
301 Slot *slot = slots.at(slotIndex);
302 if (slot != NULL)
303 {
304 shared_ptr<ItemInstance> clicked = slot->getItem();
305 shared_ptr<ItemInstance> carried = inventory->getCarried();
306
307 if (clicked != NULL)
308 {
309 clickedEntity = clicked->copy();
310 }
311
312 if (clicked == NULL)
313 {
314 if (carried != NULL && slot->mayPlace(carried))
315 {
316 int c = buttonNum == 0 ? carried->count : 1;
317 if (c > slot->getMaxStackSize())
318 {
319 c = slot->getMaxStackSize();
320 }
321 if (carried->count >= c)
322 {
323 slot->set(carried->remove(c));
324 }
325 if (carried->count == 0)
326 {
327 inventory->setCarried(nullptr);
328 }
329 }
330 }
331 // 4J Added for dyable armour and combinining damaged items
332 else if (buttonNum == 1 && mayCombine(slot, carried))
333 {
334 shared_ptr<ItemInstance> combined = slot->combine(carried);
335 if(combined != NULL)
336 {
337 slot->set(combined);
338 if(!player->abilities.instabuild) carried->remove(1);
339 if (carried->count == 0)
340 {
341 inventory->setCarried(nullptr);
342 }
343 }
344 }
345 else if (slot->mayPickup(player))
346 {
347 if (carried == NULL)
348 {
349 // pick up to empty hand
350 int c = buttonNum == 0 ? clicked->count : (clicked->count + 1) / 2;
351 shared_ptr<ItemInstance> removed = slot->remove(c);
352
353 inventory->setCarried(removed);
354 if (clicked->count == 0)
355 {
356 slot->set(nullptr);
357 }
358 slot->onTake(player, inventory->getCarried());
359 }
360 else if (slot->mayPlace(carried))
361 {
362 // put down and/or pick up
363 if (clicked->id != carried->id || clicked->getAuxValue() != carried->getAuxValue() || !ItemInstance::tagMatches(clicked, carried))
364 {
365 // no match, replace
366 if (carried->count <= slot->getMaxStackSize())
367 {
368 slot->set(carried);
369 inventory->setCarried(clicked);
370 }
371 }
372 else
373 {
374 // match, attempt to fill slot
375 int c = buttonNum == 0 ? carried->count : 1;
376 if (c > slot->getMaxStackSize() - clicked->count)
377 {
378 c = slot->getMaxStackSize() - clicked->count;
379 }
380 if (c > carried->getMaxStackSize() - clicked->count)
381 {
382 c = carried->getMaxStackSize() - clicked->count;
383 }
384 carried->remove(c);
385 if (carried->count == 0)
386 {
387 inventory->setCarried(nullptr);
388 }
389 clicked->count += c;
390 }
391 }
392 else
393 {
394 // pick up to non-empty hand
395 if (clicked->id == carried->id && carried->getMaxStackSize() > 1 && (!clicked->isStackedByData() || clicked->getAuxValue() == carried->getAuxValue())
396 && ItemInstance::tagMatches(clicked, carried))
397 {
398 int c = clicked->count;
399 if (c > 0 && c + carried->count <= carried->getMaxStackSize())
400 {
401 carried->count += c;
402 clicked = slot->remove(c);
403 if (clicked->count == 0) slot->set(nullptr);
404 slot->onTake(player, inventory->getCarried());
405 }
406 }
407 }
408
409
410 }
411 slot->setChanged();
412 }
413 }
414 }
415 else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9)
416 {
417 Slot *slot = slots.at(slotIndex);
418 if (slot->mayPickup(player))
419 {
420 shared_ptr<ItemInstance> current = inventory->getItem(buttonNum);
421 bool canMove = current == NULL || (slot->container == inventory && slot->mayPlace(current));
422 int freeSlot = -1;
423
424 if (!canMove)
425 {
426 freeSlot = inventory->getFreeSlot();
427 canMove |= freeSlot > -1;
428 }
429
430 if (slot->hasItem() && canMove)
431 {
432 shared_ptr<ItemInstance> taking = slot->getItem();
433 inventory->setItem(buttonNum, taking);
434
435 if ((slot->container == inventory && slot->mayPlace(current)) || current == NULL)
436 {
437 slot->remove(taking->count);
438 slot->set(current);
439 slot->onTake(player, taking);
440 }
441 else if (freeSlot > -1)
442 {
443 inventory->add(current);
444 slot->remove(taking->count);
445 slot->set(nullptr);
446 slot->onTake(player, taking);
447 }
448 }
449 else if (!slot->hasItem() && current != NULL && slot->mayPlace(current))
450 {
451 inventory->setItem(buttonNum, nullptr);
452 slot->set(current);
453 }
454 }
455 }
456 else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0)
457 {
458 Slot *slot = slots.at(slotIndex);
459 if (slot != NULL && slot->hasItem())
460 {
461 shared_ptr<ItemInstance> copy = slot->getItem()->copy();
462 copy->count = copy->getMaxStackSize();
463 inventory->setCarried(copy);
464 }
465 }
466 else if (clickType == CLICK_THROW && inventory->getCarried() == NULL && slotIndex >= 0)
467 {
468 Slot *slot = slots.at(slotIndex);
469 if (slot != NULL && slot->hasItem() && slot->mayPickup(player))
470 {
471 shared_ptr<ItemInstance> item = slot->remove(buttonNum == 0 ? 1 : slot->getItem()->count);
472 slot->onTake(player, item);
473 player->drop(item);
474 }
475 }
476 else if (clickType == CLICK_PICKUP_ALL && slotIndex >= 0)
477 {
478 Slot *slot = slots.at(slotIndex);
479 shared_ptr<ItemInstance> carried = inventory->getCarried();
480
481 if (carried != NULL && (slot == NULL || !slot->hasItem() || !slot->mayPickup(player)))
482 {
483 int start = buttonNum == 0 ? 0 : slots.size() - 1;
484 int step = buttonNum == 0 ? 1 : -1;
485
486 for (int pass = 0; pass < 2; pass++ )
487 {
488 // In the first pass, we only get partial stacks.
489 for (int i = start; i >= 0 && i < slots.size() && carried->count < carried->getMaxStackSize(); i += step)
490 {
491 Slot *target = slots.at(i);
492
493 if (target->hasItem() && canItemQuickReplace(target, carried, true) && target->mayPickup(player) && canTakeItemForPickAll(carried, target))
494 {
495 if (pass == 0 && target->getItem()->count == target->getItem()->getMaxStackSize()) continue;
496 int count = min(carried->getMaxStackSize() - carried->count, target->getItem()->count);
497 shared_ptr<ItemInstance> removed = target->remove(count);
498 carried->count += count;
499
500 if (removed->count <= 0)
501 {
502 target->set(nullptr);
503 }
504 target->onTake(player, removed);
505 }
506 }
507 }
508 }
509
510 broadcastChanges();
511 }
512 return clickedEntity;
513}
514
515bool AbstractContainerMenu::canTakeItemForPickAll(shared_ptr<ItemInstance> carried, Slot *target)
516{
517 return true;
518}
519
520// 4J Stu - Brought forward from 1.2 to fix infinite recursion bug in creative
521void AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr<Player> player)
522{
523 while( clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player, true) != NULL)
524 {
525 }
526}
527
528bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr<ItemInstance> item)
529{
530 return false;
531}
532
533void AbstractContainerMenu::removed(shared_ptr<Player> player)
534{
535 shared_ptr<Inventory> inventory = player->inventory;
536 if (inventory->getCarried() != NULL)
537 {
538 player->drop(inventory->getCarried());
539 inventory->setCarried(nullptr);
540 }
541}
542
543void AbstractContainerMenu::slotsChanged()// 4J used to take a shared_ptr<Container> but wasn't using it, so removed to simplify things
544{
545 broadcastChanges();
546}
547
548bool AbstractContainerMenu::isPauseScreen()
549{
550 return false;
551}
552
553void AbstractContainerMenu::setItem(unsigned int slot, shared_ptr<ItemInstance> item)
554{
555 getSlot(slot)->set(item);
556}
557
558void AbstractContainerMenu::setAll(ItemInstanceArray *items)
559{
560 for (unsigned int i = 0; i < items->length; i++)
561 {
562 getSlot(i)->set( (*items)[i] );
563 }
564}
565
566void AbstractContainerMenu::setData(int id, int value)
567{
568}
569
570short AbstractContainerMenu::backup(shared_ptr<Inventory> inventory)
571{
572 changeUid++;
573 return changeUid;
574}
575
576bool AbstractContainerMenu::isSynched(shared_ptr<Player> player)
577{
578 return !(unSynchedPlayers.find(player) != unSynchedPlayers.end());
579}
580
581void AbstractContainerMenu::setSynched(shared_ptr<Player> player, bool synched)
582{
583 if (synched)
584 {
585 AUTO_VAR(it, unSynchedPlayers.find(player));
586
587 if(it != unSynchedPlayers.end()) unSynchedPlayers.erase( it );
588 }
589 else
590 {
591 unSynchedPlayers.insert(player);
592 }
593}
594
595// 4J Stu - Brought a few changes in this function forward from 1.2 to make it return a bool
596bool AbstractContainerMenu::moveItemStackTo(shared_ptr<ItemInstance> itemStack, int startSlot, int endSlot, bool backwards)
597{
598 bool anythingChanged = false;
599
600 int destSlot = startSlot;
601 if (backwards)
602 {
603 destSlot = endSlot - 1;
604 }
605
606 // find stackable slots first
607 if (itemStack->isStackable())
608 {
609 while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)))
610 {
611
612 Slot *slot = slots.at(destSlot);
613 shared_ptr<ItemInstance> target = slot->getItem();
614 if (target != NULL && target->id == itemStack->id && (!itemStack->isStackedByData() || itemStack->getAuxValue() == target->getAuxValue())
615 && ItemInstance::tagMatches(itemStack, target) )
616 {
617 int totalStack = target->count + itemStack->count;
618 if (totalStack <= itemStack->getMaxStackSize())
619 {
620 itemStack->count = 0;
621 target->count = totalStack;
622 slot->setChanged();
623 anythingChanged = true;
624 }
625 else if (target->count < itemStack->getMaxStackSize())
626 {
627 itemStack->count -= (itemStack->getMaxStackSize() - target->count);
628 target->count = itemStack->getMaxStackSize();
629 slot->setChanged();
630 anythingChanged = true;
631 }
632 }
633
634 if (backwards)
635 {
636 destSlot--;
637 }
638 else
639 {
640 destSlot++;
641 }
642 }
643 }
644
645 // find empty slot
646 if (itemStack->count > 0)
647 {
648 if (backwards)
649 {
650 destSlot = endSlot - 1;
651 }
652 else
653 {
654 destSlot = startSlot;
655 }
656 while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))
657 {
658 Slot *slot = slots.at(destSlot);
659 shared_ptr<ItemInstance> target = slot->getItem();
660
661 if (target == NULL)
662 {
663 slot->set(itemStack->copy());
664 slot->setChanged();
665 itemStack->count = 0;
666 anythingChanged = true;
667 break;
668 }
669
670 if (backwards)
671 {
672 destSlot--;
673 }
674 else
675 {
676 destSlot++;
677 }
678 }
679 }
680 return anythingChanged;
681}
682
683bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum)
684{
685 return false;
686}
687
688int AbstractContainerMenu::getQuickcraftType(int mask)
689{
690 return (mask >> 2) & 0x3;
691}
692
693int AbstractContainerMenu::getQuickcraftHeader(int mask)
694{
695 return mask & 0x3;
696}
697
698int AbstractContainerMenu::getQuickcraftMask(int header, int type)
699{
700 return (header & 0x3) | ((type & 0x3) << 2);
701}
702
703bool AbstractContainerMenu::isValidQuickcraftType(int type)
704{
705 return type == QUICKCRAFT_TYPE_CHARITABLE || type == QUICKCRAFT_TYPE_GREEDY;
706}
707
708void AbstractContainerMenu::resetQuickCraft()
709{
710 quickcraftStatus = QUICKCRAFT_HEADER_START;
711 quickcraftSlots.clear();
712}
713
714bool AbstractContainerMenu::canItemQuickReplace(Slot *slot, shared_ptr<ItemInstance> item, bool ignoreSize)
715{
716 bool canReplace = slot == NULL || !slot->hasItem();
717
718 if (slot != NULL && slot->hasItem() && item != NULL && item->sameItem(slot->getItem()) && ItemInstance::tagMatches(slot->getItem(), item))
719 {
720 canReplace |= slot->getItem()->count + (ignoreSize ? 0 : item->count) <= item->getMaxStackSize();
721 }
722
723 return canReplace;
724}
725
726void AbstractContainerMenu::getQuickCraftSlotCount(unordered_set<Slot *> *quickCraftSlots, int quickCraftingType, shared_ptr<ItemInstance> item, int carry)
727{
728 switch (quickCraftingType)
729 {
730 case QUICKCRAFT_TYPE_CHARITABLE:
731 item->count = Mth::floor(item->count / (float) quickCraftSlots->size());
732 break;
733 case QUICKCRAFT_TYPE_GREEDY:
734 item->count = 1;
735 break;
736 }
737
738 item->count += carry;
739}
740
741bool AbstractContainerMenu::canDragTo(Slot *slot)
742{
743 return true;
744}
745
746int AbstractContainerMenu::getRedstoneSignalFromContainer(shared_ptr<Container> container)
747{
748 if (container == NULL) return 0;
749 int count = 0;
750 float totalPct = 0;
751
752 for (int i = 0; i < container->getContainerSize(); i++)
753 {
754 shared_ptr<ItemInstance> item = container->getItem(i);
755
756 if (item != NULL)
757 {
758 totalPct += item->count / (float) min(container->getMaxStackSize(), item->getMaxStackSize());
759 count++;
760 }
761 }
762
763 totalPct /= container->getContainerSize();
764 return Mth::floor(totalPct * (Redstone::SIGNAL_MAX - 1)) + (count > 0 ? 1 : 0);
765}
766
767// 4J Added
768bool AbstractContainerMenu::isValidIngredient(shared_ptr<ItemInstance> item, int slotId)
769{
770 return true;
771}