diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 240d51b04..74d099df0 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -618,8 +618,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $inventoryTag = $nbt->getListTag("Inventory"); if($inventoryTag !== null){ - $armorListener = $this->armorInventory->getSlotChangeListener(); - $this->armorInventory->setSlotChangeListener(null); + $armorListeners = $this->armorInventory->getChangeListeners(); + $this->armorInventory->removeChangeListeners(...$armorListeners); /** @var CompoundTag $item */ foreach($inventoryTag as $i => $item){ @@ -633,7 +633,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } } - $this->armorInventory->setSlotChangeListener($armorListener); + $this->armorInventory->addChangeListeners(...$armorListeners); } $enderChestInventoryTag = $nbt->getListTag("EnderChestInventory"); diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index bb1b52ad0..9be938cbf 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -27,7 +27,6 @@ use pocketmine\event\inventory\InventoryOpenEvent; use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\Player; -use pocketmine\utils\Utils; use function array_slice; use function count; use function max; @@ -42,8 +41,8 @@ abstract class BaseInventory implements Inventory{ protected $slots = []; /** @var Player[] */ protected $viewers = []; - /** @var \Closure */ - protected $slotChangeListener; + /** @var InventoryChangeListener[] */ + protected $listeners = []; /** * @param int $size @@ -121,6 +120,10 @@ abstract class BaseInventory implements Inventory{ } } + foreach($this->listeners as $listener){ + $listener->onContentChange($this); + } + if($send){ $this->sendContents($this->getViewers()); } @@ -138,10 +141,6 @@ abstract class BaseInventory implements Inventory{ $this->slots[$index] = $item->isNull() ? null : $item; $this->onSlotChange($index, $oldItem, $send); - if($this->slotChangeListener !== null){ - ($this->slotChangeListener)($this, $index); - } - return true; } @@ -331,13 +330,7 @@ abstract class BaseInventory implements Inventory{ } public function clearAll(bool $send = true) : void{ - for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ - $this->clear($i, false); - } - - if($send){ - $this->sendContents($this->getViewers()); - } + $this->setContents([], $send); } public function swap(int $slot1, int $slot2) : void{ @@ -394,6 +387,9 @@ abstract class BaseInventory implements Inventory{ } protected function onSlotChange(int $index, Item $before, bool $send) : void{ + foreach($this->listeners as $listener){ + $listener->onSlotChange($this, $index); + } if($send){ $this->sendSlot($index, $this->getViewers()); } @@ -430,14 +426,19 @@ abstract class BaseInventory implements Inventory{ return $slot >= 0 and $slot < $this->slots->getSize(); } - public function getSlotChangeListener() : ?\Closure{ - return $this->slotChangeListener; + public function addChangeListeners(InventoryChangeListener ...$listeners) : void{ + foreach($listeners as $listener){ + $this->listeners[spl_object_id($listener)] = $listener; + } } - public function setSlotChangeListener(?\Closure $eventProcessor) : void{ - if($eventProcessor !== null){ - Utils::validateCallableSignature(function(Inventory $inventory, int $slot) : void{}, $eventProcessor); + public function removeChangeListeners(InventoryChangeListener ...$listeners) : void{ + foreach($listeners as $listener){ + unset($this->listeners[spl_object_id($listener)]); } - $this->slotChangeListener = $eventProcessor; + } + + public function getChangeListeners() : array{ + return $this->listeners; } } diff --git a/src/pocketmine/inventory/CallbackInventoryChangeListener.php b/src/pocketmine/inventory/CallbackInventoryChangeListener.php new file mode 100644 index 000000000..b27499740 --- /dev/null +++ b/src/pocketmine/inventory/CallbackInventoryChangeListener.php @@ -0,0 +1,65 @@ +onSlotChangeCallback = $onSlotChange; + $this->onContentChangeCallback = $onContentChange; + } + + public static function onAnyChange(\Closure $onChange) : self{ + return new self( + static function(Inventory $inventory, int $unused) use($onChange) : void{ + $onChange($inventory); + }, + static function(Inventory $inventory) use($onChange) : void{ + $onChange($inventory); + } + ); + } + + public function onSlotChange(Inventory $inventory, int $slot) : void{ + ($this->onSlotChangeCallback)($inventory, $slot); + } + + public function onContentChange(Inventory $inventory) : void{ + ($this->onContentChangeCallback)($inventory); + } +} diff --git a/src/pocketmine/inventory/Inventory.php b/src/pocketmine/inventory/Inventory.php index c0fba1d2b..a27a8525c 100644 --- a/src/pocketmine/inventory/Inventory.php +++ b/src/pocketmine/inventory/Inventory.php @@ -231,12 +231,17 @@ interface Inventory{ public function slotExists(int $slot) : bool; /** - * @return null|\Closure + * @param InventoryChangeListener ...$listeners */ - public function getSlotChangeListener() : ?\Closure; + public function addChangeListeners(InventoryChangeListener ...$listeners) : void; /** - * @param \Closure|null $eventProcessor + * @param InventoryChangeListener ...$listeners */ - public function setSlotChangeListener(?\Closure $eventProcessor) : void; + public function removeChangeListeners(InventoryChangeListener ...$listeners) : void; + + /** + * @return InventoryChangeListener[] + */ + public function getChangeListeners() : array; } diff --git a/src/pocketmine/inventory/InventoryChangeListener.php b/src/pocketmine/inventory/InventoryChangeListener.php new file mode 100644 index 000000000..d13edf7f0 --- /dev/null +++ b/src/pocketmine/inventory/InventoryChangeListener.php @@ -0,0 +1,38 @@ +getListTag(Container::TAG_ITEMS); $inventory = $this->getRealInventory(); - $slotChangeListener = $inventory->getSlotChangeListener(); - $inventory->setSlotChangeListener(null); //prevent any events being fired by initialization + $listeners = $inventory->getChangeListeners(); + $inventory->removeChangeListeners(...$listeners); //prevent any events being fired by initialization $inventory->clearAll(); /** @var CompoundTag $itemNBT */ foreach($inventoryTag as $itemNBT){ $inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT)); } - $inventory->setSlotChangeListener($slotChangeListener); + $inventory->addChangeListeners(...$listeners); } if($tag->hasTag(Container::TAG_LOCK, StringTag::class)){ diff --git a/src/pocketmine/tile/Furnace.php b/src/pocketmine/tile/Furnace.php index 26ce225ab..ad9337139 100644 --- a/src/pocketmine/tile/Furnace.php +++ b/src/pocketmine/tile/Furnace.php @@ -26,6 +26,7 @@ namespace pocketmine\tile; use pocketmine\block\Furnace as BlockFurnace; use pocketmine\event\inventory\FurnaceBurnEvent; use pocketmine\event\inventory\FurnaceSmeltEvent; +use pocketmine\inventory\CallbackInventoryChangeListener; use pocketmine\inventory\FurnaceInventory; use pocketmine\inventory\FurnaceRecipe; use pocketmine\inventory\Inventory; @@ -60,9 +61,11 @@ class Furnace extends Spawnable implements InventoryHolder, Container, Nameable{ public function __construct(World $world, Vector3 $pos){ $this->inventory = new FurnaceInventory($this); - $this->inventory->setSlotChangeListener(function(Inventory $inventory, int $slot) : void{ - $this->scheduleUpdate(); - }); + $this->inventory->addChangeListeners(CallbackInventoryChangeListener::onAnyChange( + function(Inventory $unused) : void{ + $this->scheduleUpdate(); + }) + ); parent::__construct($world, $pos); }