mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-08-29 14:35:09 +00:00
Merge 'minor-next' into 'major-next'
Automatic merge performed by: https://github.com/pmmp/RestrictedActions/actions/runs/17223908234
This commit is contained in:
commit
24795eef0e
@ -61,7 +61,12 @@ abstract class BaseBanner extends Transparent implements Colored{
|
||||
return $this;
|
||||
}
|
||||
|
||||
abstract protected function getOminousVersion() : Block;
|
||||
/**
|
||||
* TODO: make this abstract in PM6 (BC break)
|
||||
*/
|
||||
protected function getOminousVersion() : Block{
|
||||
return VanillaBlocks::AIR();
|
||||
}
|
||||
|
||||
public function writeStateToWorld() : void{
|
||||
parent::writeStateToWorld();
|
||||
|
@ -103,27 +103,10 @@ abstract class BaseSign extends Transparent implements WoodMaterial{
|
||||
return SupportType::NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
abstract protected function getSupportingFace() : int;
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
protected function getSupportingFaceOptions() : array{
|
||||
return [$this->getSupportingFace()];
|
||||
}
|
||||
|
||||
public function onNearbyBlockChange() : void{
|
||||
$foundSupport = false;
|
||||
foreach($this->getSupportingFaceOptions() as $face){
|
||||
if($this->getSide($face)->getTypeId() !== BlockTypeIds::AIR){
|
||||
$foundSupport = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!$foundSupport){
|
||||
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
|
||||
$this->position->getWorld()->useBreakOn($this->position);
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,10 @@ 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;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
@ -39,25 +41,41 @@ final class WallHangingSign extends BaseSign implements HorizontalFacing{
|
||||
return Facing::rotateY($this->facing, clockwise: true);
|
||||
}
|
||||
|
||||
protected function getSupportingFaceOptions() : array{
|
||||
//wall hanging signs can be supported from either end of the post
|
||||
return [
|
||||
Facing::rotateY($this->facing, clockwise: true),
|
||||
Facing::rotateY($this->facing, clockwise: false)
|
||||
];
|
||||
public function onNearbyBlockChange() : void{
|
||||
//NOOP - disable default self-destruct behaviour
|
||||
}
|
||||
|
||||
protected function recalculateCollisionBoxes() : array{
|
||||
//only the cross bar is collidable
|
||||
return [AxisAlignedBB::one()->trim(Facing::DOWN, 7 / 8)->squash(Facing::axis($this->facing), 3 / 4)];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ use pocketmine\utils\Binary;
|
||||
use pocketmine\world\World;
|
||||
use function implode;
|
||||
use function mb_scrub;
|
||||
use function rtrim;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
@ -106,7 +107,7 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function writeSaveData(CompoundTag $nbt) : void{
|
||||
$nbt->setTag(self::TAG_FRONT_TEXT, CompoundTag::create()
|
||||
->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()))
|
||||
->setString(self::TAG_TEXT_BLOB, rtrim(implode("\n", $this->text->getLines()), "\n"))
|
||||
->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()))
|
||||
->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0)
|
||||
->setByte(self::TAG_PERSIST_FORMATTING, 1)
|
||||
@ -151,7 +152,7 @@ class Sign extends Spawnable{
|
||||
|
||||
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
|
||||
$nbt->setTag(self::TAG_FRONT_TEXT, CompoundTag::create()
|
||||
->setString(self::TAG_TEXT_BLOB, implode("\n", $this->text->getLines()))
|
||||
->setString(self::TAG_TEXT_BLOB, rtrim(implode("\n", $this->text->getLines()), "\n"))
|
||||
->setInt(self::TAG_TEXT_COLOR, Binary::signInt($this->text->getBaseColor()->toARGB()))
|
||||
->setByte(self::TAG_GLOWING_TEXT, $this->text->isGlowing() ? 1 : 0)
|
||||
->setByte(self::TAG_PERSIST_FORMATTING, 1) //TODO: not sure what this is used for
|
||||
|
@ -24,9 +24,10 @@ declare(strict_types=1);
|
||||
namespace pocketmine\item;
|
||||
|
||||
use pocketmine\block\Block;
|
||||
use pocketmine\block\utils\SupportType;
|
||||
use pocketmine\math\Facing;
|
||||
use pocketmine\math\Vector3;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
|
||||
final class HangingSign extends Item{
|
||||
|
||||
@ -40,14 +41,15 @@ final class HangingSign extends Item{
|
||||
parent::__construct($identifier, $name);
|
||||
}
|
||||
|
||||
public function getPlacementBlock(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;
|
||||
return clone $result;
|
||||
public function getPlacementTransaction(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : ?BlockTransaction{
|
||||
if($face !== Facing::DOWN){
|
||||
return $this->tryPlacementTransaction(clone $this->wallVariant, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
//ceiling edges sign has stricter placement conditions than ceiling center sign, so try that first
|
||||
$ceilingEdgeTx = $player === null || !$player->isSneaking() ?
|
||||
$this->tryPlacementTransaction(clone $this->edgePointCeilingVariant, $blockReplace, $blockClicked, $face, $clickVector, $player) :
|
||||
null;
|
||||
return $ceilingEdgeTx ?? $this->tryPlacementTransaction(clone $this->centerPointCeilingVariant, $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
public function getBlock(?int $clickedFace = null) : Block{
|
||||
|
@ -48,6 +48,7 @@ use pocketmine\nbt\tag\StringTag;
|
||||
use pocketmine\nbt\TreeRoot;
|
||||
use pocketmine\player\Player;
|
||||
use pocketmine\utils\Utils;
|
||||
use pocketmine\world\BlockTransaction;
|
||||
use pocketmine\world\format\io\GlobalItemDataHandlers;
|
||||
use function base64_decode;
|
||||
use function base64_encode;
|
||||
@ -488,8 +489,18 @@ class Item implements \JsonSerializable{
|
||||
return $this->getBlock()->canBePlaced();
|
||||
}
|
||||
|
||||
public function getPlacementBlock(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{
|
||||
return $this->getBlock($face);
|
||||
protected final function tryPlacementTransaction(Block $blockPlace, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player) : ?BlockTransaction{
|
||||
$position = $blockReplace->getPosition();
|
||||
$blockPlace->position($position->getWorld(), $position->getFloorX(), $position->getFloorY(), $position->getFloorZ());
|
||||
if(!$blockPlace->canBePlacedAt($blockReplace, $clickVector, $face, $blockReplace->getPosition()->equals($blockClicked->getPosition()))){
|
||||
return null;
|
||||
}
|
||||
$transaction = new BlockTransaction($position->getWorld());
|
||||
return $blockPlace->place($transaction, $this, $blockReplace, $blockClicked, $face, $clickVector, $player) ? $transaction : null;
|
||||
}
|
||||
|
||||
public function getPlacementTransaction(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : ?BlockTransaction{
|
||||
return $this->tryPlacementTransaction($this->getBlock($face), $blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2279,22 +2279,15 @@ class World implements ChunkManager{
|
||||
if($item->isNull() || !$item->canBePlaced()){
|
||||
return false;
|
||||
}
|
||||
$hand = $item->getPlacementBlock($blockReplace, $blockClicked, $face, $clickVector);
|
||||
$hand->position($this, $blockReplace->getPosition()->x, $blockReplace->getPosition()->y, $blockReplace->getPosition()->z);
|
||||
|
||||
if($hand->canBePlacedAt($blockClicked, $clickVector, $face, true)){
|
||||
$blockReplace = $blockClicked;
|
||||
//TODO: while this mimics the vanilla behaviour with replaceable blocks, we should really pass some other
|
||||
//value like NULL and let place() deal with it. This will look like a bug to anyone who doesn't know about
|
||||
//the vanilla behaviour.
|
||||
$face = Facing::UP;
|
||||
$hand->position($this, $blockReplace->getPosition()->x, $blockReplace->getPosition()->y, $blockReplace->getPosition()->z);
|
||||
}elseif(!$hand->canBePlacedAt($blockReplace, $clickVector, $face, false)){
|
||||
return false;
|
||||
}
|
||||
|
||||
$tx = new BlockTransaction($this);
|
||||
if(!$hand->place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player)){
|
||||
//TODO: while passing Facing::UP mimics the vanilla behaviour with replaceable blocks, we should really pass
|
||||
//some other value like NULL and let place() deal with it. This will look like a bug to anyone who doesn't know
|
||||
//about the vanilla behaviour.
|
||||
$tx =
|
||||
$item->getPlacementTransaction($blockClicked, $blockClicked, Facing::UP, $clickVector, $player) ??
|
||||
$item->getPlacementTransaction($blockReplace, $blockClicked, $face, $clickVector, $player);
|
||||
if($tx === null){
|
||||
//no placement options available
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2338,6 +2331,7 @@ class World implements ChunkManager{
|
||||
if(!$tx->apply()){
|
||||
return false;
|
||||
}
|
||||
$first = true;
|
||||
foreach($tx->getBlocks() as [$x, $y, $z, $_]){
|
||||
$tile = $this->getTileAt($x, $y, $z);
|
||||
if($tile !== null){
|
||||
@ -2345,11 +2339,12 @@ class World implements ChunkManager{
|
||||
$tile->copyDataFromItem($item);
|
||||
}
|
||||
|
||||
$this->getBlockAt($x, $y, $z)->onPostPlace();
|
||||
$placed = $this->getBlockAt($x, $y, $z);
|
||||
$placed->onPostPlace();
|
||||
if($first && $playSound){
|
||||
$this->addSound($placed->getPosition(), new BlockPlaceSound($placed));
|
||||
}
|
||||
|
||||
if($playSound){
|
||||
$this->addSound($hand->getPosition(), new BlockPlaceSound($hand));
|
||||
$first = false;
|
||||
}
|
||||
|
||||
$item->pop();
|
||||
|
Loading…
x
Reference in New Issue
Block a user