diff --git a/src/inventory/BaseInventory.php b/src/inventory/BaseInventory.php index 5e2ed288cc..c8e4f5db4d 100644 --- a/src/inventory/BaseInventory.php +++ b/src/inventory/BaseInventory.php @@ -30,11 +30,10 @@ use pocketmine\utils\ObjectSet; use function array_map; use function array_slice; use function count; -use function max; -use function min; use function spl_object_id; abstract class BaseInventory implements Inventory{ + use InventoryHelpersTrait; /** @var int */ protected $maxStackSize = Inventory::MAX_STACK; @@ -140,202 +139,6 @@ 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->slots as $i => $slot){ - if($slot === null or $slot->isNull()){ - return $i; - } - } - - return -1; - } - - public function isSlotEmpty(int $index) : bool{ - return $this->slots[$index] === null or $this->slots[$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->equals($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; - } - } - - $emptySlots = []; - - for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - $item = $this->getItem($i); - if($item->isNull()){ - $emptySlots[] = $i; - } - - foreach($itemSlots as $index => $slot){ - if($slot->equals($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){ - unset($itemSlots[$index]); - } - } - } - } - - if(count($itemSlots) === 0){ - break; - } - } - - if(count($itemSlots) > 0 and count($emptySlots) > 0){ - foreach($emptySlots as $slotIndex){ - //This loop only gets the first item, then goes to the next empty slot - foreach($itemSlots as $index => $slot){ - $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){ - unset($itemSlots[$index]); - } - break; - } - } - } - - return $itemSlots; - } - - 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 new file mode 100644 index 0000000000..828a817e85 --- /dev/null +++ b/src/inventory/InventoryHelpersTrait.php @@ -0,0 +1,244 @@ +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 === null or $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->equals($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; + } + } + + $emptySlots = []; + + for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ + $item = $this->getItem($i); + if($item->isNull()){ + $emptySlots[] = $i; + } + + foreach($itemSlots as $index => $slot){ + if($slot->equals($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){ + unset($itemSlots[$index]); + } + } + } + } + + if(count($itemSlots) === 0){ + break; + } + } + + if(count($itemSlots) > 0 and count($emptySlots) > 0){ + foreach($emptySlots as $slotIndex){ + //This loop only gets the first item, then goes to the next empty slot + foreach($itemSlots as $index => $slot){ + $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){ + unset($itemSlots[$index]); + } + break; + } + } + } + + return $itemSlots; + } + + 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); + } +}