Inventory: reduce API duplication by using a Set for viewers

This commit is contained in:
Dylan K. Taylor 2020-05-14 14:13:28 +01:00
parent 3dafee6aa6
commit 4437756987
8 changed files with 25 additions and 47 deletions

View File

@ -54,7 +54,7 @@ class BrewingStand extends Spawnable implements Container, Nameable{
public function __construct(World $world, Vector3 $pos){ public function __construct(World $world, Vector3 $pos){
parent::__construct($world, $pos); parent::__construct($world, $pos);
$this->inventory = new BrewingStandInventory($this->pos); $this->inventory = new BrewingStandInventory($this->pos);
$this->inventory->addListeners(CallbackInventoryListener::onAnyChange(function(Inventory $unused) : void{ $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(function(Inventory $unused) : void{
$this->pos->getWorldNonNull()->scheduleDelayedBlockUpdate($this->pos, 1); $this->pos->getWorldNonNull()->scheduleDelayedBlockUpdate($this->pos, 1);
})); }));
} }

View File

@ -48,14 +48,14 @@ trait ContainerTrait{
$inventoryTag = $tag->getListTag(Container::TAG_ITEMS); $inventoryTag = $tag->getListTag(Container::TAG_ITEMS);
$inventory = $this->getRealInventory(); $inventory = $this->getRealInventory();
$listeners = $inventory->getListeners(); $listeners = $inventory->getListeners()->toArray();
$inventory->removeListeners(...$listeners); //prevent any events being fired by initialization $inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization
$inventory->clearAll(); $inventory->clearAll();
/** @var CompoundTag $itemNBT */ /** @var CompoundTag $itemNBT */
foreach($inventoryTag as $itemNBT){ foreach($inventoryTag as $itemNBT){
$inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT)); $inventory->setItem($itemNBT->getByte("Slot"), Item::nbtDeserialize($itemNBT));
} }
$inventory->addListeners(...$listeners); $inventory->getListeners()->add(...$listeners);
} }
if($tag->hasTag(Container::TAG_LOCK, StringTag::class)){ if($tag->hasTag(Container::TAG_LOCK, StringTag::class)){

View File

@ -58,7 +58,7 @@ class Furnace extends Spawnable implements Container, Nameable{
public function __construct(World $world, Vector3 $pos){ public function __construct(World $world, Vector3 $pos){
parent::__construct($world, $pos); parent::__construct($world, $pos);
$this->inventory = new FurnaceInventory($this->pos); $this->inventory = new FurnaceInventory($this->pos);
$this->inventory->addListeners(CallbackInventoryListener::onAnyChange( $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
function(Inventory $unused) : void{ function(Inventory $unused) : void{
$this->pos->getWorldNonNull()->scheduleDelayedBlockUpdate($this->pos, 1); $this->pos->getWorldNonNull()->scheduleDelayedBlockUpdate($this->pos, 1);
}) })

View File

@ -221,8 +221,8 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
$inventoryTag = $nbt->getListTag("Inventory"); $inventoryTag = $nbt->getListTag("Inventory");
if($inventoryTag !== null){ if($inventoryTag !== null){
$armorListeners = $this->armorInventory->getListeners(); $armorListeners = $this->armorInventory->getListeners()->toArray();
$this->armorInventory->removeListeners(...$armorListeners); $this->armorInventory->getListeners()->clear();
/** @var CompoundTag $item */ /** @var CompoundTag $item */
foreach($inventoryTag as $i => $item){ foreach($inventoryTag as $i => $item){
@ -236,7 +236,7 @@ class Human extends Living implements ProjectileSource, InventoryHolder{
} }
} }
$this->armorInventory->addListeners(...$armorListeners); $this->armorInventory->getListeners()->add(...$armorListeners);
} }
$enderChestInventoryTag = $nbt->getListTag("EnderChestInventory"); $enderChestInventoryTag = $nbt->getListTag("EnderChestInventory");

View File

@ -110,7 +110,7 @@ abstract class Living extends Entity{
$this->armorInventory = new ArmorInventory($this); $this->armorInventory = new ArmorInventory($this);
//TODO: load/save armor inventory contents //TODO: load/save armor inventory contents
$this->armorInventory->addListeners(CallbackInventoryListener::onAnyChange( $this->armorInventory->getListeners()->add(CallbackInventoryListener::onAnyChange(
function(Inventory $unused) : void{ function(Inventory $unused) : void{
foreach($this->getViewers() as $viewer){ foreach($this->getViewers() as $viewer){
$viewer->getNetworkSession()->onMobArmorChange($this); $viewer->getNetworkSession()->onMobArmorChange($this);

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\inventory; namespace pocketmine\inventory;
use Ds\Set;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\ItemFactory; use pocketmine\item\ItemFactory;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -43,11 +44,15 @@ abstract class BaseInventory implements Inventory{
protected $slots; protected $slots;
/** @var Player[] */ /** @var Player[] */
protected $viewers = []; protected $viewers = [];
/** @var InventoryListener[] */ /**
protected $listeners = []; * @var InventoryListener[]|Set
* @phpstan-var Set<InventoryListener>
*/
protected $listeners;
public function __construct(int $size){ public function __construct(int $size){
$this->slots = new \SplFixedArray($size); $this->slots = new \SplFixedArray($size);
$this->listeners = new Set();
} }
/** /**
@ -92,8 +97,8 @@ abstract class BaseInventory implements Inventory{
$oldContents = $this->slots->toArray(); $oldContents = $this->slots->toArray();
$listeners = $this->listeners; $listeners = $this->listeners->toArray();
$this->listeners = []; $this->listeners->clear();
$viewers = $this->viewers; $viewers = $this->viewers;
$this->viewers = []; $this->viewers = [];
@ -105,7 +110,7 @@ abstract class BaseInventory implements Inventory{
} }
} }
$this->addListeners(...$listeners); //don't directly write, in case listeners were added while operation was in progress $this->listeners->add(...$listeners); //don't directly write, in case listeners were added while operation was in progress
foreach($viewers as $id => $viewer){ foreach($viewers as $id => $viewer){
$this->viewers[$id] = $viewer; $this->viewers[$id] = $viewer;
} }
@ -372,23 +377,7 @@ abstract class BaseInventory implements Inventory{
return $slot >= 0 and $slot < $this->slots->getSize(); return $slot >= 0 and $slot < $this->slots->getSize();
} }
public function addListeners(InventoryListener ...$listeners) : void{ public function getListeners() : Set{
foreach($listeners as $listener){
$this->listeners[spl_object_id($listener)] = $listener;
}
}
public function removeListeners(InventoryListener ...$listeners) : void{
foreach($listeners as $listener){
unset($this->listeners[spl_object_id($listener)]);
}
}
public function removeAllListeners() : void{
$this->listeners = [];
}
public function getListeners() : array{
return $this->listeners; return $this->listeners;
} }
} }

View File

@ -26,6 +26,7 @@ declare(strict_types=1);
*/ */
namespace pocketmine\inventory; namespace pocketmine\inventory;
use Ds\Set;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\player\Player; use pocketmine\player\Player;
@ -155,19 +156,8 @@ interface Inventory{
public function slotExists(int $slot) : bool; public function slotExists(int $slot) : bool;
/** /**
* @param InventoryListener ...$listeners * @return InventoryListener[]|Set
* @phpstan-return Set<InventoryListener>
*/ */
public function addListeners(InventoryListener ...$listeners) : void; public function getListeners() : Set;
/**
* @param InventoryListener ...$listeners
*/
public function removeListeners(InventoryListener ...$listeners) : void;
public function removeAllListeners() : void;
/**
* @return InventoryListener[]
*/
public function getListeners() : array;
} }

View File

@ -29,8 +29,7 @@ use pocketmine\item\Item;
* Classes implementing this interface can be injected into inventories to receive notifications when content changes * Classes implementing this interface can be injected into inventories to receive notifications when content changes
* occur. * occur.
* @see CallbackInventoryListener for a closure-based listener * @see CallbackInventoryListener for a closure-based listener
* @see Inventory::addListeners() * @see Inventory::getListeners()
* @see Inventory::removeListeners()
*/ */
interface InventoryListener{ interface InventoryListener{