From 6482aa7c645b85e8740f3851ae3f32637dcebf65 Mon Sep 17 00:00:00 2001 From: ShockedPlot7560 <66992287+ShockedPlot7560@users.noreply.github.com> Date: Fri, 20 May 2022 16:18:34 +0200 Subject: [PATCH] Block: introduce logic for face support types (#4886) fixes #4856 fixes #458 fixes #4529 fixes #3299 Added API method Block::getSupportType(Facing) : SupportType Added SupportType enum fixes torch, lantern, door etc. placement on slabs and upside-down stairs --- src/block/Air.php | 19 +------ src/block/Anvil.php | 5 ++ src/block/Bamboo.php | 5 ++ src/block/BaseBanner.php | 5 ++ src/block/BaseCoral.php | 5 ++ src/block/BaseRail.php | 6 +-- src/block/BaseSign.php | 5 ++ src/block/Bed.php | 14 ++++-- src/block/Bell.php | 5 ++ src/block/Block.php | 5 ++ src/block/BrewingStand.php | 5 ++ src/block/Button.php | 18 +++++-- src/block/Cactus.php | 5 ++ src/block/Cake.php | 5 ++ src/block/Chest.php | 5 ++ src/block/CocoaBlock.php | 5 ++ src/block/Coral.php | 9 +++- src/block/DaylightSensor.php | 5 ++ src/block/Door.php | 13 ++++- src/block/DragonEgg.php | 5 ++ src/block/EnchantingTable.php | 5 ++ src/block/EnderChest.php | 5 ++ src/block/Fence.php | 5 ++ src/block/FenceGate.php | 5 ++ src/block/FloorCoralFan.php | 9 +++- src/block/Flowable.php | 5 ++ src/block/FlowerPot.php | 8 ++- src/block/Hopper.php | 9 ++++ src/block/Ladder.php | 13 ++++- src/block/Lantern.php | 16 ++++-- src/block/Leaves.php | 5 ++ src/block/Lectern.php | 5 ++ src/block/Lever.php | 9 +++- src/block/Liquid.php | 5 ++ src/block/MonsterSpawner.php | 5 ++ src/block/NetherPortal.php | 5 ++ src/block/PressurePlate.php | 22 ++++++++ src/block/RedstoneComparator.php | 9 +++- src/block/RedstoneRepeater.php | 9 +++- src/block/RedstoneWire.php | 22 ++++++++ src/block/SeaPickle.php | 5 ++ src/block/Slab.php | 10 ++++ src/block/SnowLayer.php | 10 +++- src/block/Stair.php | 15 ++++++ src/block/Stonecutter.php | 5 ++ src/block/Thin.php | 5 ++ src/block/Torch.php | 15 ++++-- src/block/Trapdoor.php | 5 ++ src/block/Wall.php | 6 +++ src/block/WallCoralFan.php | 8 ++- src/block/utils/SupportType.php | 58 ++++++++++++++++++++++ tests/phpstan/configs/actual-problems.neon | 15 ++++++ 52 files changed, 427 insertions(+), 55 deletions(-) create mode 100644 src/block/utils/SupportType.php diff --git a/src/block/Air.php b/src/block/Air.php index 8e1104bba..624af39df 100644 --- a/src/block/Air.php +++ b/src/block/Air.php @@ -23,16 +23,10 @@ declare(strict_types=1); namespace pocketmine\block; -use pocketmine\math\AxisAlignedBB; - /** * Air block */ -class Air extends Transparent{ - - public function canBeFlowedInto() : bool{ - return true; - } +class Air extends Flowable{ public function canBeReplaced() : bool{ return true; @@ -41,15 +35,4 @@ class Air extends Transparent{ public function canBePlaced() : bool{ return false; } - - public function isSolid() : bool{ - return false; - } - - /** - * @return AxisAlignedBB[] - */ - protected function recalculateCollisionBoxes() : array{ - return []; - } } diff --git a/src/block/Anvil.php b/src/block/Anvil.php index 5a97384c5..d4f2e239e 100644 --- a/src/block/Anvil.php +++ b/src/block/Anvil.php @@ -28,6 +28,7 @@ use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\Fallable; use pocketmine\block\utils\FallableTrait; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -80,6 +81,10 @@ class Anvil extends Transparent implements Fallable{ return [AxisAlignedBB::one()->squash(Facing::axis(Facing::rotateY($this->facing, false)), 1 / 8)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ $player->setCurrentWindow(new AnvilInventory($this->position)); diff --git a/src/block/Bamboo.php b/src/block/Bamboo.php index 7fdf226a0..8f61b36eb 100644 --- a/src/block/Bamboo.php +++ b/src/block/Bamboo.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\block\utils\SupportType; use pocketmine\event\block\StructureGrowEvent; use pocketmine\item\Bamboo as ItemBamboo; use pocketmine\item\Fertilizer; @@ -100,6 +101,10 @@ class Bamboo extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::SOUTH, $inset)->trim(Facing::EAST, $inset)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + private static function getOffsetSeed(int $x, int $y, int $z) : int{ $p1 = gmp_mul($z, 0x6ebfff5); $p2 = gmp_mul($x, 0x2fc20f); diff --git a/src/block/BaseBanner.php b/src/block/BaseBanner.php index 64e767897..708254afd 100644 --- a/src/block/BaseBanner.php +++ b/src/block/BaseBanner.php @@ -27,6 +27,7 @@ use pocketmine\block\tile\Banner as TileBanner; use pocketmine\block\utils\BannerPatternLayer; use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\DyeColor; +use pocketmine\block\utils\SupportType; use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\item\Banner as ItemBanner; use pocketmine\item\Item; @@ -107,6 +108,10 @@ abstract class BaseBanner extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($item instanceof ItemBanner){ $this->color = $item->getColor(); diff --git a/src/block/BaseCoral.php b/src/block/BaseCoral.php index 71b1a5880..2fb217e19 100644 --- a/src/block/BaseCoral.php +++ b/src/block/BaseCoral.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\CoralType; use pocketmine\block\utils\CoralTypeTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; abstract class BaseCoral extends Transparent{ @@ -65,4 +66,8 @@ abstract class BaseCoral extends Transparent{ public function isSolid() : bool{ return false; } protected function recalculateCollisionBoxes() : array{ return []; } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/BaseRail.php b/src/block/BaseRail.php index 0344cdba8..0c91f735a 100644 --- a/src/block/BaseRail.php +++ b/src/block/BaseRail.php @@ -38,7 +38,7 @@ use function in_array; abstract class BaseRail extends Flowable{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockReplace->getSide(Facing::DOWN)->isTransparent()){ + if($blockReplace->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){ return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } @@ -220,11 +220,11 @@ abstract class BaseRail extends Flowable{ } public function onNearbyBlockChange() : void{ - if($this->getSide(Facing::DOWN)->isTransparent()){ + if(!$this->getSide(Facing::DOWN)->getSupportType(Facing::UP)->hasEdgeSupport()){ $this->position->getWorld()->useBreakOn($this->position); }else{ foreach($this->getCurrentShapeConnections() as $connection){ - if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && $this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->isTransparent()){ + if(($connection & RailConnectionInfo::FLAG_ASCEND) !== 0 && !$this->getSide($connection & ~RailConnectionInfo::FLAG_ASCEND)->getSupportType(Facing::UP)->hasEdgeSupport()){ $this->position->getWorld()->useBreakOn($this->position); break; } diff --git a/src/block/BaseSign.php b/src/block/BaseSign.php index 42e6bf178..e201a2d72 100644 --- a/src/block/BaseSign.php +++ b/src/block/BaseSign.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Sign as TileSign; use pocketmine\block\utils\SignText; +use pocketmine\block\utils\SupportType; use pocketmine\event\block\SignChangeEvent; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; @@ -77,6 +78,10 @@ abstract class BaseSign extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + abstract protected function getSupportingFace() : int; public function onNearbyBlockChange() : void{ diff --git a/src/block/Bed.php b/src/block/Bed.php index 9a487aa8f..48189b601 100644 --- a/src/block/Bed.php +++ b/src/block/Bed.php @@ -28,6 +28,7 @@ use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\ColoredTrait; use pocketmine\block\utils\DyeColor; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\data\bedrock\DyeColorIdMap; use pocketmine\entity\Entity; use pocketmine\entity\Living; @@ -94,6 +95,10 @@ class Bed extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function isHeadPart() : bool{ return $this->head; } @@ -181,12 +186,11 @@ class Bed extends Transparent{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - $down = $this->getSide(Facing::DOWN); - if(!$down->isTransparent()){ + if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){ $this->facing = $player !== null ? $player->getHorizontalFacing() : Facing::NORTH; $next = $this->getSide($this->getOtherHalfSide()); - if($next->canBeReplaced() && !$next->getSide(Facing::DOWN)->isTransparent()){ + if($next->canBeReplaced() && $this->canBeSupportedBy($next->getSide(Facing::DOWN))){ $nextState = clone $this; $nextState->head = true; $tx->addBlock($blockReplace->position, $this)->addBlock($next->position, $nextState); @@ -216,4 +220,8 @@ class Bed extends Transparent{ return parent::getAffectedBlocks(); } + + private function canBeSupportedBy(Block $block) : bool{ + return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); + } } diff --git a/src/block/Bell.php b/src/block/Bell.php index 7c836ceeb..19a86edef 100644 --- a/src/block/Bell.php +++ b/src/block/Bell.php @@ -28,6 +28,7 @@ use pocketmine\block\utils\BellAttachmentType; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\InvalidBlockStateException; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -101,6 +102,10 @@ final class Bell extends Transparent{ ]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function getAttachmentType() : BellAttachmentType{ return $this->attachmentType; } /** @return $this */ diff --git a/src/block/Block.php b/src/block/Block.php index 76376dde2..c388dd58a 100644 --- a/src/block/Block.php +++ b/src/block/Block.php @@ -29,6 +29,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Spawnable; use pocketmine\block\tile\Tile; use pocketmine\block\utils\InvalidBlockStateException; +use pocketmine\block\utils\SupportType; use pocketmine\entity\Entity; use pocketmine\item\enchantment\VanillaEnchantments; use pocketmine\item\Item; @@ -610,6 +611,10 @@ class Block{ return [AxisAlignedBB::one()]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::FULL(); + } + public function isFullCube() : bool{ $bb = $this->getCollisionBoxes(); diff --git a/src/block/BrewingStand.php b/src/block/BrewingStand.php index fd763a3f0..be1f7858b 100644 --- a/src/block/BrewingStand.php +++ b/src/block/BrewingStand.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\tile\BrewingStand as TileBrewingStand; use pocketmine\block\utils\BrewingStandSlot; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; @@ -83,6 +84,10 @@ class BrewingStand extends Transparent{ ]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function hasSlot(BrewingStandSlot $slot) : bool{ return array_key_exists($slot->id(), $this->slots); } diff --git a/src/block/Button.php b/src/block/Button.php index 9168bbd16..fe85d52f9 100644 --- a/src/block/Button.php +++ b/src/block/Button.php @@ -61,9 +61,11 @@ abstract class Button extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - //TODO: check valid target block - $this->facing = $face; - return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + if($this->canBeSupportedBy($blockClicked, $face)){ + $this->facing = $face; + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } + return false; } abstract protected function getActivationTime() : int; @@ -86,4 +88,14 @@ abstract class Button extends Flowable{ $this->position->getWorld()->addSound($this->position->add(0.5, 0.5, 0.5), new RedstonePowerOffSound()); } } + + public function onNearbyBlockChange() : void{ + if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){ + $this->position->getWorld()->useBreakOn($this->position); + } + } + + private function canBeSupportedBy(Block $support, int $face) : bool{ + return $support->getSupportType($face)->hasCenterSupport(); + } } diff --git a/src/block/Cactus.php b/src/block/Cactus.php index 815d8bcef..5ed929db6 100644 --- a/src/block/Cactus.php +++ b/src/block/Cactus.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\block\utils\SupportType; use pocketmine\entity\Entity; use pocketmine\event\block\BlockGrowEvent; use pocketmine\event\entity\EntityDamageByBlockEvent; @@ -75,6 +76,10 @@ class Cactus extends Transparent{ return [AxisAlignedBB::one()->contract($shrinkSize, 0, $shrinkSize)->trim(Facing::UP, $shrinkSize)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onEntityInside(Entity $entity) : bool{ $ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_CONTACT, 1); $entity->attack($ev); diff --git a/src/block/Cake.php b/src/block/Cake.php index 3ac75147c..ebde23012 100644 --- a/src/block/Cake.php +++ b/src/block/Cake.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\block\utils\SupportType; use pocketmine\entity\effect\EffectInstance; use pocketmine\entity\FoodSource; use pocketmine\entity\Living; @@ -63,6 +64,10 @@ class Cake extends Transparent implements FoodSource{ ]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function getBites() : int{ return $this->bites; } /** @return $this */ diff --git a/src/block/Chest.php b/src/block/Chest.php index c270246e5..a65120d63 100644 --- a/src/block/Chest.php +++ b/src/block/Chest.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\tile\Chest as TileChest; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; +use pocketmine\block\utils\SupportType; use pocketmine\event\block\ChestPairEvent; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; @@ -45,6 +46,10 @@ class Chest extends Transparent{ return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onPostPlace() : void{ $tile = $this->position->getWorld()->getTile($this->position); if($tile instanceof TileChest){ diff --git a/src/block/CocoaBlock.php b/src/block/CocoaBlock.php index c33fcfe7e..89a1e9d6e 100644 --- a/src/block/CocoaBlock.php +++ b/src/block/CocoaBlock.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\block\utils\TreeType; use pocketmine\event\block\BlockGrowEvent; use pocketmine\item\Fertilizer; @@ -83,6 +84,10 @@ class CocoaBlock extends Transparent{ ]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + private function canAttachTo(Block $block) : bool{ return $block instanceof Wood && $block->getTreeType()->equals(TreeType::JUNGLE()); } diff --git a/src/block/Coral.php b/src/block/Coral.php index 7a991492d..424639577 100644 --- a/src/block/Coral.php +++ b/src/block/Coral.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\InvalidBlockStateException; use pocketmine\data\bedrock\CoralTypeIdMap; use pocketmine\item\Item; +use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; @@ -65,7 +66,7 @@ final class Coral extends BaseCoral{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$tx->fetchBlock($blockReplace->getPosition()->down())->isSolid()){ + if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){ return false; } return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); @@ -73,10 +74,14 @@ final class Coral extends BaseCoral{ public function onNearbyBlockChange() : void{ $world = $this->position->getWorld(); - if(!$world->getBlock($this->position->down())->isSolid()){ + if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){ $world->useBreakOn($this->position); }else{ parent::onNearbyBlockChange(); } } + + private function canBeSupportedBy(Block $block) : bool{ + return $block->getSupportType(Facing::UP)->hasCenterSupport(); + } } diff --git a/src/block/DaylightSensor.php b/src/block/DaylightSensor.php index 17103ed47..e51907c41 100644 --- a/src/block/DaylightSensor.php +++ b/src/block/DaylightSensor.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -87,6 +88,10 @@ class DaylightSensor extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::UP, 10 / 16)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $this->inverted = !$this->inverted; $this->signalStrength = $this->recalculateSignalStrength(); diff --git a/src/block/Door.php b/src/block/Door.php index a52e51d9d..164875df3 100644 --- a/src/block/Door.php +++ b/src/block/Door.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\PoweredByRedstoneTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -119,8 +120,12 @@ class Door extends Transparent{ return [AxisAlignedBB::one()->trim($this->open ? Facing::rotateY($this->facing, !$this->hingeRight) : $this->facing, 327 / 400)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onNearbyBlockChange() : void{ - if($this->getSide(Facing::DOWN)->getId() === BlockLegacyIds::AIR){ //Replace with common break method + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN)) && !$this->getSide(Facing::DOWN) instanceof Door){ //Replace with common break method $this->position->getWorld()->useBreakOn($this->position); //this will delete both halves if they exist } } @@ -129,7 +134,7 @@ class Door extends Transparent{ if($face === Facing::UP){ $blockUp = $this->getSide(Facing::UP); $blockDown = $this->getSide(Facing::DOWN); - if(!$blockUp->canBeReplaced() || $blockDown->isTransparent()){ + if(!$blockUp->canBeReplaced() || !$this->canBeSupportedBy($blockDown)){ return false; } @@ -184,4 +189,8 @@ class Door extends Transparent{ } return parent::getAffectedBlocks(); } + + private function canBeSupportedBy(Block $block) : bool{ + return $block->getSupportType(Facing::UP)->hasEdgeSupport(); + } } diff --git a/src/block/DragonEgg.php b/src/block/DragonEgg.php index a2ef58cd4..2db6b7b92 100644 --- a/src/block/DragonEgg.php +++ b/src/block/DragonEgg.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\Fallable; use pocketmine\block\utils\FallableTrait; +use pocketmine\block\utils\SupportType; use pocketmine\event\block\BlockTeleportEvent; use pocketmine\item\Item; use pocketmine\math\Vector3; @@ -82,4 +83,8 @@ class DragonEgg extends Transparent implements Fallable{ } } } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/EnchantingTable.php b/src/block/EnchantingTable.php index b011002cd..b8a6458c2 100644 --- a/src/block/EnchantingTable.php +++ b/src/block/EnchantingTable.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\inventory\EnchantInventory; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -39,6 +40,10 @@ class EnchantingTable extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::UP, 0.25)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ //TODO lock diff --git a/src/block/EnderChest.php b/src/block/EnderChest.php index 6f6acc39a..486ba9a44 100644 --- a/src/block/EnderChest.php +++ b/src/block/EnderChest.php @@ -27,6 +27,7 @@ use pocketmine\block\inventory\EnderChestInventory; use pocketmine\block\tile\EnderChest as TileEnderChest; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -49,6 +50,10 @@ class EnderChest extends Transparent{ return [AxisAlignedBB::one()->contract(0.025, 0, 0.025)->trim(Facing::UP, 0.05)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player instanceof Player){ $enderChest = $this->position->getWorld()->getTile($this->position); diff --git a/src/block/Fence.php b/src/block/Fence.php index cbcdd62e9..b1dff5b44 100644 --- a/src/block/Fence.php +++ b/src/block/Fence.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -93,4 +94,8 @@ class Fence extends Transparent{ return $bbs; } + + public function getSupportType(int $facing) : SupportType{ + return Facing::axis($facing) === Axis::Y ? SupportType::CENTER() : SupportType::NONE(); + } } diff --git a/src/block/FenceGate.php b/src/block/FenceGate.php index 4255ee5ef..9dfe58847 100644 --- a/src/block/FenceGate.php +++ b/src/block/FenceGate.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -78,6 +79,10 @@ class FenceGate extends Transparent{ return $this->open ? [] : [AxisAlignedBB::one()->extend(Facing::UP, 0.5)->squash(Facing::axis($this->facing), 6 / 16)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + private function checkInWall() : bool{ return ( $this->getSide(Facing::rotateY($this->facing, false)) instanceof Wall || diff --git a/src/block/FloorCoralFan.php b/src/block/FloorCoralFan.php index 262925c06..9a36f52c9 100644 --- a/src/block/FloorCoralFan.php +++ b/src/block/FloorCoralFan.php @@ -29,6 +29,7 @@ use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\item\ItemIds; use pocketmine\math\Axis; +use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; use pocketmine\world\BlockTransaction; @@ -93,7 +94,7 @@ final class FloorCoralFan extends BaseCoral{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$tx->fetchBlock($blockReplace->getPosition()->down())->isSolid()){ + if(!$this->canBeSupportedBy($tx->fetchBlock($blockReplace->getPosition()->down()))){ return false; } if($player !== null){ @@ -112,11 +113,15 @@ final class FloorCoralFan extends BaseCoral{ public function onNearbyBlockChange() : void{ $world = $this->position->getWorld(); - if(!$world->getBlock($this->position->down())->isSolid()){ + if(!$this->canBeSupportedBy($world->getBlock($this->position->down()))){ $world->useBreakOn($this->position); }else{ parent::onNearbyBlockChange(); } } + private function canBeSupportedBy(Block $block) : bool{ + return $block->getSupportType(Facing::UP)->hasCenterSupport(); + } + } diff --git a/src/block/Flowable.php b/src/block/Flowable.php index 60f737e1d..b8609b6d0 100644 --- a/src/block/Flowable.php +++ b/src/block/Flowable.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\math\AxisAlignedBB; abstract class Flowable extends Transparent{ @@ -41,4 +42,8 @@ abstract class Flowable extends Transparent{ protected function recalculateCollisionBoxes() : array{ return []; } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/FlowerPot.php b/src/block/FlowerPot.php index bc1ad9296..0c54763af 100644 --- a/src/block/FlowerPot.php +++ b/src/block/FlowerPot.php @@ -104,7 +104,7 @@ class FlowerPot extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($this->getSide(Facing::DOWN)->isTransparent()){ + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ return false; } @@ -112,11 +112,15 @@ class FlowerPot extends Flowable{ } public function onNearbyBlockChange() : void{ - if($this->getSide(Facing::DOWN)->isTransparent()){ + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ $this->position->getWorld()->useBreakOn($this->position); } } + private function canBeSupportedBy(Block $block) : bool{ + return $block->getSupportType(Facing::UP)->hasCenterSupport(); + } + public function onInteract(Item $item, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $plant = $item->getBlock(); if($this->plant !== null){ diff --git a/src/block/Hopper.php b/src/block/Hopper.php index ec8f69014..d8fa67851 100644 --- a/src/block/Hopper.php +++ b/src/block/Hopper.php @@ -27,6 +27,7 @@ use pocketmine\block\tile\Hopper as TileHopper; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\InvalidBlockStateException; use pocketmine\block\utils\PoweredByRedstoneTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -78,6 +79,14 @@ class Hopper extends Transparent{ return $result; } + public function getSupportType(int $facing) : SupportType{ + return match($facing){ + Facing::UP => SupportType::FULL(), + Facing::DOWN => $this->facing === Facing::DOWN ? SupportType::CENTER() : SupportType::NONE(), + default => SupportType::NONE() + }; + } + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $this->facing = $face === Facing::DOWN ? Facing::DOWN : Facing::opposite($face); diff --git a/src/block/Ladder.php b/src/block/Ladder.php index bd4de7e0f..7885bd13c 100644 --- a/src/block/Ladder.php +++ b/src/block/Ladder.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\NormalHorizontalFacingInMetadataTrait; +use pocketmine\block\utils\SupportType; use pocketmine\entity\Entity; use pocketmine\entity\Living; use pocketmine\item\Item; @@ -64,8 +65,12 @@ class Ladder extends Transparent{ return [AxisAlignedBB::one()->trim($this->facing, 13 / 16)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockClicked->isTransparent() && Facing::axis($face) !== Axis::Y){ + if($this->canBeSupportedBy($blockClicked, $face) && Facing::axis($face) !== Axis::Y){ $this->facing = $face; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } @@ -74,8 +79,12 @@ class Ladder extends Transparent{ } public function onNearbyBlockChange() : void{ - if(!$this->getSide(Facing::opposite($this->facing))->isSolid()){ //Replace with common break method + if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($this->facing)), $this->facing)){ //Replace with common break method $this->position->getWorld()->useBreakOn($this->position); } } + + private function canBeSupportedBy(Block $block, int $face) : bool{ + return $block->getSupportType($face)->equals(SupportType::FULL()); + } } diff --git a/src/block/Lantern.php b/src/block/Lantern.php index 516374a4d..c17f1ecc9 100644 --- a/src/block/Lantern.php +++ b/src/block/Lantern.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; @@ -72,22 +73,27 @@ class Lantern extends Transparent{ ]; } - protected function canAttachTo(Block $b) : bool{ - return !$b->isTransparent(); + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->up())) && !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))){ + if(!$this->canBeSupportedBy($blockReplace->getSide(Facing::UP), Facing::DOWN) && !$this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN), Facing::UP)){ return false; } - $this->hanging = ($face === Facing::DOWN || !$this->canAttachTo($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()))); + $this->hanging = ($face === Facing::DOWN || !$this->canBeSupportedBy($this->position->getWorld()->getBlock($blockReplace->getPosition()->down()), Facing::UP)); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } public function onNearbyBlockChange() : void{ - if(!$this->canAttachTo($this->position->getWorld()->getBlock($this->hanging ? $this->position->up() : $this->position->down()))){ + $face = $this->hanging ? Facing::UP : Facing::DOWN; + if(!$this->canBeSupportedBy($this->getSide($face), Facing::opposite($face))){ $this->position->getWorld()->useBreakOn($this->position); } } + + private function canBeSupportedBy(Block $block, int $face) : bool{ + return $block->getSupportType($face)->hasCenterSupport(); + } } diff --git a/src/block/Leaves.php b/src/block/Leaves.php index 777a29926..8d00611c7 100644 --- a/src/block/Leaves.php +++ b/src/block/Leaves.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\block\utils\TreeType; use pocketmine\event\block\LeavesDecayEvent; use pocketmine\item\Item; @@ -166,4 +167,8 @@ class Leaves extends Transparent{ public function getFlammability() : int{ return 60; } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/Lectern.php b/src/block/Lectern.php index d56b73c63..6e3e5bd21 100644 --- a/src/block/Lectern.php +++ b/src/block/Lectern.php @@ -27,6 +27,7 @@ use pocketmine\block\tile\Lectern as TileLectern; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\item\WritableBookBase; use pocketmine\math\AxisAlignedBB; @@ -92,6 +93,10 @@ class Lectern extends Transparent{ return [AxisAlignedBB::one()->trim(Facing::UP, 0.1)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function isProducingSignal() : bool{ return $this->producingSignal; } /** @return $this */ diff --git a/src/block/Lever.php b/src/block/Lever.php index 905ee8756..bfbbd9409 100644 --- a/src/block/Lever.php +++ b/src/block/Lever.php @@ -96,7 +96,7 @@ class Lever extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockClicked->isSolid()){ + if(!$this->canBeSupportedBy($blockClicked, $face)){ return false; } @@ -120,7 +120,8 @@ class Lever extends Flowable{ } public function onNearbyBlockChange() : void{ - if(!$this->getSide(Facing::opposite($this->facing->getFacing()))->isSolid()){ + $facing = $this->facing->getFacing(); + if(!$this->canBeSupportedBy($this->getSide(Facing::opposite($facing)), $facing)){ $this->position->getWorld()->useBreakOn($this->position); } } @@ -135,5 +136,9 @@ class Lever extends Flowable{ return true; } + private function canBeSupportedBy(Block $block, int $face) : bool{ + return $block->getSupportType($face)->hasCenterSupport(); + } + //TODO } diff --git a/src/block/Liquid.php b/src/block/Liquid.php index 3bff3fca7..3e9fb08b4 100644 --- a/src/block/Liquid.php +++ b/src/block/Liquid.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\MinimumCostFlowCalculator; +use pocketmine\block\utils\SupportType; use pocketmine\entity\Entity; use pocketmine\event\block\BlockFormEvent; use pocketmine\event\block\BlockSpreadEvent; @@ -114,6 +115,10 @@ abstract class Liquid extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function getDropsForCompatibleTool(Item $item) : array{ return []; } diff --git a/src/block/MonsterSpawner.php b/src/block/MonsterSpawner.php index 5ecc202b8..218dfcc3e 100644 --- a/src/block/MonsterSpawner.php +++ b/src/block/MonsterSpawner.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use function mt_rand; @@ -39,4 +40,8 @@ class MonsterSpawner extends Transparent{ public function onScheduledUpdate() : void{ //TODO } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/NetherPortal.php b/src/block/NetherPortal.php index 5ba1f0d41..22d3ca1d7 100644 --- a/src/block/NetherPortal.php +++ b/src/block/NetherPortal.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\entity\Entity; use pocketmine\item\Item; use pocketmine\math\Axis; @@ -75,6 +76,10 @@ class NetherPortal extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function getDrops(Item $item) : array{ return []; } diff --git a/src/block/PressurePlate.php b/src/block/PressurePlate.php index b133e3225..172b05b6a 100644 --- a/src/block/PressurePlate.php +++ b/src/block/PressurePlate.php @@ -23,6 +23,13 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; +use pocketmine\item\Item; +use pocketmine\math\Facing; +use pocketmine\math\Vector3; +use pocketmine\player\Player; +use pocketmine\world\BlockTransaction; + abstract class PressurePlate extends Transparent{ public function isSolid() : bool{ @@ -33,5 +40,20 @@ abstract class PressurePlate extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($this->canBeSupportedBy($blockClicked)){ + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } + return false; + } + + private function canBeSupportedBy(Block $block) : bool{ + return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); + } + //TODO } diff --git a/src/block/RedstoneComparator.php b/src/block/RedstoneComparator.php index 95471bd98..311fed636 100644 --- a/src/block/RedstoneComparator.php +++ b/src/block/RedstoneComparator.php @@ -28,6 +28,7 @@ use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\PoweredByRedstoneTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -103,7 +104,7 @@ class RedstoneComparator extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockReplace->getSide(Facing::DOWN)->isTransparent()){ + if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($player !== null){ $this->facing = Facing::opposite($player->getHorizontalFacing()); } @@ -120,10 +121,14 @@ class RedstoneComparator extends Flowable{ } public function onNearbyBlockChange() : void{ - if($this->getSide(Facing::DOWN)->isTransparent()){ + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ $this->position->getWorld()->useBreakOn($this->position); } } + private function canBeSupportedBy(Block $block) : bool{ + return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); + } + //TODO: redstone functionality } diff --git a/src/block/RedstoneRepeater.php b/src/block/RedstoneRepeater.php index 839393248..114823ed7 100644 --- a/src/block/RedstoneRepeater.php +++ b/src/block/RedstoneRepeater.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\PoweredByRedstoneTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -86,7 +87,7 @@ class RedstoneRepeater extends Flowable{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(!$blockReplace->getSide(Facing::DOWN)->isTransparent()){ + if($this->canBeSupportedBy($blockReplace->getSide(Facing::DOWN))){ if($player !== null){ $this->facing = Facing::opposite($player->getHorizontalFacing()); } @@ -106,10 +107,14 @@ class RedstoneRepeater extends Flowable{ } public function onNearbyBlockChange() : void{ - if($this->getSide(Facing::DOWN)->isTransparent()){ + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ $this->position->getWorld()->useBreakOn($this->position); } } + private function canBeSupportedBy(Block $block) : bool{ + return !$block->getSupportType(Facing::UP)->equals(SupportType::NONE()); + } + //TODO: redstone functionality } diff --git a/src/block/RedstoneWire.php b/src/block/RedstoneWire.php index 6c2140406..1c85694df 100644 --- a/src/block/RedstoneWire.php +++ b/src/block/RedstoneWire.php @@ -25,10 +25,22 @@ namespace pocketmine\block; use pocketmine\block\utils\AnalogRedstoneSignalEmitterTrait; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\item\Item; +use pocketmine\math\Facing; +use pocketmine\math\Vector3; +use pocketmine\player\Player; +use pocketmine\world\BlockTransaction; class RedstoneWire extends Flowable{ use AnalogRedstoneSignalEmitterTrait; + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ + if($this->canBeSupportedBy($this->getSide(Facing::DOWN))){ + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } + return false; + } + public function readStateFromData(int $id, int $stateMeta) : void{ $this->signalStrength = BlockDataSerializer::readBoundedInt("signalStrength", $stateMeta, 0, 15); } @@ -45,4 +57,14 @@ class RedstoneWire extends Flowable{ parent::readStateFromWorld(); //TODO: check connections to nearby redstone components } + + public function onNearbyBlockChange() : void{ + if(!$this->canBeSupportedBy($this->getSide(Facing::DOWN))){ + $this->position->getWorld()->useBreakOn($this->position); + } + } + + private function canBeSupportedBy(Block $block) : bool{ + return $block->getSupportType(Facing::UP)->hasCenterSupport(); + } } diff --git a/src/block/SeaPickle.php b/src/block/SeaPickle.php index f32107a80..b01d4d94e 100644 --- a/src/block/SeaPickle.php +++ b/src/block/SeaPickle.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Vector3; @@ -83,6 +84,10 @@ class SeaPickle extends Transparent{ return []; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function canBePlacedAt(Block $blockReplace, Vector3 $clickVector, int $face, bool $isClickedBlock) : bool{ //TODO: proper placement logic (needs a supporting face below) return ($blockReplace instanceof SeaPickle && $blockReplace->count < self::MAX_COUNT) || parent::canBePlacedAt($blockReplace, $clickVector, $face, $isClickedBlock); diff --git a/src/block/Slab.php b/src/block/Slab.php index 1bddeba94..bb38ba6ca 100644 --- a/src/block/Slab.php +++ b/src/block/Slab.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\SlabType; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -125,6 +126,15 @@ class Slab extends Transparent{ return [AxisAlignedBB::one()->trim($this->slabType->equals(SlabType::TOP()) ? Facing::DOWN : Facing::UP, 0.5)]; } + public function getSupportType(int $facing) : SupportType{ + if($this->slabType->equals(SlabType::DOUBLE())){ + return SupportType::FULL(); + }elseif(($facing === Facing::UP && $this->slabType->equals(SlabType::TOP())) || ($facing === Facing::DOWN && $this->slabType->equals(SlabType::BOTTOM()))){ + return SupportType::FULL(); + } + return SupportType::NONE(); + } + public function getDropsForCompatibleTool(Item $item) : array{ return [$this->asItem()->setCount($this->slabType->equals(SlabType::DOUBLE()) ? 2 : 1)]; } diff --git a/src/block/SnowLayer.php b/src/block/SnowLayer.php index be5acb6dc..0a90676b1 100644 --- a/src/block/SnowLayer.php +++ b/src/block/SnowLayer.php @@ -26,6 +26,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\Fallable; use pocketmine\block\utils\FallableTrait; +use pocketmine\block\utils\SupportType; use pocketmine\event\block\BlockMeltEvent; use pocketmine\item\Item; use pocketmine\item\VanillaItems; @@ -80,8 +81,15 @@ class SnowLayer extends Flowable implements Fallable{ return [AxisAlignedBB::one()->trim(Facing::UP, $this->layers >= 4 ? 0.5 : 1)]; } + public function getSupportType(int $facing) : SupportType{ + if(!$this->canBeReplaced()){ + return SupportType::FULL(); + } + return SupportType::NONE(); + } + private function canBeSupportedBy(Block $b) : bool{ - return $b->isSolid() || ($b instanceof SnowLayer && $b->isSameType($this) && $b->layers === self::MAX_LAYERS); + return $b->getSupportType(Facing::UP)->equals(SupportType::FULL()); } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ diff --git a/src/block/Stair.php b/src/block/Stair.php index 39bf4ab3a..437fd8e13 100644 --- a/src/block/Stair.php +++ b/src/block/Stair.php @@ -26,7 +26,9 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; use pocketmine\block\utils\StairShape; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; +use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; use pocketmine\math\Vector3; @@ -111,6 +113,19 @@ class Stair extends Transparent{ return $bbs; } + public function getSupportType(int $facing) : SupportType{ + if( + $facing === Facing::UP && $this->isUpsideDown() || + $facing === Facing::DOWN && !$this->isUpsideDown() || + ($facing === $this->facing && !$this->shape->equals(StairShape::OUTER_LEFT()) && !$this->shape->equals(StairShape::OUTER_RIGHT())) || + ($facing === Facing::rotate($this->facing, Axis::Y, false) && $this->shape->equals(StairShape::INNER_LEFT())) || + ($facing === Facing::rotate($this->facing, Axis::Y, true) && $this->shape->equals(StairShape::INNER_RIGHT())) + ){ + return SupportType::FULL(); + } + return SupportType::NONE(); + } + private function getPossibleCornerFacing(bool $oppositeFacing) : ?int{ $side = $this->getSide($oppositeFacing ? Facing::opposite($this->facing) : $this->facing); return ( diff --git a/src/block/Stonecutter.php b/src/block/Stonecutter.php index 8a66ddc4a..d37950e4f 100644 --- a/src/block/Stonecutter.php +++ b/src/block/Stonecutter.php @@ -27,6 +27,7 @@ use pocketmine\block\inventory\StonecutterInventory; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\FacesOppositePlacingPlayerTrait; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -59,4 +60,8 @@ class Stonecutter extends Transparent{ protected function recalculateCollisionBoxes() : array{ return [AxisAlignedBB::one()->trim(Facing::UP, 7 / 16)]; } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/Thin.php b/src/block/Thin.php index 567e4e86c..ba2fb0bd9 100644 --- a/src/block/Thin.php +++ b/src/block/Thin.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -82,4 +83,8 @@ class Thin extends Transparent{ return $bbs; } + + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } } diff --git a/src/block/Torch.php b/src/block/Torch.php index cb5bf8fb8..03827df1d 100644 --- a/src/block/Torch.php +++ b/src/block/Torch.php @@ -24,7 +24,9 @@ declare(strict_types=1); namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; +use pocketmine\math\Axis; use pocketmine\math\Facing; use pocketmine\math\Vector3; use pocketmine\player\Player; @@ -66,16 +68,16 @@ class Torch extends Flowable{ $below = $this->getSide(Facing::DOWN); $face = Facing::opposite($this->facing); - if($this->getSide($face)->isTransparent() && !($face === Facing::DOWN && ($below->getId() === BlockLegacyIds::FENCE || $below->getId() === BlockLegacyIds::COBBLESTONE_WALL))){ + if(!$this->canBeSupportedBy($this->getSide($face), $this->facing)){ $this->position->getWorld()->useBreakOn($this->position); } } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if($blockClicked->canBeReplaced() && !$blockClicked->getSide(Facing::DOWN)->isTransparent()){ + if($blockClicked->canBeReplaced() && $this->canBeSupportedBy($blockClicked->getSide(Facing::DOWN), Facing::UP)){ $this->facing = Facing::UP; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); - }elseif($face !== Facing::DOWN && (!$blockClicked->isTransparent() || ($face === Facing::UP && ($blockClicked->getId() === BlockLegacyIds::FENCE || $blockClicked->getId() === BlockLegacyIds::COBBLESTONE_WALL)))){ + }elseif($face !== Facing::DOWN && $this->canBeSupportedBy($blockClicked, $face)){ $this->facing = $face; return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); }else{ @@ -87,7 +89,7 @@ class Torch extends Flowable{ Facing::DOWN ] as $side){ $block = $this->getSide($side); - if(!$block->isTransparent()){ + if($this->canBeSupportedBy($block, Facing::opposite($side))){ $this->facing = Facing::opposite($side); return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } @@ -95,4 +97,9 @@ class Torch extends Flowable{ } return false; } + + private function canBeSupportedBy(Block $support, int $face) : bool{ + return ($face === Facing::UP && $support->getSupportType($face)->hasCenterSupport()) || + (Facing::axis($face) !== Axis::Y && $support->getSupportType($face)->equals(SupportType::FULL())); + } } diff --git a/src/block/Trapdoor.php b/src/block/Trapdoor.php index 08cb4b200..64f92b62e 100644 --- a/src/block/Trapdoor.php +++ b/src/block/Trapdoor.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\BlockDataSerializer; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -78,6 +79,10 @@ class Trapdoor extends Transparent{ return [AxisAlignedBB::one()->trim($this->open ? $this->facing : ($this->top ? Facing::DOWN : Facing::UP), 13 / 16)]; } + public function getSupportType(int $facing) : SupportType{ + return SupportType::NONE(); + } + public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ if($player !== null){ $this->facing = Facing::opposite($player->getHorizontalFacing()); diff --git a/src/block/Wall.php b/src/block/Wall.php index 6c827d190..0ce74d0b0 100644 --- a/src/block/Wall.php +++ b/src/block/Wall.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\block; +use pocketmine\block\utils\SupportType; +use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; use pocketmine\math\Facing; @@ -76,4 +78,8 @@ class Wall extends Transparent{ ->trim(Facing::EAST, $east ? 0 : $inset) ]; } + + public function getSupportType(int $facing) : SupportType{ + return Facing::axis($facing) === Axis::Y ? SupportType::CENTER() : SupportType::NONE(); + } } diff --git a/src/block/WallCoralFan.php b/src/block/WallCoralFan.php index f9462f582..ac158453f 100644 --- a/src/block/WallCoralFan.php +++ b/src/block/WallCoralFan.php @@ -113,7 +113,7 @@ final class WallCoralFan extends BaseCoral{ public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ $axis = Facing::axis($face); - if(($axis !== Axis::X && $axis !== Axis::Z) || !$blockClicked->isSolid()){ + if(($axis !== Axis::X && $axis !== Axis::Z) || !$this->canBeSupportedBy($blockClicked, $face)){ return false; } $this->facing = $face; @@ -122,10 +122,14 @@ final class WallCoralFan extends BaseCoral{ public function onNearbyBlockChange() : void{ $world = $this->position->getWorld(); - if(!$world->getBlock($this->position->getSide(Facing::opposite($this->facing)))->isSolid()){ + if(!$this->canBeSupportedBy($world->getBlock($this->position->getSide(Facing::opposite($this->facing))), $this->facing)){ $world->useBreakOn($this->position); }else{ parent::onNearbyBlockChange(); } } + + private function canBeSupportedBy(Block $block, int $face) : bool{ + return $block->getSupportType($face)->hasCenterSupport(); + } } diff --git a/src/block/utils/SupportType.php b/src/block/utils/SupportType.php new file mode 100644 index 000000000..d01646b55 --- /dev/null +++ b/src/block/utils/SupportType.php @@ -0,0 +1,58 @@ +equals(self::EDGE()) || $this->equals(self::FULL()); + } + + public function hasCenterSupport() : bool{ + return $this->equals(self::CENTER()) || $this->equals(self::FULL()); + } +} diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 67fa6bd2e..40d68e83d 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -335,6 +335,21 @@ parameters: count: 3 path: ../../../src/block/Mycelium.php + - + message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/RedMushroom.php + + - + message: "#^Parameter \\#2 \\$y of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/RedMushroom.php + + - + message: "#^Parameter \\#3 \\$z of method pocketmine\\\\world\\\\World\\:\\:getFullLightAt\\(\\) expects int, float\\|int given\\.$#" + count: 1 + path: ../../../src/block/RedMushroom.php + - message: "#^Parameter \\#1 \\$x of method pocketmine\\\\world\\\\World\\:\\:getBlockLightAt\\(\\) expects int, float\\|int given\\.$#" count: 1