diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 6154bcb900..433fcbf879 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -108,13 +108,23 @@ abstract class BaseInventory implements Inventory{ $this->onContentChange($oldContents); } + /** + * Helper for utility functions which search the inventory. + * TODO: make this abstract instead of providing a slow default implementation (BC break) + */ + protected function getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int{ + $item = $this->getItem($slot); + return $item->equals($test, $checkDamage, $checkTags) ? $item->getCount() : 0; + } + public function contains(Item $item) : bool{ $count = max(1, $item->getCount()); $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasNamedTag(); - foreach($this->getContents() as $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $count -= $i->getCount(); + for($i = 0, $size = $this->getSize(); $i < $size; $i++){ + $slotCount = $this->getMatchingItemCount($i, $item, $checkDamage, $checkTags); + if($slotCount > 0){ + $count -= $slotCount; if($count <= 0){ return true; } @@ -128,9 +138,9 @@ abstract class BaseInventory implements Inventory{ $slots = []; $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasNamedTag(); - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $slots[$index] = $i; + for($i = 0, $size = $this->getSize(); $i < $size; $i++){ + if($this->getMatchingItemCount($i, $item, $checkDamage, $checkTags) > 0){ + $slots[$i] = $this->getItem($i); } } @@ -142,9 +152,10 @@ abstract class BaseInventory implements Inventory{ $checkDamage = $exact || !$item->hasAnyDamageValue(); $checkTags = $exact || $item->hasNamedTag(); - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags) && ($i->getCount() === $count || (!$exact && $i->getCount() > $count))){ - return $index; + for($i = 0, $size = $this->getSize(); $i < $size; $i++){ + $slotCount = $this->getMatchingItemCount($i, $item, $checkDamage, $checkTags); + if($slotCount > 0 && ($slotCount === $count || (!$exact && $slotCount > $count))){ + return $i; } } @@ -177,11 +188,9 @@ abstract class BaseInventory implements Inventory{ if($this->isSlotEmpty($i)){ $count -= $maxStackSize; }else{ - $slot = $this->getItem($i); - if($item->canStackWith($slot)){ - if(($diff = $maxStackSize - $slot->getCount()) > 0){ - $count -= $diff; - } + $slotCount = $this->getMatchingItemCount($i, $item, true, true); + if($slotCount > 0 && ($diff = $maxStackSize - $slotCount) > 0){ + $count -= $diff; } } @@ -226,12 +235,16 @@ abstract class BaseInventory implements Inventory{ $emptySlots[] = $i; continue; } - $slotItem = $this->getItem($i); + $slotCount = $this->getMatchingItemCount($i, $newItem, true, true); + if($slotCount === 0){ + continue; + } - if($newItem->canStackWith($slotItem) && $slotItem->getCount() < $maxStackSize){ - $amount = min($maxStackSize - $slotItem->getCount(), $newItem->getCount()); + if($slotCount < $maxStackSize){ + $amount = min($maxStackSize - $slotCount, $newItem->getCount()); if($amount > 0){ $newItem->setCount($newItem->getCount() - $amount); + $slotItem = $this->getItem($i); $slotItem->setCount($slotItem->getCount() + $amount); $this->setItem($i, $slotItem); if($newItem->getCount() <= 0){ @@ -261,20 +274,20 @@ abstract class BaseInventory implements Inventory{ $checkDamage = !$item->hasAnyDamageValue(); $checkTags = $item->hasNamedTag(); - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $this->clear($index); + for($i = 0, $size = $this->getSize(); $i < $size; $i++){ + if($this->getMatchingItemCount($i, $item, $checkDamage, $checkTags) > 0){ + $this->clear($i); } } } public function removeItem(Item ...$slots) : array{ - /** @var Item[] $itemSlots */ + /** @var Item[] $searchItems */ /** @var Item[] $slots */ - $itemSlots = []; + $searchItems = []; foreach($slots as $slot){ if(!$slot->isNull()){ - $itemSlots[] = clone $slot; + $searchItems[] = clone $slot; } } @@ -282,26 +295,28 @@ abstract class BaseInventory implements Inventory{ if($this->isSlotEmpty($i)){ continue; } - $item = $this->getItem($i); - foreach($itemSlots as $index => $slot){ - if($slot->equals($item, !$slot->hasAnyDamageValue(), $slot->hasNamedTag())){ - $amount = min($item->getCount(), $slot->getCount()); - $slot->setCount($slot->getCount() - $amount); - $item->setCount($item->getCount() - $amount); - $this->setItem($i, $item); - if($slot->getCount() <= 0){ - unset($itemSlots[$index]); + foreach($searchItems as $index => $search){ + $slotCount = $this->getMatchingItemCount($i, $search, !$search->hasAnyDamageValue(), $search->hasNamedTag()); + if($slotCount > 0){ + $amount = min($slotCount, $search->getCount()); + $search->setCount($search->getCount() - $amount); + + $slotItem = $this->getItem($i); + $slotItem->setCount($slotItem->getCount() - $amount); + $this->setItem($i, $slotItem); + if($search->getCount() <= 0){ + unset($searchItems[$index]); } } } - if(count($itemSlots) === 0){ + if(count($searchItems) === 0){ break; } } - return $itemSlots; + return $searchItems; } public function clear(int $index) : void{ diff --git a/src/inventory/SimpleInventory.php b/src/inventory/SimpleInventory.php index 19fbdbb17c..c1f352b7b7 100644 --- a/src/inventory/SimpleInventory.php +++ b/src/inventory/SimpleInventory.php @@ -84,6 +84,11 @@ class SimpleInventory extends BaseInventory{ } } + protected function getMatchingItemCount(int $slot, Item $test, bool $checkDamage, bool $checkTags) : int{ + $slotItem = $this->slots[$slot]; + return $slotItem !== null && $slotItem->equals($test, $checkDamage, $checkTags) ? $slotItem->getCount() : 0; + } + public function isSlotEmpty(int $index) : bool{ return $this->slots[$index] === null || $this->slots[$index]->isNull(); }