From db54c481aa5248a01ae59435cf3a7d954f3e28f8 Mon Sep 17 00:00:00 2001 From: ipad54 <63200545+ipad54@users.noreply.github.com> Date: Tue, 26 Aug 2025 01:27:17 +0300 Subject: [PATCH] Fixed hanging signs placement criteria (#6775) --- src/block/BlockTypeTags.php | 1 + src/block/CeilingCenterHangingSign.php | 9 ++++++++ src/block/CeilingEdgesHangingSign.php | 17 +++++++++++++++ src/block/VanillaBlocks.php | 7 ++++--- src/block/WallHangingSign.php | 22 ++++++++++++++++--- src/item/HangingSign.php | 29 ++++++++++++++++++++------ src/item/Item.php | 2 +- src/world/World.php | 2 +- 8 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/block/BlockTypeTags.php b/src/block/BlockTypeTags.php index 19a4825d9..531f3bcb3 100644 --- a/src/block/BlockTypeTags.php +++ b/src/block/BlockTypeTags.php @@ -31,4 +31,5 @@ final class BlockTypeTags{ public const SAND = self::PREFIX . "sand"; public const POTTABLE_PLANTS = self::PREFIX . "pottable"; public const FIRE = self::PREFIX . "fire"; + public const HANGING_SIGN = self::PREFIX . "hanging_sign"; } diff --git a/src/block/CeilingCenterHangingSign.php b/src/block/CeilingCenterHangingSign.php index 7078f38d8..1125de553 100644 --- a/src/block/CeilingCenterHangingSign.php +++ b/src/block/CeilingCenterHangingSign.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\SignLikeRotation; use pocketmine\block\utils\SignLikeRotationTrait; +use pocketmine\block\utils\StaticSupportTrait; use pocketmine\item\Item; use pocketmine\math\Facing; use pocketmine\math\Vector3; @@ -33,6 +34,7 @@ use pocketmine\world\BlockTransaction; final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotation{ use SignLikeRotationTrait; + use StaticSupportTrait; protected function getSupportingFace() : int{ return Facing::UP; @@ -49,4 +51,11 @@ final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotatio } return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } + + private function canBeSupportedAt(Block $block) : bool{ + $supportBlock = $block->getSide(Facing::UP); + return + $supportBlock->getSupportType(Facing::DOWN)->hasCenterSupport() || + $supportBlock->hasTypeTag(BlockTypeTags::HANGING_SIGN); + } } diff --git a/src/block/CeilingEdgesHangingSign.php b/src/block/CeilingEdgesHangingSign.php index 5dafe6932..3f7b6489b 100644 --- a/src/block/CeilingEdgesHangingSign.php +++ b/src/block/CeilingEdgesHangingSign.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\HorizontalFacing; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\Facing; use pocketmine\math\Vector3; @@ -45,7 +46,23 @@ final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing if($player !== null){ $this->facing = Facing::opposite($player->getHorizontalFacing()); } + if(!$this->canBeSupportedAt($blockReplace)){ + return false; + } return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } + + public function onNearbyBlockChange() : void{ + if(!$this->canBeSupportedAt($this)){ + $this->position->getWorld()->useBreakOn($this->position); + } + } + + private function canBeSupportedAt(Block $block) : bool{ + $supportBlock = $block->getSide(Facing::UP); + return + $supportBlock->getSupportType(Facing::DOWN) === SupportType::FULL || + (($supportBlock instanceof WallHangingSign || $supportBlock instanceof CeilingEdgesHangingSign) && Facing::axis($supportBlock->getFacing()) === Facing::axis($this->facing)); + } } diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index e3b7a5f06..36074c606 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -1391,6 +1391,7 @@ final class VanillaBlocks{ private static function registerWoodenBlocks() : void{ $planksBreakInfo = new Info(BreakInfo::axe(2.0, null, 15.0)); $signBreakInfo = new Info(BreakInfo::axe(1.0)); + $hangingSignBreakInfo = new Info(BreakInfo::axe(1.0), [Tags::HANGING_SIGN]); $logBreakInfo = new Info(BreakInfo::axe(2.0)); $woodenDoorBreakInfo = new Info(BreakInfo::axe(3.0, null, 15.0)); $woodenButtonBreakInfo = new Info(BreakInfo::axe(0.5)); @@ -1444,9 +1445,9 @@ final class VanillaBlocks{ WoodType::CHERRY => VanillaItems::CHERRY_HANGING_SIGN(...), WoodType::PALE_OAK => VanillaItems::PALE_OAK_HANGING_SIGN(...), }; - self::register($idName("ceiling_center_hanging_sign"), fn(BID $id) => new CeilingCenterHangingSign($id, $name . " Center Hanging Sign", $signBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); - self::register($idName("ceiling_edges_hanging_sign"), fn(BID $id) => new CeilingEdgesHangingSign($id, $name . " Edges Hanging Sign", $signBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); - self::register($idName("wall_hanging_sign"), fn(BID $id) => new WallHangingSign($id, $name . " Wall Hanging Sign", $signBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); + self::register($idName("ceiling_center_hanging_sign"), fn(BID $id) => new CeilingCenterHangingSign($id, $name . " Center Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); + self::register($idName("ceiling_edges_hanging_sign"), fn(BID $id) => new CeilingEdgesHangingSign($id, $name . " Edges Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); + self::register($idName("wall_hanging_sign"), fn(BID $id) => new WallHangingSign($id, $name . " Wall Hanging Sign", $hangingSignBreakInfo, $woodType, $hangingSignAsItem), TileHangingSign::class); } } diff --git a/src/block/WallHangingSign.php b/src/block/WallHangingSign.php index 2332f8e4f..df959c720 100644 --- a/src/block/WallHangingSign.php +++ b/src/block/WallHangingSign.php @@ -25,6 +25,7 @@ namespace pocketmine\block; use pocketmine\block\utils\HorizontalFacing; use pocketmine\block\utils\HorizontalFacingTrait; +use pocketmine\block\utils\SupportType; use pocketmine\item\Item; use pocketmine\math\Axis; use pocketmine\math\AxisAlignedBB; @@ -50,16 +51,31 @@ final class WallHangingSign extends BaseSign implements HorizontalFacing{ } public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{ - if(Facing::axis($face) === Axis::Y){ + if($player === null){ + return false; + } + $attachFace = Facing::axis($face) === Axis::Y ? Facing::rotateY($player->getHorizontalFacing(), clockwise: true) : $face; + + if($this->canBeSupportedAt($blockReplace->getSide($attachFace), $attachFace)){ + $direction = $attachFace; + }elseif($this->canBeSupportedAt($blockReplace->getSide($opposite = Facing::opposite($attachFace)), $opposite)){ + $direction = $opposite; + }else{ return false; } - $this->facing = Facing::rotateY($face, clockwise: true); + $this->facing = Facing::rotateY(Facing::opposite($direction), clockwise: true); //the front should always face the player if possible - if($player !== null && $this->facing === $player->getHorizontalFacing()){ + if($this->facing === $player->getHorizontalFacing()){ $this->facing = Facing::opposite($this->facing); } return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); } + + private function canBeSupportedAt(Block $block, int $face) : bool{ + return + ($block instanceof WallHangingSign && Facing::axis(Facing::rotateY($block->getFacing(), clockwise: true)) === Facing::axis($face)) || + $block->getSupportType(Facing::opposite($face)) === SupportType::FULL; + } } diff --git a/src/item/HangingSign.php b/src/item/HangingSign.php index 7143637ba..5e3bd068a 100644 --- a/src/item/HangingSign.php +++ b/src/item/HangingSign.php @@ -24,9 +24,13 @@ declare(strict_types=1); namespace pocketmine\item; use pocketmine\block\Block; +use pocketmine\block\CeilingCenterHangingSign; +use pocketmine\block\CeilingEdgesHangingSign; use pocketmine\block\utils\SupportType; +use pocketmine\block\WallHangingSign; use pocketmine\math\Facing; use pocketmine\math\Vector3; +use pocketmine\player\Player; final class HangingSign extends Item{ @@ -40,13 +44,26 @@ final class HangingSign extends Item{ parent::__construct($identifier, $name); } - public function getPlacementBlock(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{ + public function getPlacementBlock(?Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{ //we don't verify valid placement conditions here, only decide which block to return - $result = $face === Facing::DOWN ? - $blockReplace->getSide(Facing::UP)->getSupportType(Facing::DOWN) === SupportType::CENTER ? - $this->centerPointCeilingVariant : - $this->edgePointCeilingVariant - : $this->wallVariant; + if($face === Facing::DOWN){ + if($player !== null && $player->isSneaking()){ + return clone $this->centerPointCeilingVariant; + } + + //we select the center variant when support is edge/wall sign with perpendicular player facing, + //support is a center sign itself, or support provides center support. + //otherwise use the edge variant. + $support = $blockReplace->getSide(Facing::UP); + $result = + (($support instanceof CeilingEdgesHangingSign || $support instanceof WallHangingSign) && ($player === null || Facing::axis($player->getHorizontalFacing()) !== Facing::axis($support->getFacing()))) || + $support instanceof CeilingCenterHangingSign || + $support->getSupportType(Facing::DOWN) === SupportType::CENTER ? + $this->centerPointCeilingVariant : + $this->edgePointCeilingVariant; + }else{ + $result = $this->wallVariant; + } return clone $result; } diff --git a/src/item/Item.php b/src/item/Item.php index 6786238b0..c286a2bff 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -485,7 +485,7 @@ class Item implements \JsonSerializable{ return $this->getBlock()->canBePlaced(); } - public function getPlacementBlock(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{ + public function getPlacementBlock(?Player $player, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{ return $this->getBlock($face); } diff --git a/src/world/World.php b/src/world/World.php index 4f2e222ca..bd79ae083 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -2298,7 +2298,7 @@ class World implements ChunkManager{ if($item->isNull() || !$item->canBePlaced()){ return false; } - $hand = $item->getPlacementBlock($blockReplace, $blockClicked, $face, $clickVector); + $hand = $item->getPlacementBlock($player, $blockReplace, $blockClicked, $face, $clickVector); $hand->position($this, $blockReplace->getPosition()->x, $blockReplace->getPosition()->y, $blockReplace->getPosition()->z); if($hand->canBePlacedAt($blockClicked, $clickVector, $face, true)){