diff --git a/src/block/Campfire.php b/src/block/Campfire.php index af167b52f..dcb0e3fa8 100644 --- a/src/block/Campfire.php +++ b/src/block/Campfire.php @@ -276,6 +276,9 @@ class Campfire extends Transparent{ $this->position->getWorld()->addSound($this->position, $furnaceType->getCookSound()); } $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, self::UPDATE_INTERVAL_TICKS); + }else{ + //make sure the visual state is updated when items are added + $this->position->getWorld()->setBlock($this->position, $this); } } diff --git a/src/block/tile/Barrel.php b/src/block/tile/Barrel.php index d70f5a405..bf3913b7b 100644 --- a/src/block/tile/Barrel.php +++ b/src/block/tile/Barrel.php @@ -50,13 +50,6 @@ class Barrel extends Spawnable implements ContainerTile, Nameable{ $this->saveItems($nbt); } - public function close() : void{ - if(!$this->closed){ - $this->inventory->removeAllViewers(); - parent::close(); - } - } - public function getInventory() : Inventory{ return $this->inventory; } diff --git a/src/block/tile/BrewingStand.php b/src/block/tile/BrewingStand.php index 30b94bc5f..8c70b4d03 100644 --- a/src/block/tile/BrewingStand.php +++ b/src/block/tile/BrewingStand.php @@ -27,7 +27,6 @@ use pocketmine\block\inventory\window\BrewingStandInventoryWindow; use pocketmine\crafting\BrewingRecipe; use pocketmine\event\block\BrewingFuelUseEvent; use pocketmine\event\block\BrewItemEvent; -use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; use pocketmine\inventory\SimpleInventory; use pocketmine\item\Item; @@ -64,9 +63,6 @@ class BrewingStand extends Spawnable implements ContainerTile, Nameable{ public function __construct(World $world, Vector3 $pos){ parent::__construct($world, $pos); $this->inventory = new SimpleInventory(5); - $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange(static function(Inventory $unused) use ($world, $pos) : void{ - $world->scheduleDelayedBlockUpdate($pos, 1); - })); } public function readSaveData(CompoundTag $nbt) : void{ @@ -105,14 +101,6 @@ class BrewingStand extends Spawnable implements ContainerTile, Nameable{ return "Brewing Stand"; } - public function close() : void{ - if(!$this->closed){ - $this->inventory->removeAllViewers(); - - parent::close(); - } - } - public function getInventory() : Inventory{ return $this->inventory; } diff --git a/src/block/tile/Campfire.php b/src/block/tile/Campfire.php index 44c7a9e6e..c237c5c78 100644 --- a/src/block/tile/Campfire.php +++ b/src/block/tile/Campfire.php @@ -23,10 +23,7 @@ declare(strict_types=1); namespace pocketmine\block\tile; -use pocketmine\block\Campfire as BlockCampfire; use pocketmine\block\inventory\CampfireInventory; -use pocketmine\inventory\CallbackInventoryListener; -use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; @@ -54,14 +51,6 @@ class Campfire extends Spawnable implements ContainerTile{ public function __construct(World $world, Vector3 $pos){ parent::__construct($world, $pos); $this->inventory = new CampfireInventory(); - $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange( - static function(Inventory $unused) use ($world, $pos) : void{ - $block = $world->getBlock($pos); - if($block instanceof BlockCampfire){ - $world->setBlock($pos, $block); - } - }) - ); } public function getInventory() : CampfireInventory{ diff --git a/src/block/tile/Chest.php b/src/block/tile/Chest.php index 8f5ee48fa..67581290b 100644 --- a/src/block/tile/Chest.php +++ b/src/block/tile/Chest.php @@ -94,8 +94,6 @@ class Chest extends Spawnable implements ContainerTile, Nameable{ public function close() : void{ if(!$this->closed){ - $this->inventory->removeAllViewers(); - if($this->doubleInventory !== null){ if($this->isPaired() && $this->position->getWorld()->isChunkLoaded($this->pairX >> Chunk::COORD_BIT_SIZE, $this->pairZ >> Chunk::COORD_BIT_SIZE)){ $this->doubleInventory->removeAllViewers(); diff --git a/src/block/tile/Furnace.php b/src/block/tile/Furnace.php index b6d18b0ba..4a7713f36 100644 --- a/src/block/tile/Furnace.php +++ b/src/block/tile/Furnace.php @@ -29,7 +29,6 @@ use pocketmine\crafting\FurnaceRecipe; use pocketmine\crafting\FurnaceType; use pocketmine\event\inventory\FurnaceBurnEvent; use pocketmine\event\inventory\FurnaceSmeltEvent; -use pocketmine\inventory\CallbackInventoryListener; use pocketmine\inventory\Inventory; use pocketmine\inventory\SimpleInventory; use pocketmine\item\Item; @@ -57,11 +56,6 @@ abstract class Furnace extends Spawnable implements ContainerTile, Nameable{ public function __construct(World $world, Vector3 $pos){ parent::__construct($world, $pos); $this->inventory = new SimpleInventory(3); - $this->inventory->getListeners()->add(CallbackInventoryListener::onAnyChange( - static function(Inventory $unused) use ($world, $pos) : void{ - $world->scheduleDelayedBlockUpdate($pos, 1); - }) - ); } public function readSaveData(CompoundTag $nbt) : void{ @@ -79,10 +73,6 @@ abstract class Furnace extends Spawnable implements ContainerTile, Nameable{ $this->loadName($nbt); $this->loadItems($nbt); - - if($this->remainingFuelTime > 0){ - $this->position->getWorld()->scheduleDelayedBlockUpdate($this->position, 1); - } } protected function writeSaveData(CompoundTag $nbt) : void{ @@ -97,14 +87,6 @@ abstract class Furnace extends Spawnable implements ContainerTile, Nameable{ return "Furnace"; } - public function close() : void{ - if(!$this->closed){ - $this->inventory->removeAllViewers(); - - parent::close(); - } - } - public function getInventory() : Inventory{ return $this->inventory; } diff --git a/src/block/tile/Hopper.php b/src/block/tile/Hopper.php index ed0c2c479..d001b8726 100644 --- a/src/block/tile/Hopper.php +++ b/src/block/tile/Hopper.php @@ -58,14 +58,6 @@ class Hopper extends Spawnable implements ContainerTile, Nameable{ $nbt->setInt(self::TAG_TRANSFER_COOLDOWN, $this->transferCooldown); } - public function close() : void{ - if(!$this->closed){ - $this->inventory->removeAllViewers(); - - parent::close(); - } - } - public function getDefaultName() : string{ return "Hopper"; } diff --git a/src/block/tile/ShulkerBox.php b/src/block/tile/ShulkerBox.php index c30e1696e..104f1b944 100644 --- a/src/block/tile/ShulkerBox.php +++ b/src/block/tile/ShulkerBox.php @@ -80,13 +80,6 @@ class ShulkerBox extends Spawnable implements ContainerTile, Nameable{ } } - public function close() : void{ - if(!$this->closed){ - $this->inventory->removeAllViewers(); - parent::close(); - } - } - protected function onBlockDestroyedHook() : void{ //NOOP override of ContainerTrait - shulker boxes retain their contents when destroyed } diff --git a/src/world/World.php b/src/world/World.php index ff65377c0..03ceca29c 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -30,6 +30,7 @@ use pocketmine\block\Air; use pocketmine\block\Block; use pocketmine\block\BlockTypeIds; use pocketmine\block\RuntimeBlockStateRegistry; +use pocketmine\block\tile\ContainerTile; use pocketmine\block\tile\Spawnable; use pocketmine\block\tile\Tile; use pocketmine\block\tile\TileFactory; @@ -57,6 +58,8 @@ use pocketmine\event\world\WorldDisplayNameChangeEvent; use pocketmine\event\world\WorldParticleEvent; use pocketmine\event\world\WorldSaveEvent; use pocketmine\event\world\WorldSoundEvent; +use pocketmine\inventory\Inventory; +use pocketmine\inventory\InventoryListener; use pocketmine\item\Item; use pocketmine\item\ItemUseResult; use pocketmine\item\LegacyStringToItemParser; @@ -144,7 +147,7 @@ use const PHP_INT_MIN; * @phpstan-type BlockPosHash int * @phpstan-type ChunkBlockPosHash int */ -class World implements ChunkManager{ +class World implements ChunkManager, InventoryListener{ private static int $worldIdCounter = 1; @@ -282,6 +285,12 @@ class World implements ChunkManager{ */ private array $chunks = []; + /** + * @var Vector3[]|\WeakMap + * @phpstan-var \WeakMap + */ + private \WeakMap $containerToBlockPositionMap; + /** * @var Vector3[][] chunkHash => [relativeBlockHash => Vector3] * @phpstan-var array> @@ -506,6 +515,8 @@ class World implements ChunkManager{ } }); + $this->containerToBlockPositionMap = new \WeakMap(); + $this->scheduledBlockUpdateQueue = new ReversePriorityQueue(); $this->scheduledBlockUpdateQueue->setExtractFlags(\SplPriorityQueue::EXTR_BOTH); @@ -2787,6 +2798,10 @@ class World implements ChunkManager{ //delegate tile ticking to the corresponding block $this->scheduleDelayedBlockUpdate($pos->asVector3(), 1); + if($tile instanceof ContainerTile){ + $tile->getInventory()->getListeners()->add($this); + $this->containerToBlockPositionMap[$tile->getInventory()] = $pos->asVector3(); + } } /** @@ -2805,11 +2820,40 @@ class World implements ChunkManager{ if(isset($this->chunks[$hash = World::chunkHash($chunkX, $chunkZ)])){ $this->chunks[$hash]->removeTile($tile); } + if($tile instanceof ContainerTile){ + $inventory = $tile->getInventory(); + $inventory->removeAllViewers(); + $inventory->getListeners()->remove($this); + unset($this->containerToBlockPositionMap[$inventory]); + } foreach($this->getChunkListeners($chunkX, $chunkZ) as $listener){ $listener->onBlockChanged($pos->asVector3()); } } + private function notifyInventoryUpdate(Inventory $inventory) : void{ + $blockPosition = $this->containerToBlockPositionMap[$inventory] ?? null; + if($blockPosition !== null){ + $this->scheduleDelayedBlockUpdate($blockPosition, 1); + } + } + + /** + * @internal + * @see InventoryListener + */ + public function onSlotChange(Inventory $inventory, int $slot, Item $oldItem) : void{ + $this->notifyInventoryUpdate($inventory); + } + + /** + * @internal + * @see InventoryListener + */ + public function onContentChange(Inventory $inventory, array $oldContents) : void{ + $this->notifyInventoryUpdate($inventory); + } + public function isChunkInUse(int $x, int $z) : bool{ return isset($this->chunkLoaders[$index = World::chunkHash($x, $z)]) && count($this->chunkLoaders[$index]) > 0; }