diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 425c6a809..4d79d7d94 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -29,14 +29,14 @@ use pocketmine\player\Player; use pocketmine\utils\ObjectSet; use function array_slice; use function count; +use function max; +use function min; use function spl_object_id; /** * This class provides everything needed to implement an inventory, minus the underlying storage system. */ abstract class BaseInventory implements Inventory{ - use InventoryHelpersTrait; - /** @var int */ protected $maxStackSize = Inventory::MAX_STACK; /** @var Player[] */ @@ -100,6 +100,206 @@ abstract class BaseInventory implements Inventory{ $this->onSlotChange($index, $oldItem); } + 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(); + if($count <= 0){ + return true; + } + } + } + + return false; + } + + public function all(Item $item) : array{ + $slots = []; + $checkDamage = !$item->hasAnyDamageValue(); + $checkTags = $item->hasNamedTag(); + foreach($this->getContents() as $index => $i){ + if($item->equals($i, $checkDamage, $checkTags)){ + $slots[$index] = $i; + } + } + + return $slots; + } + + public function remove(Item $item) : void{ + $checkDamage = !$item->hasAnyDamageValue(); + $checkTags = $item->hasNamedTag(); + + foreach($this->getContents() as $index => $i){ + if($item->equals($i, $checkDamage, $checkTags)){ + $this->clear($index); + } + } + } + + public function first(Item $item, bool $exact = false) : int{ + $count = $exact ? $item->getCount() : max(1, $item->getCount()); + $checkDamage = $exact || !$item->hasAnyDamageValue(); + $checkTags = $exact || $item->hasNamedTag(); + + foreach($this->getContents() as $index => $i){ + if($item->equals($i, $checkDamage, $checkTags) and ($i->getCount() === $count or (!$exact and $i->getCount() > $count))){ + return $index; + } + } + + return -1; + } + + public function firstEmpty() : int{ + foreach($this->getContents(true) as $i => $slot){ + if($slot->isNull()){ + return $i; + } + } + + return -1; + } + + public function isSlotEmpty(int $index) : bool{ + return $this->getItem($index)->isNull(); + } + + public function canAddItem(Item $item) : bool{ + $count = $item->getCount(); + for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ + $slot = $this->getItem($i); + if($item->canStackWith($slot)){ + if(($diff = min($slot->getMaxStackSize(), $item->getMaxStackSize()) - $slot->getCount()) > 0){ + $count -= $diff; + } + }elseif($slot->isNull()){ + $count -= min($this->getMaxStackSize(), $item->getMaxStackSize()); + } + + if($count <= 0){ + return true; + } + } + + return false; + } + + public function addItem(Item ...$slots) : array{ + /** @var Item[] $itemSlots */ + /** @var Item[] $slots */ + $itemSlots = []; + foreach($slots as $slot){ + if(!$slot->isNull()){ + $itemSlots[] = clone $slot; + } + } + + /** @var Item[] $returnSlots */ + $returnSlots = []; + + foreach($itemSlots as $item){ + $leftover = $this->internalAddItem($item); + if(!$leftover->isNull()){ + $returnSlots[] = $leftover; + } + } + + return $returnSlots; + } + + private function internalAddItem(Item $slot) : Item{ + $emptySlots = []; + + for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ + $item = $this->getItem($i); + if($item->isNull()){ + $emptySlots[] = $i; + } + + if($slot->canStackWith($item) and $item->getCount() < $item->getMaxStackSize()){ + $amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize()); + if($amount > 0){ + $slot->setCount($slot->getCount() - $amount); + $item->setCount($item->getCount() + $amount); + $this->setItem($i, $item); + if($slot->getCount() <= 0){ + break; + } + } + } + } + + if(count($emptySlots) > 0){ + foreach($emptySlots as $slotIndex){ + $amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize()); + $slot->setCount($slot->getCount() - $amount); + $item = clone $slot; + $item->setCount($amount); + $this->setItem($slotIndex, $item); + if($slot->getCount() <= 0){ + break; + } + } + } + + return $slot; + } + + public function removeItem(Item ...$slots) : array{ + /** @var Item[] $itemSlots */ + /** @var Item[] $slots */ + $itemSlots = []; + foreach($slots as $slot){ + if(!$slot->isNull()){ + $itemSlots[] = clone $slot; + } + } + + for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ + $item = $this->getItem($i); + if($item->isNull()){ + continue; + } + + 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]); + } + } + } + + if(count($itemSlots) === 0){ + break; + } + } + + return $itemSlots; + } + + public function clear(int $index) : void{ + $this->setItem($index, ItemFactory::air()); + } + + public function clearAll() : void{ + $this->setContents([]); + } + + public function swap(int $slot1, int $slot2) : void{ + $i1 = $this->getItem($slot1); + $i2 = $this->getItem($slot2); + $this->setItem($slot1, $i2); + $this->setItem($slot2, $i1); + } + /** * @return Player[] */ diff --git a/src/inventory/InventoryHelpersTrait.php b/src/inventory/InventoryHelpersTrait.php deleted file mode 100644 index 1d6de457b..000000000 --- a/src/inventory/InventoryHelpersTrait.php +++ /dev/null @@ -1,248 +0,0 @@ -getCount()); - $checkDamage = !$item->hasAnyDamageValue(); - $checkTags = $item->hasNamedTag(); - foreach($this->getContents() as $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $count -= $i->getCount(); - if($count <= 0){ - return true; - } - } - } - - return false; - } - - public function all(Item $item) : array{ - $slots = []; - $checkDamage = !$item->hasAnyDamageValue(); - $checkTags = $item->hasNamedTag(); - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $slots[$index] = $i; - } - } - - return $slots; - } - - public function remove(Item $item) : void{ - $checkDamage = !$item->hasAnyDamageValue(); - $checkTags = $item->hasNamedTag(); - - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags)){ - $this->clear($index); - } - } - } - - public function first(Item $item, bool $exact = false) : int{ - $count = $exact ? $item->getCount() : max(1, $item->getCount()); - $checkDamage = $exact || !$item->hasAnyDamageValue(); - $checkTags = $exact || $item->hasNamedTag(); - - foreach($this->getContents() as $index => $i){ - if($item->equals($i, $checkDamage, $checkTags) and ($i->getCount() === $count or (!$exact and $i->getCount() > $count))){ - return $index; - } - } - - return -1; - } - - public function firstEmpty() : int{ - foreach($this->getContents(true) as $i => $slot){ - if($slot->isNull()){ - return $i; - } - } - - return -1; - } - - public function isSlotEmpty(int $index) : bool{ - return $this->getItem($index)->isNull(); - } - - public function canAddItem(Item $item) : bool{ - $count = $item->getCount(); - for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - $slot = $this->getItem($i); - if($item->canStackWith($slot)){ - if(($diff = min($slot->getMaxStackSize(), $item->getMaxStackSize()) - $slot->getCount()) > 0){ - $count -= $diff; - } - }elseif($slot->isNull()){ - $count -= min($this->getMaxStackSize(), $item->getMaxStackSize()); - } - - if($count <= 0){ - return true; - } - } - - return false; - } - - public function addItem(Item ...$slots) : array{ - /** @var Item[] $itemSlots */ - /** @var Item[] $slots */ - $itemSlots = []; - foreach($slots as $slot){ - if(!$slot->isNull()){ - $itemSlots[] = clone $slot; - } - } - - /** @var Item[] $returnSlots */ - $returnSlots = []; - - foreach($itemSlots as $item){ - $leftover = $this->internalAddItem($item); - if(!$leftover->isNull()){ - $returnSlots[] = $leftover; - } - } - - return $returnSlots; - } - - private function internalAddItem(Item $slot) : Item{ - $emptySlots = []; - - for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - $item = $this->getItem($i); - if($item->isNull()){ - $emptySlots[] = $i; - } - - if($slot->canStackWith($item) and $item->getCount() < $item->getMaxStackSize()){ - $amount = min($item->getMaxStackSize() - $item->getCount(), $slot->getCount(), $this->getMaxStackSize()); - if($amount > 0){ - $slot->setCount($slot->getCount() - $amount); - $item->setCount($item->getCount() + $amount); - $this->setItem($i, $item); - if($slot->getCount() <= 0){ - break; - } - } - } - } - - if(count($emptySlots) > 0){ - foreach($emptySlots as $slotIndex){ - $amount = min($slot->getMaxStackSize(), $slot->getCount(), $this->getMaxStackSize()); - $slot->setCount($slot->getCount() - $amount); - $item = clone $slot; - $item->setCount($amount); - $this->setItem($slotIndex, $item); - if($slot->getCount() <= 0){ - break; - } - } - } - - return $slot; - } - - public function removeItem(Item ...$slots) : array{ - /** @var Item[] $itemSlots */ - /** @var Item[] $slots */ - $itemSlots = []; - foreach($slots as $slot){ - if(!$slot->isNull()){ - $itemSlots[] = clone $slot; - } - } - - for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - $item = $this->getItem($i); - if($item->isNull()){ - continue; - } - - 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]); - } - } - } - - if(count($itemSlots) === 0){ - break; - } - } - - return $itemSlots; - } - - public function clear(int $index) : void{ - $this->setItem($index, ItemFactory::air()); - } - - public function clearAll() : void{ - $this->setContents([]); - } - - public function swap(int $slot1, int $slot2) : void{ - $i1 = $this->getItem($slot1); - $i2 = $this->getItem($slot2); - $this->setItem($slot1, $i2); - $this->setItem($slot2, $i1); - } -}