From 496ab808a866618a9e1732fc72b377374b319814 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Aug 2025 21:35:42 +0100 Subject: [PATCH] First step towards standardised opening logic for containers and menu blocks we'll want to introduce interfaces for these, but getting the code deduplicated is enough to start with. --- src/block/Anvil.php | 11 ++-- src/block/Barrel.php | 19 +------ src/block/BrewingStand.php | 17 +++--- src/block/CartographyTable.php | 14 ++--- src/block/Chest.php | 49 ++++++++--------- src/block/CraftingTable.php | 14 ++--- src/block/EnchantingTable.php | 15 ++---- src/block/EnderChest.php | 16 +++--- src/block/Furnace.php | 19 +++---- src/block/Hopper.php | 17 +++--- src/block/Loom.php | 14 ++--- src/block/ShulkerBox.php | 25 ++++----- src/block/SmithingTable.php | 15 +++--- src/block/Stonecutter.php | 12 ++--- src/block/utils/ContainerOpenResult.php | 43 +++++++++++++++ src/block/utils/ContainerTrait.php | 72 +++++++++++++++++++++++++ src/block/utils/InventoryMenuTrait.php | 60 +++++++++++++++++++++ 17 files changed, 270 insertions(+), 162 deletions(-) create mode 100644 src/block/utils/ContainerOpenResult.php create mode 100644 src/block/utils/ContainerTrait.php create mode 100644 src/block/utils/InventoryMenuTrait.php diff --git a/src/block/Anvil.php b/src/block/Anvil.php index dc9a75a18..7de5e471a 100644 --- a/src/block/Anvil.php +++ b/src/block/Anvil.php @@ -29,6 +29,7 @@ use pocketmine\block\utils\FallableTrait; use pocketmine\block\utils\HorizontalFacing; use pocketmine\block\utils\HorizontalFacingOption; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\block\utils\SupportType; use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\entity\object\FallingBlock; @@ -39,6 +40,7 @@ use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\utils\Utils; use pocketmine\world\BlockTransaction; +use pocketmine\world\Position; use pocketmine\world\sound\AnvilFallSound; use pocketmine\world\sound\Sound; use function round; @@ -46,6 +48,7 @@ use function round; class Anvil extends Transparent implements Fallable, HorizontalFacing{ use FallableTrait; use HorizontalFacingTrait; + use InventoryMenuTrait; public const UNDAMAGED = 0; public const SLIGHTLY_DAMAGED = 1; @@ -80,12 +83,8 @@ class Anvil extends Transparent implements Fallable, HorizontalFacing{ return SupportType::NONE; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $player->setCurrentWindow(new AnvilInventoryWindow($player, $this->position)); - } - - return true; + protected function newWindow(Player $player, Position $position) : AnvilInventoryWindow{ + return new AnvilInventoryWindow($player, $position); } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, Facing $face, Vector3 $clickVector, ?Player $player = null) : bool{ diff --git a/src/block/Barrel.php b/src/block/Barrel.php index b17c583e8..363b73acd 100644 --- a/src/block/Barrel.php +++ b/src/block/Barrel.php @@ -23,12 +23,11 @@ declare(strict_types=1); namespace pocketmine\block; -use pocketmine\block\inventory\window\BlockInventoryWindow; -use pocketmine\block\tile\Barrel as TileBarrel; use pocketmine\block\utils\AnimatedContainer; use pocketmine\block\utils\AnimatedContainerTrait; use pocketmine\block\utils\AnyFacing; use pocketmine\block\utils\AnyFacingTrait; +use pocketmine\block\utils\ContainerTrait; use pocketmine\data\runtime\RuntimeDataDescriber; use pocketmine\item\Item; use pocketmine\math\Facing; @@ -44,6 +43,7 @@ use function abs; class Barrel extends Opaque implements AnimatedContainer, AnyFacing{ use AnimatedContainerTrait; use AnyFacingTrait; + use ContainerTrait; protected bool $open = false; @@ -82,21 +82,6 @@ class Barrel extends Opaque implements AnimatedContainer, AnyFacing{ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $barrel = $this->position->getWorld()->getTile($this->position); - if($barrel instanceof TileBarrel){ - if(!$barrel->canOpenWith($item->getCustomName())){ - return true; - } - - $player->setCurrentWindow(new BlockInventoryWindow($player, $barrel->getInventory(), $this->position)); - } - } - - return true; - } - public function getFuelTime() : int{ return 300; } diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index 0184de199..210384ea8 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -26,18 +26,20 @@ namespace pocketmine\block; use pocketmine\block\inventory\window\BrewingStandInventoryWindow; use pocketmine\block\tile\BrewingStand as TileBrewingStand; use pocketmine\block\utils\BrewingStandSlot; +use pocketmine\block\utils\ContainerTrait; use pocketmine\block\utils\SupportType; use pocketmine\data\runtime\RuntimeDataDescriber; -use pocketmine\item\Item; +use pocketmine\inventory\Inventory; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; -use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\world\Position; use function array_key_exists; use function spl_object_id; class BrewingStand extends Transparent{ + use ContainerTrait; /** * @var BrewingStandSlot[] @@ -96,15 +98,8 @@ class BrewingStand extends Transparent{ return $this; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $stand = $this->position->getWorld()->getTile($this->position); - if($stand instanceof TileBrewingStand && $stand->canOpenWith($item->getCustomName())){ - $player->setCurrentWindow(new BrewingStandInventoryWindow($player, $stand->getInventory(), $this->position)); - } - } - - return true; + protected function newWindow(Player $player, Inventory $inventory, Position $position) : BrewingStandInventoryWindow{ + return new BrewingStandInventoryWindow($player, $inventory, $position); } public function onScheduledUpdate() : void{ diff --git a/src/block/CartographyTable.php b/src/block/CartographyTable.php index 28ca59f7c..a1eeb6cb2 100644 --- a/src/block/CartographyTable.php +++ b/src/block/CartographyTable.php @@ -24,19 +24,15 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\window\CartographyTableInventoryWindow; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\player\Player; +use pocketmine\world\Position; final class CartographyTable extends Opaque{ + use InventoryMenuTrait; - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player !== null){ - $player->setCurrentWindow(new CartographyTableInventoryWindow($player, $this->position)); - } - - return true; + protected function newWindow(Player $player, Position $position) : CartographyTableInventoryWindow{ + return new CartographyTableInventoryWindow($player, $position); } public function getFuelTime() : int{ diff --git a/src/block/Chest.php b/src/block/Chest.php index c5ae39f26..77cb02492 100644 --- a/src/block/Chest.php +++ b/src/block/Chest.php @@ -28,16 +28,17 @@ use pocketmine\block\inventory\window\DoubleChestInventoryWindow; use pocketmine\block\tile\Chest as TileChest; use pocketmine\block\utils\AnimatedContainer; use pocketmine\block\utils\AnimatedContainerTrait; +use pocketmine\block\utils\ContainerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacing; use pocketmine\block\utils\SupportType; use pocketmine\event\block\ChestPairEvent; -use pocketmine\item\Item; +use pocketmine\inventory\Inventory; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; -use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\types\BlockPosition; +use pocketmine\player\InventoryWindow; use pocketmine\player\Player; use pocketmine\world\Position; use pocketmine\world\sound\ChestCloseSound; @@ -46,6 +47,7 @@ use pocketmine\world\sound\Sound; class Chest extends Transparent implements AnimatedContainer, HorizontalFacing{ use AnimatedContainerTrait; + use ContainerTrait; use FacesOppositePlacingPlayerTrait; protected function recalculateCollisionBoxes() : array{ @@ -100,34 +102,25 @@ class Chest extends Transparent implements AnimatedContainer, HorizontalFacing{ } } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $world = $this->position->getWorld(); - $chest = $world->getTile($this->position); - if($chest instanceof TileChest){ - [$pairOnLeft, $pair] = $this->locatePair($this->position) ?? [false, null]; - if( - !$this->getSide(Facing::UP)->isTransparent() || - ($pair !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent()) || - !$chest->canOpenWith($item->getCustomName()) - ){ - return true; - } - - if($pair !== null){ - [$left, $right] = $pairOnLeft ? [$pair->getBlock(), $this] : [$this, $pair->getBlock()]; - - //TODO: we should probably construct DoubleChestInventory here directly too using the same logic - //right now it uses some weird logic in TileChest which produces incorrect results - //however I'm not sure if this is currently possible - $window = new DoubleChestInventoryWindow($player, $chest->getInventory(), $left->position, $right->position); - } - - $player->setCurrentWindow($window ?? new BlockInventoryWindow($player, $chest->getInventory(), $this->position)); - } + protected function isOpeningObstructed() : bool{ + if(!$this->getSide(Facing::UP)->isTransparent()){ + return true; } + [, $pair] = $this->locatePair($this->position) ?? [false, null]; + return $pair !== null && !$pair->getBlock()->getSide(Facing::UP)->isTransparent(); + } - return true; + protected function newWindow(Player $player, Inventory $inventory, Position $position) : InventoryWindow{ + [$pairOnLeft, $pair] = $this->locatePair($position) ?? [false, null]; + if($pair === null){ + return new BlockInventoryWindow($player, $inventory, $position); + } + [$left, $right] = $pairOnLeft ? [$pair->getPosition(), $position] : [$position, $pair->getPosition()]; + + //TODO: we should probably construct DoubleChestInventory here directly too using the same logic + //right now it uses some weird logic in TileChest which produces incorrect results + //however I'm not sure if this is currently possible + return new DoubleChestInventoryWindow($player, $inventory, $left, $right); } public function getFuelTime() : int{ diff --git a/src/block/CraftingTable.php b/src/block/CraftingTable.php index 99d509660..d8ef03def 100644 --- a/src/block/CraftingTable.php +++ b/src/block/CraftingTable.php @@ -24,19 +24,15 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\window\CraftingTableInventoryWindow; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\player\Player; +use pocketmine\world\Position; class CraftingTable extends Opaque{ + use InventoryMenuTrait; - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $player->setCurrentWindow(new CraftingTableInventoryWindow($player, $this->position)); - } - - return true; + protected function newWindow(Player $player, Position $position) : CraftingTableInventoryWindow{ + return new CraftingTableInventoryWindow($player, $position); } public function getFuelTime() : int{ diff --git a/src/block/EnchantingTable.php b/src/block/EnchantingTable.php index 2344ae793..7756e10fb 100644 --- a/src/block/EnchantingTable.php +++ b/src/block/EnchantingTable.php @@ -24,14 +24,15 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\window\EnchantingTableInventoryWindow; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\block\utils\SupportType; -use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; -use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\world\Position; class EnchantingTable extends Transparent{ + use InventoryMenuTrait; protected function recalculateCollisionBoxes() : array{ return [AxisAlignedBB::one()->trimmedCopy(Facing::UP, 0.25)]; @@ -41,13 +42,7 @@ class EnchantingTable extends Transparent{ return SupportType::NONE; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - //TODO lock - - $player->setCurrentWindow(new EnchantingTableInventoryWindow($player, $this->position)); - } - - return true; + protected function newWindow(Player $player, Position $position) : EnchantingTableInventoryWindow{ + return new EnchantingTableInventoryWindow($player, $position); } } diff --git a/src/block/EnderChest.php b/src/block/EnderChest.php index 70eb739ff..ce07f0e73 100644 --- a/src/block/EnderChest.php +++ b/src/block/EnderChest.php @@ -29,11 +29,11 @@ use pocketmine\block\utils\AnimatedContainer; use pocketmine\block\utils\AnimatedContainerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacing; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; -use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\types\BlockPosition; use pocketmine\player\Player; @@ -47,6 +47,7 @@ class EnderChest extends Transparent implements AnimatedContainer, HorizontalFac onContainerOpen as private traitOnContainerOpen; onContainerClose as private traitOnContainerClose; } + use InventoryMenuTrait; use FacesOppositePlacingPlayerTrait; public function getLightLevel() : int{ @@ -62,15 +63,12 @@ class EnderChest extends Transparent implements AnimatedContainer, HorizontalFac return SupportType::NONE; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $enderChest = $this->position->getWorld()->getTile($this->position); - if($enderChest instanceof TileEnderChest && $this->getSide(Facing::UP)->isTransparent()){ - $player->setCurrentWindow(new BlockInventoryWindow($player, $player->getEnderInventory(), $this->position)); - } - } + protected function isOpeningObstructed() : bool{ + return !$this->getSide(Facing::UP)->isTransparent(); + } - return true; + protected function newWindow(Player $player, Position $position) : BlockInventoryWindow{ + return new BlockInventoryWindow($player, $player->getEnderInventory(), $position); } public function getDropsForCompatibleTool(Item $item) : array{ diff --git a/src/block/Furnace.php b/src/block/Furnace.php index 9a315dc1c..4ced668e2 100644 --- a/src/block/Furnace.php +++ b/src/block/Furnace.php @@ -25,19 +25,21 @@ namespace pocketmine\block; use pocketmine\block\inventory\window\FurnaceInventoryWindow; use pocketmine\block\tile\Furnace as TileFurnace; +use pocketmine\block\utils\ContainerTrait; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacing; use pocketmine\block\utils\Lightable; use pocketmine\block\utils\LightableTrait; use pocketmine\crafting\FurnaceType; use pocketmine\data\runtime\RuntimeDataDescriber; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; +use pocketmine\inventory\Inventory; +use pocketmine\player\InventoryWindow; use pocketmine\player\Player; +use pocketmine\world\Position; use function mt_rand; class Furnace extends Opaque implements Lightable, HorizontalFacing{ + use ContainerTrait; use FacesOppositePlacingPlayerTrait; use LightableTrait; @@ -61,15 +63,8 @@ class Furnace extends Opaque implements Lightable, HorizontalFacing{ return $this->lit ? 13 : 0; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ - $furnace = $this->position->getWorld()->getTile($this->position); - if($furnace instanceof TileFurnace && $furnace->canOpenWith($item->getCustomName())){ - $player->setCurrentWindow(new FurnaceInventoryWindow($player, $furnace->getInventory(), $this->position, $this->furnaceType)); - } - } - - return true; + protected function newWindow(Player $player, Inventory $inventory, Position $position) : InventoryWindow{ + return new FurnaceInventoryWindow($player, $inventory, $position, $this->furnaceType); } public function onScheduledUpdate() : void{ diff --git a/src/block/Hopper.php b/src/block/Hopper.php index e0a0f6dc7..0117edb5f 100644 --- a/src/block/Hopper.php +++ b/src/block/Hopper.php @@ -24,19 +24,23 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\window\HopperInventoryWindow; -use pocketmine\block\tile\Hopper as TileHopper; +use pocketmine\block\utils\ContainerTrait; use pocketmine\block\utils\PoweredByRedstone; use pocketmine\block\utils\PoweredByRedstoneTrait; use pocketmine\block\utils\SupportType; use pocketmine\data\runtime\RuntimeDataDescriber; +use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; +use pocketmine\player\InventoryWindow; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; +use pocketmine\world\Position; class Hopper extends Transparent implements PoweredByRedstone{ + use ContainerTrait; use PoweredByRedstoneTrait; private Facing $facing = Facing::DOWN; @@ -82,15 +86,8 @@ class Hopper extends Transparent implements PoweredByRedstone{ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player !== null){ - $tile = $this->position->getWorld()->getTile($this->position); - if($tile instanceof TileHopper){ //TODO: find a way to have inventories open on click without this boilerplate in every block - $player->setCurrentWindow(new HopperInventoryWindow($player, $tile->getInventory(), $this->position)); - } - return true; - } - return false; + protected function newWindow(Player $player, Inventory $inventory, Position $position) : InventoryWindow{ + return new HopperInventoryWindow($player, $inventory, $position); } public function onScheduledUpdate() : void{ diff --git a/src/block/Loom.php b/src/block/Loom.php index 3c7cf2cc8..564117692 100644 --- a/src/block/Loom.php +++ b/src/block/Loom.php @@ -26,19 +26,15 @@ namespace pocketmine\block; use pocketmine\block\inventory\window\LoomInventoryWindow; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacing; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\player\Player; +use pocketmine\world\Position; final class Loom extends Opaque implements HorizontalFacing{ use FacesOppositePlacingPlayerTrait; + use InventoryMenuTrait; - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player !== null){ - $player->setCurrentWindow(new LoomInventoryWindow($player, $this->position)); - return true; - } - return false; + protected function newWindow(Player $player, Position $position) : LoomInventoryWindow{ + return new LoomInventoryWindow($player, $position); } } diff --git a/src/block/ShulkerBox.php b/src/block/ShulkerBox.php index c29999992..5b6d051c3 100644 --- a/src/block/ShulkerBox.php +++ b/src/block/ShulkerBox.php @@ -29,13 +29,16 @@ use pocketmine\block\utils\AnimatedContainer; use pocketmine\block\utils\AnimatedContainerTrait; use pocketmine\block\utils\AnyFacing; use pocketmine\block\utils\AnyFacingTrait; +use pocketmine\block\utils\ContainerTrait; use pocketmine\block\utils\SupportType; use pocketmine\data\runtime\RuntimeDataDescriber; +use pocketmine\inventory\Inventory; use pocketmine\item\Item; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\BlockEventPacket; use pocketmine\network\mcpe\protocol\types\BlockPosition; +use pocketmine\player\InventoryWindow; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; use pocketmine\world\Position; @@ -46,6 +49,7 @@ use pocketmine\world\sound\Sound; class ShulkerBox extends Opaque implements AnimatedContainer, AnyFacing{ use AnimatedContainerTrait; use AnyFacingTrait; + use ContainerTrait; protected function describeBlockOnlyState(RuntimeDataDescriber $w) : void{ //NOOP - we don't read or write facing here, because the tile persists it @@ -105,23 +109,12 @@ class ShulkerBox extends Opaque implements AnimatedContainer, AnyFacing{ return $result; } - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player instanceof Player){ + protected function isOpeningObstructed() : bool{ + return $this->getSide($this->facing)->isSolid(); + } - $shulker = $this->position->getWorld()->getTile($this->position); - if($shulker instanceof TileShulkerBox){ - if( - $this->getSide($this->facing)->isSolid() || - !$shulker->canOpenWith($item->getCustomName()) - ){ - return true; - } - - $player->setCurrentWindow(new BlockInventoryWindow($player, $shulker->getInventory(), $this->position)); - } - } - - return true; + protected function newWindow(Player $player, Inventory $inventory, Position $position) : InventoryWindow{ + return new BlockInventoryWindow($player, $inventory, $position); } public function getSupportType(Facing $facing) : SupportType{ diff --git a/src/block/SmithingTable.php b/src/block/SmithingTable.php index 01fdbc189..d6c6ddd5d 100644 --- a/src/block/SmithingTable.php +++ b/src/block/SmithingTable.php @@ -24,19 +24,16 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\window\SmithingTableInventoryWindow; -use pocketmine\item\Item; -use pocketmine\math\Facing; -use pocketmine\math\Vector3; +use pocketmine\block\utils\InventoryMenuTrait; +use pocketmine\player\InventoryWindow; use pocketmine\player\Player; +use pocketmine\world\Position; final class SmithingTable extends Opaque{ + use InventoryMenuTrait; - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player !== null){ - $player->setCurrentWindow(new SmithingTableInventoryWindow($player, $this->position)); - } - - return true; + protected function newWindow(Player $player, Position $position) : InventoryWindow{ + return new SmithingTableInventoryWindow($player, $position); } public function getFuelTime() : int{ diff --git a/src/block/Stonecutter.php b/src/block/Stonecutter.php index f254b4950..31dc10220 100644 --- a/src/block/Stonecutter.php +++ b/src/block/Stonecutter.php @@ -26,21 +26,19 @@ namespace pocketmine\block; use pocketmine\block\inventory\window\StonecutterInventoryWindow; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacing; +use pocketmine\block\utils\InventoryMenuTrait; use pocketmine\block\utils\SupportType; -use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; -use pocketmine\math\Vector3; use pocketmine\player\Player; +use pocketmine\world\Position; class Stonecutter extends Transparent implements HorizontalFacing{ use FacesOppositePlacingPlayerTrait; + use InventoryMenuTrait; - public function onInteract(Item $item, Facing $face, Vector3 $clickVector, ?Player $player = null, array &$returnedItems = []) : bool{ - if($player !== null){ - $player->setCurrentWindow(new StonecutterInventoryWindow($player, $this->position)); - } - return true; + protected function newWindow(Player $player, Position $position) : StonecutterInventoryWindow{ + return new StonecutterInventoryWindow($player, $position); } protected function recalculateCollisionBoxes() : array{ diff --git a/src/block/utils/ContainerOpenResult.php b/src/block/utils/ContainerOpenResult.php new file mode 100644 index 000000000..b06c0d875 --- /dev/null +++ b/src/block/utils/ContainerOpenResult.php @@ -0,0 +1,43 @@ +openTo($player, ignoreObstruction: false, ignoreLock: false); + } + + return true; + } + + protected function isOpeningObstructed() : bool{ + return false; + } + + protected function newWindow(Player $player, Inventory $inventory, Position $position) : InventoryWindow{ + return new BlockInventoryWindow($player, $inventory, $position); + } + + public function openTo(Player $player, bool $ignoreObstruction, bool $ignoreLock) : ContainerOpenResult{ + $tile = $this->position->getWorld()->getTile($this->position); + if(!$tile instanceof ContainerTile){ + return ContainerOpenResult::CONTAINER_NOT_FOUND; + } + if(!$ignoreLock && !$tile->canOpenWith($player->getHotbar()->getHeldItem()->getCustomName())){ + return ContainerOpenResult::INCORRECT_KEY; + } + if(!$ignoreObstruction && $this->isOpeningObstructed()){ + return ContainerOpenResult::OBSTRUCTED; + } + $window = $this->newWindow($player, $tile->getInventory(), $this->position); + $player->setCurrentWindow($window); + return ContainerOpenResult::SUCCESS; + } +} diff --git a/src/block/utils/InventoryMenuTrait.php b/src/block/utils/InventoryMenuTrait.php new file mode 100644 index 000000000..3ba02e51a --- /dev/null +++ b/src/block/utils/InventoryMenuTrait.php @@ -0,0 +1,60 @@ +openTo($player, ignoreObstruction: false); + } + + return true; + } + + abstract protected function newWindow(Player $player, Position $position) : InventoryWindow; + + protected function isOpeningObstructed() : bool{ + return false; + } + + public function openTo(Player $player, bool $ignoreObstruction) : bool{ + if(!$ignoreObstruction && $this->isOpeningObstructed()){ + return false; + } + $player->setCurrentWindow($this->newWindow($player, $this->position)); + return true; + } +}