Revert "Chest block now has responsibility for configuring double chest inventories"

This reverts commit 1d2b52732e3c475ddc2bab4e45726d22850e3d5c.

I hadn't considered that the likes of plugins and hoppers need to be
able to interact with double chest inventories as well as players.

If we were to move this logic to the Block side, we'd have to expose
APIs on the Chest block to get the correct inventory lazily. I'm not
sure I want to commit to having getInventory() on the block right now,
as we can't guarantee it's available (see problems around Campfire
inventory on the block).

Short term, it'll probably be better to just expose the logic in
block\Chest for deciding which side the inventories should be on.
This commit is contained in:
Dylan K. Taylor 2024-12-07 16:04:50 +00:00
parent b5a69c829d
commit ef3d16597a
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
11 changed files with 66 additions and 37 deletions

View File

@ -109,30 +109,22 @@ class Chest extends Transparent implements AnimatedContainer{
$world = $this->position->getWorld(); $world = $this->position->getWorld();
$chest = $world->getTile($this->position); $chest = $world->getTile($this->position);
if($chest instanceof TileChest){ if($chest instanceof TileChest){
[$pairOnLeft, $pair] = $this->locatePair($this->position) ?? [false, null];
if( if(
!$this->getSide(Facing::UP)->isTransparent() || !$this->getSide(Facing::UP)->isTransparent() ||
(($pair = $chest->getPair()) !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) || ($pair !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) ||
!$chest->canOpenWith($item->getCustomName()) !$chest->canOpenWith($item->getCustomName())
){ ){
return true; return true;
} }
$window = null; if($pair !== null){
if($chest->isPaired()){ [$left, $right] = $pairOnLeft ? [$pair->getPosition(), $this->position] : [$this->position, $pair->getPosition()];
$info = $this->locatePair($this->position);
if($info !== null){
[$clockwise, $pair] = $info;
[$left, $right] = $clockwise ? [$pair, $chest] : [$chest, $pair];
$doubleInventory = $left->getDoubleInventory() ?? $right->getDoubleInventory(); //TODO: we should probably construct DoubleChestInventory here directly too using the same logic
if($doubleInventory === null){ //right now it uses some weird logic in TileChest which produces incorrect results
$doubleInventory = new DoubleChestInventory($left->getInventory(), $right->getInventory()); //however I'm not sure if this is currently possible
$left->setDoubleInventory($doubleInventory); $window = new DoubleChestInventoryWindow($player, $chest->getInventory(), $left, $right);
$right->setDoubleInventory($doubleInventory);
}
$window = new DoubleChestInventoryWindow($player, $doubleInventory, $left->getPosition(), $right->getPosition());
}
} }
$player->setCurrentWindow($window ?? new BlockInventoryWindow($player, $chest->getInventory(), $this->position)); $player->setCurrentWindow($window ?? new BlockInventoryWindow($player, $chest->getInventory(), $this->position));
@ -146,15 +138,6 @@ class Chest extends Transparent implements AnimatedContainer{
return 300; return 300;
} }
protected function getContainerViewerCount() : int{
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileChest){
$inventory = $tile->getDoubleInventory() ?? $tile->getInventory();
return count($inventory->getViewers());
}
return 0;
}
protected function getContainerOpenSound() : Sound{ protected function getContainerOpenSound() : Sound{
return new ChestOpenSound(); return new ChestOpenSound();
} }

View File

@ -54,6 +54,10 @@ class Barrel extends Spawnable implements ContainerTile, Nameable{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->inventory;
}
public function getDefaultName() : string{ public function getDefaultName() : string{
return "Barrel"; return "Barrel";
} }

View File

@ -105,6 +105,10 @@ class BrewingStand extends Spawnable implements ContainerTile, Nameable{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->inventory;
}
private function checkFuel(Item $item) : void{ private function checkFuel(Item $item) : void{
$ev = new BrewingFuelUseEvent($this); $ev = new BrewingFuelUseEvent($this);
if(!$item->equals(VanillaItems::BLAZE_POWDER(), true, false)){ if(!$item->equals(VanillaItems::BLAZE_POWDER(), true, false)){

View File

@ -59,6 +59,10 @@ class Campfire extends Spawnable implements ContainerTile{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->inventory;
}
/** /**
* @return int[] * @return int[]
* @phpstan-return array<int, int> * @phpstan-return array<int, int>

View File

@ -113,14 +113,15 @@ class Chest extends Spawnable implements ContainerTile, Nameable{
$this->containerTraitBlockDestroyedHook(); $this->containerTraitBlockDestroyedHook();
} }
public function getInventory() : Inventory{ public function getInventory() : Inventory|DoubleChestInventory{
return $this->inventory; if($this->isPaired() && $this->doubleInventory === null){
$this->checkPairing();
}
return $this->doubleInventory instanceof DoubleChestInventory ? $this->doubleInventory : $this->inventory;
} }
public function getDoubleInventory() : ?DoubleChestInventory{ return $this->doubleInventory; } public function getRealInventory() : Inventory{
return $this->inventory;
public function setDoubleInventory(?DoubleChestInventory $doubleChestInventory) : void{
$this->doubleInventory = $doubleChestInventory;
} }
protected function checkPairing() : void{ protected function checkPairing() : void{
@ -131,7 +132,18 @@ class Chest extends Spawnable implements ContainerTile, Nameable{
}elseif(($pair = $this->getPair()) instanceof Chest){ }elseif(($pair = $this->getPair()) instanceof Chest){
if(!$pair->isPaired()){ if(!$pair->isPaired()){
$pair->createPair($this); $pair->createPair($this);
$this->doubleInventory = $pair->doubleInventory = null; $pair->checkPairing();
}
if($this->doubleInventory === null){
if($pair->doubleInventory !== null){
$this->doubleInventory = $pair->doubleInventory;
}else{
if(($pair->position->x + ($pair->position->z << 15)) > ($this->position->x + ($this->position->z << 15))){ //Order them correctly
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($pair->inventory, $this->inventory);
}else{
$this->doubleInventory = $pair->doubleInventory = new DoubleChestInventory($this->inventory, $pair->inventory);
}
}
} }
}else{ }else{
$this->doubleInventory = null; $this->doubleInventory = null;

View File

@ -55,6 +55,10 @@ class ChiseledBookshelf extends Tile implements ContainerTile{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : SimpleInventory{
return $this->inventory;
}
public function getLastInteractedSlot() : ?ChiseledBookshelfSlot{ public function getLastInteractedSlot() : ?ChiseledBookshelfSlot{
return $this->lastInteractedSlot; return $this->lastInteractedSlot;
} }
@ -83,7 +87,7 @@ class ChiseledBookshelf extends Tile implements ContainerTile{
protected function loadItems(CompoundTag $tag) : void{ protected function loadItems(CompoundTag $tag) : void{
if(($inventoryTag = $tag->getTag(ContainerTile::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){ if(($inventoryTag = $tag->getTag(ContainerTile::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){
$inventory = $this->inventory; $inventory = $this->getRealInventory();
$listeners = $inventory->getListeners()->toArray(); $listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization $inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization
@ -114,7 +118,7 @@ class ChiseledBookshelf extends Tile implements ContainerTile{
protected function saveItems(CompoundTag $tag) : void{ protected function saveItems(CompoundTag $tag) : void{
$items = []; $items = [];
foreach($this->inventory->getContents(true) as $slot => $item){ foreach($this->getRealInventory()->getContents(true) as $slot => $item){
if($item->isNull()){ if($item->isNull()){
$items[$slot] = CompoundTag::create() $items[$slot] = CompoundTag::create()
->setByte(SavedItemStackData::TAG_COUNT, 0) ->setByte(SavedItemStackData::TAG_COUNT, 0)

View File

@ -23,12 +23,15 @@ declare(strict_types=1);
namespace pocketmine\block\tile; namespace pocketmine\block\tile;
use pocketmine\inventory\Inventory;
use pocketmine\inventory\InventoryHolder; use pocketmine\inventory\InventoryHolder;
interface ContainerTile extends InventoryHolder{ interface ContainerTile extends InventoryHolder{
public const TAG_ITEMS = "Items"; public const TAG_ITEMS = "Items";
public const TAG_LOCK = "Lock"; public const TAG_LOCK = "Lock";
public function getRealInventory() : Inventory;
/** /**
* Returns whether this container can be opened by an item with the given custom name. * Returns whether this container can be opened by an item with the given custom name.
*/ */

View File

@ -25,6 +25,7 @@ namespace pocketmine\block\tile;
use pocketmine\data\bedrock\item\SavedItemStackData; use pocketmine\data\bedrock\item\SavedItemStackData;
use pocketmine\data\SavedDataLoadingException; use pocketmine\data\SavedDataLoadingException;
use pocketmine\inventory\Inventory;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -39,9 +40,11 @@ trait ContainerTileTrait{
/** @var string|null */ /** @var string|null */
private $lock = null; private $lock = null;
abstract public function getRealInventory() : Inventory;
protected function loadItems(CompoundTag $tag) : void{ protected function loadItems(CompoundTag $tag) : void{
if(($inventoryTag = $tag->getTag(ContainerTile::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){ if(($inventoryTag = $tag->getTag(ContainerTile::TAG_ITEMS)) instanceof ListTag && $inventoryTag->getTagType() === NBT::TAG_Compound){
$inventory = $this->getInventory(); $inventory = $this->getRealInventory();
$listeners = $inventory->getListeners()->toArray(); $listeners = $inventory->getListeners()->toArray();
$inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization $inventory->getListeners()->remove(...$listeners); //prevent any events being fired by initialization
@ -68,7 +71,7 @@ trait ContainerTileTrait{
protected function saveItems(CompoundTag $tag) : void{ protected function saveItems(CompoundTag $tag) : void{
$items = []; $items = [];
foreach($this->getInventory()->getContents() as $slot => $item){ foreach($this->getRealInventory()->getContents() as $slot => $item){
$items[] = $item->nbtSerialize($slot); $items[] = $item->nbtSerialize($slot);
} }
@ -95,7 +98,7 @@ trait ContainerTileTrait{
* @see Tile::onBlockDestroyedHook() * @see Tile::onBlockDestroyedHook()
*/ */
protected function onBlockDestroyedHook() : void{ protected function onBlockDestroyedHook() : void{
$inv = $this->getInventory(); $inv = $this->getRealInventory();
$pos = $this->getPosition(); $pos = $this->getPosition();
$world = $pos->getWorld(); $world = $pos->getWorld();

View File

@ -91,6 +91,10 @@ abstract class Furnace extends Spawnable implements ContainerTile, Nameable{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->getInventory();
}
protected function checkFuel(Item $fuel) : void{ protected function checkFuel(Item $fuel) : void{
$ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime()); $ev = new FurnaceBurnEvent($this, $fuel, $fuel->getFuelTime());
$ev->call(); $ev->call();

View File

@ -65,4 +65,8 @@ class Hopper extends Spawnable implements ContainerTile, Nameable{
public function getInventory() : Inventory{ public function getInventory() : Inventory{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->inventory;
}
} }

View File

@ -104,6 +104,10 @@ class ShulkerBox extends Spawnable implements ContainerTile, Nameable{
return $this->inventory; return $this->inventory;
} }
public function getRealInventory() : Inventory{
return $this->inventory;
}
public function getDefaultName() : string{ public function getDefaultName() : string{
return "Shulker Box"; return "Shulker Box";
} }