Merge remote-tracking branch 'origin/minor-next' into major-next

This commit is contained in:
Dylan K. Taylor 2025-08-24 23:18:21 +01:00
commit e8eda19ae5
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
57 changed files with 4984 additions and 3636 deletions

View File

@ -50,6 +50,10 @@ abstract class BaseBanner extends Transparent implements Colored{
parent::readStateFromWorld();
$tile = $this->position->getWorld()->getTile($this->position);
if($tile instanceof TileBanner){
if($tile->getType() === TileBanner::TYPE_OMINOUS){
//illager banner is implemented as a separate block, as it doesn't support base color or custom patterns
return $this->getOminousVersion();
}
$this->color = $tile->getBaseColor();
$this->setPatterns($tile->getPatterns());
}
@ -57,6 +61,8 @@ abstract class BaseBanner extends Transparent implements Colored{
return $this;
}
abstract protected function getOminousVersion() : Block;
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);

View File

@ -0,0 +1,90 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SupportType;
use pocketmine\item\Item;
use pocketmine\item\VanillaItems;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
use function assert;
abstract class BaseOminousBanner extends Transparent{
public function writeStateToWorld() : void{
parent::writeStateToWorld();
$tile = $this->position->getWorld()->getTile($this->position);
assert($tile instanceof TileBanner);
$tile->setBaseColor(DyeColor::WHITE);
$tile->setPatterns([]);
$tile->setType(TileBanner::TYPE_OMINOUS);
}
public function isSolid() : bool{
return false;
}
public function getMaxStackSize() : int{
return 16;
}
public function getFuelTime() : int{
return 300;
}
protected function recalculateCollisionBoxes() : array{
return [];
}
public function getSupportType(int $facing) : SupportType{
return SupportType::NONE;
}
private function canBeSupportedBy(Block $block) : bool{
return $block->isSolid();
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(!$this->canBeSupportedBy($blockReplace->getSide($this->getSupportingFace()))){
return false;
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
abstract protected function getSupportingFace() : int;
public function onNearbyBlockChange() : void{
if(!$this->canBeSupportedBy($this->getSide($this->getSupportingFace()))){
$this->position->getWorld()->useBreakOn($this->position);
}
}
public function asItem() : Item{
return VanillaItems::OMINOUS_BANNER();
}
}

View File

@ -103,10 +103,27 @@ 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{
if($this->getSide($this->getSupportingFace())->getTypeId() === BlockTypeIds::AIR){
$foundSupport = false;
foreach($this->getSupportingFaceOptions() as $face){
if($this->getSide($face)->getTypeId() !== BlockTypeIds::AIR){
$foundSupport = true;
break;
}
}
if(!$foundSupport){
$this->position->getWorld()->useBreakOn($this->position);
}
}

View File

@ -787,8 +787,43 @@ final class BlockTypeIds{
public const RESIN_CLUMP = 10757;
public const CHISELED_RESIN_BRICKS = 10758;
public const RESPAWN_ANCHOR = 10759;
public const OMINOUS_BANNER = 10760;
public const OMINOUS_WALL_BANNER = 10761;
public const ACACIA_CEILING_CENTER_HANGING_SIGN = 10762;
public const ACACIA_CEILING_EDGES_HANGING_SIGN = 10763;
public const ACACIA_WALL_HANGING_SIGN = 10764;
public const BIRCH_CEILING_CENTER_HANGING_SIGN = 10765;
public const BIRCH_CEILING_EDGES_HANGING_SIGN = 10766;
public const BIRCH_WALL_HANGING_SIGN = 10767;
public const CHERRY_CEILING_CENTER_HANGING_SIGN = 10768;
public const CHERRY_CEILING_EDGES_HANGING_SIGN = 10769;
public const CHERRY_WALL_HANGING_SIGN = 10770;
public const CRIMSON_CEILING_CENTER_HANGING_SIGN = 10771;
public const CRIMSON_CEILING_EDGES_HANGING_SIGN = 10772;
public const CRIMSON_WALL_HANGING_SIGN = 10773;
public const DARK_OAK_CEILING_CENTER_HANGING_SIGN = 10774;
public const DARK_OAK_CEILING_EDGES_HANGING_SIGN = 10775;
public const DARK_OAK_WALL_HANGING_SIGN = 10776;
public const JUNGLE_CEILING_CENTER_HANGING_SIGN = 10777;
public const JUNGLE_CEILING_EDGES_HANGING_SIGN = 10778;
public const JUNGLE_WALL_HANGING_SIGN = 10779;
public const MANGROVE_CEILING_CENTER_HANGING_SIGN = 10780;
public const MANGROVE_CEILING_EDGES_HANGING_SIGN = 10781;
public const MANGROVE_WALL_HANGING_SIGN = 10782;
public const OAK_CEILING_CENTER_HANGING_SIGN = 10783;
public const OAK_CEILING_EDGES_HANGING_SIGN = 10784;
public const OAK_WALL_HANGING_SIGN = 10785;
public const PALE_OAK_CEILING_CENTER_HANGING_SIGN = 10786;
public const PALE_OAK_CEILING_EDGES_HANGING_SIGN = 10787;
public const PALE_OAK_WALL_HANGING_SIGN = 10788;
public const SPRUCE_CEILING_CENTER_HANGING_SIGN = 10789;
public const SPRUCE_CEILING_EDGES_HANGING_SIGN = 10790;
public const SPRUCE_WALL_HANGING_SIGN = 10791;
public const WARPED_CEILING_CENTER_HANGING_SIGN = 10792;
public const WARPED_CEILING_EDGES_HANGING_SIGN = 10793;
public const WARPED_WALL_HANGING_SIGN = 10794;
public const FIRST_UNUSED_BLOCK_ID = 10760;
public const FIRST_UNUSED_BLOCK_ID = 10795;
private static int $nextDynamicId = self::FIRST_UNUSED_BLOCK_ID;

View File

@ -0,0 +1,52 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingCenterHangingSign extends BaseSign implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getSupportingFace() : int{
return Facing::UP;
}
//TODO: duplicated code :(
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -0,0 +1,51 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class CeilingEdgesHangingSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
return Facing::UP;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::DOWN){
return false;
}
if($player !== null){
$this->facing = Facing::opposite($player->getHorizontalFacing());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -34,6 +34,10 @@ use pocketmine\world\BlockTransaction;
final class FloorBanner extends BaseBanner implements SignLikeRotation{
use SignLikeRotationTrait;
protected function getOminousVersion() : Block{
return VanillaBlocks::OMINOUS_BANNER()->setRotation($this->rotation);
}
protected function getSupportingFace() : int{
return Facing::DOWN;
}

View File

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SignLikeRotationTrait;
use pocketmine\item\Item;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class OminousFloorBanner extends BaseOminousBanner implements SignLikeRotation{
use SignLikeRotationTrait;
//TODO: duplicated code :(
protected function getSupportingFace() : int{
return Facing::DOWN;
}
public function place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if($face !== Facing::UP){
return false;
}
if($player !== null){
$this->rotation = self::getRotationFromYaw($player->getLocation()->getYaw());
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -0,0 +1,49 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class OminousWallBanner extends BaseOminousBanner implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
return Facing::opposite($this->facing);
}
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){
return false;
}
$this->facing = $face;
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -45,6 +45,7 @@ use pocketmine\block\tile\EnchantTable as TileEnchantingTable;
use pocketmine\block\tile\EnderChest as TileEnderChest;
use pocketmine\block\tile\FlowerPot as TileFlowerPot;
use pocketmine\block\tile\GlowingItemFrame as TileGlowingItemFrame;
use pocketmine\block\tile\HangingSign as TileHangingSign;
use pocketmine\block\tile\Hopper as TileHopper;
use pocketmine\block\tile\ItemFrame as TileItemFrame;
use pocketmine\block\tile\Jukebox as TileJukebox;
@ -80,6 +81,8 @@ use function strtolower;
* @generate-registry-docblock
*
* @method static WoodenButton ACACIA_BUTTON()
* @method static CeilingCenterHangingSign ACACIA_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign ACACIA_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor ACACIA_DOOR()
* @method static WoodenFence ACACIA_FENCE()
* @method static FenceGate ACACIA_FENCE_GATE()
@ -92,6 +95,7 @@ use function strtolower;
* @method static WoodenSlab ACACIA_SLAB()
* @method static WoodenStairs ACACIA_STAIRS()
* @method static WoodenTrapdoor ACACIA_TRAPDOOR()
* @method static WallHangingSign ACACIA_WALL_HANGING_SIGN()
* @method static WallSign ACACIA_WALL_SIGN()
* @method static Wood ACACIA_WOOD()
* @method static ActivatorRail ACTIVATOR_RAIL()
@ -122,6 +126,8 @@ use function strtolower;
* @method static BigDripleafHead BIG_DRIPLEAF_HEAD()
* @method static BigDripleafStem BIG_DRIPLEAF_STEM()
* @method static WoodenButton BIRCH_BUTTON()
* @method static CeilingCenterHangingSign BIRCH_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign BIRCH_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor BIRCH_DOOR()
* @method static WoodenFence BIRCH_FENCE()
* @method static FenceGate BIRCH_FENCE_GATE()
@ -134,6 +140,7 @@ use function strtolower;
* @method static WoodenSlab BIRCH_SLAB()
* @method static WoodenStairs BIRCH_STAIRS()
* @method static WoodenTrapdoor BIRCH_TRAPDOOR()
* @method static WallHangingSign BIRCH_WALL_HANGING_SIGN()
* @method static WallSign BIRCH_WALL_SIGN()
* @method static Wood BIRCH_WOOD()
* @method static Opaque BLACKSTONE()
@ -170,6 +177,8 @@ use function strtolower;
* @method static Chain CHAIN()
* @method static ChemicalHeat CHEMICAL_HEAT()
* @method static WoodenButton CHERRY_BUTTON()
* @method static CeilingCenterHangingSign CHERRY_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign CHERRY_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor CHERRY_DOOR()
* @method static WoodenFence CHERRY_FENCE()
* @method static FenceGate CHERRY_FENCE_GATE()
@ -181,6 +190,7 @@ use function strtolower;
* @method static WoodenSlab CHERRY_SLAB()
* @method static WoodenStairs CHERRY_STAIRS()
* @method static WoodenTrapdoor CHERRY_TRAPDOOR()
* @method static WallHangingSign CHERRY_WALL_HANGING_SIGN()
* @method static WallSign CHERRY_WALL_SIGN()
* @method static Wood CHERRY_WOOD()
* @method static Chest CHEST()
@ -231,6 +241,8 @@ use function strtolower;
* @method static Opaque CRACKED_STONE_BRICKS()
* @method static CraftingTable CRAFTING_TABLE()
* @method static WoodenButton CRIMSON_BUTTON()
* @method static CeilingCenterHangingSign CRIMSON_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign CRIMSON_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor CRIMSON_DOOR()
* @method static WoodenFence CRIMSON_FENCE()
* @method static FenceGate CRIMSON_FENCE_GATE()
@ -243,6 +255,7 @@ use function strtolower;
* @method static WoodenStairs CRIMSON_STAIRS()
* @method static Wood CRIMSON_STEM()
* @method static WoodenTrapdoor CRIMSON_TRAPDOOR()
* @method static WallHangingSign CRIMSON_WALL_HANGING_SIGN()
* @method static WallSign CRIMSON_WALL_SIGN()
* @method static Opaque CRYING_OBSIDIAN()
* @method static Copper CUT_COPPER()
@ -254,6 +267,8 @@ use function strtolower;
* @method static Slab CUT_SANDSTONE_SLAB()
* @method static Flower DANDELION()
* @method static WoodenButton DARK_OAK_BUTTON()
* @method static CeilingCenterHangingSign DARK_OAK_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign DARK_OAK_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor DARK_OAK_DOOR()
* @method static WoodenFence DARK_OAK_FENCE()
* @method static FenceGate DARK_OAK_FENCE_GATE()
@ -266,6 +281,7 @@ use function strtolower;
* @method static WoodenSlab DARK_OAK_SLAB()
* @method static WoodenStairs DARK_OAK_STAIRS()
* @method static WoodenTrapdoor DARK_OAK_TRAPDOOR()
* @method static WallHangingSign DARK_OAK_WALL_HANGING_SIGN()
* @method static WallSign DARK_OAK_WALL_SIGN()
* @method static Wood DARK_OAK_WOOD()
* @method static Opaque DARK_PRISMARINE()
@ -488,6 +504,8 @@ use function strtolower;
* @method static ItemFrame ITEM_FRAME()
* @method static Jukebox JUKEBOX()
* @method static WoodenButton JUNGLE_BUTTON()
* @method static CeilingCenterHangingSign JUNGLE_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign JUNGLE_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor JUNGLE_DOOR()
* @method static WoodenFence JUNGLE_FENCE()
* @method static FenceGate JUNGLE_FENCE_GATE()
@ -500,6 +518,7 @@ use function strtolower;
* @method static WoodenSlab JUNGLE_SLAB()
* @method static WoodenStairs JUNGLE_STAIRS()
* @method static WoodenTrapdoor JUNGLE_TRAPDOOR()
* @method static WallHangingSign JUNGLE_WALL_HANGING_SIGN()
* @method static WallSign JUNGLE_WALL_SIGN()
* @method static Wood JUNGLE_WOOD()
* @method static ChemistryTable LAB_TABLE()
@ -522,6 +541,8 @@ use function strtolower;
* @method static Loom LOOM()
* @method static Magma MAGMA()
* @method static WoodenButton MANGROVE_BUTTON()
* @method static CeilingCenterHangingSign MANGROVE_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign MANGROVE_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor MANGROVE_DOOR()
* @method static WoodenFence MANGROVE_FENCE()
* @method static FenceGate MANGROVE_FENCE_GATE()
@ -534,6 +555,7 @@ use function strtolower;
* @method static WoodenSlab MANGROVE_SLAB()
* @method static WoodenStairs MANGROVE_STAIRS()
* @method static WoodenTrapdoor MANGROVE_TRAPDOOR()
* @method static WallHangingSign MANGROVE_WALL_HANGING_SIGN()
* @method static WallSign MANGROVE_WALL_SIGN()
* @method static Wood MANGROVE_WOOD()
* @method static ChemistryTable MATERIAL_REDUCER()
@ -572,6 +594,8 @@ use function strtolower;
* @method static Opaque NETHER_WART_BLOCK()
* @method static Note NOTE_BLOCK()
* @method static WoodenButton OAK_BUTTON()
* @method static CeilingCenterHangingSign OAK_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign OAK_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor OAK_DOOR()
* @method static WoodenFence OAK_FENCE()
* @method static FenceGate OAK_FENCE_GATE()
@ -584,14 +608,19 @@ use function strtolower;
* @method static WoodenSlab OAK_SLAB()
* @method static WoodenStairs OAK_STAIRS()
* @method static WoodenTrapdoor OAK_TRAPDOOR()
* @method static WallHangingSign OAK_WALL_HANGING_SIGN()
* @method static WallSign OAK_WALL_SIGN()
* @method static Wood OAK_WOOD()
* @method static Opaque OBSIDIAN()
* @method static OminousFloorBanner OMINOUS_BANNER()
* @method static OminousWallBanner OMINOUS_WALL_BANNER()
* @method static Flower ORANGE_TULIP()
* @method static Flower OXEYE_DAISY()
* @method static PackedIce PACKED_ICE()
* @method static Opaque PACKED_MUD()
* @method static WoodenButton PALE_OAK_BUTTON()
* @method static CeilingCenterHangingSign PALE_OAK_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign PALE_OAK_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor PALE_OAK_DOOR()
* @method static WoodenFence PALE_OAK_FENCE()
* @method static FenceGate PALE_OAK_FENCE_GATE()
@ -603,6 +632,7 @@ use function strtolower;
* @method static WoodenSlab PALE_OAK_SLAB()
* @method static WoodenStairs PALE_OAK_STAIRS()
* @method static WoodenTrapdoor PALE_OAK_TRAPDOOR()
* @method static WallHangingSign PALE_OAK_WALL_HANGING_SIGN()
* @method static WallSign PALE_OAK_WALL_SIGN()
* @method static Wood PALE_OAK_WOOD()
* @method static DoublePlant PEONY()
@ -733,6 +763,8 @@ use function strtolower;
* @method static Sponge SPONGE()
* @method static SporeBlossom SPORE_BLOSSOM()
* @method static WoodenButton SPRUCE_BUTTON()
* @method static CeilingCenterHangingSign SPRUCE_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign SPRUCE_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor SPRUCE_DOOR()
* @method static WoodenFence SPRUCE_FENCE()
* @method static FenceGate SPRUCE_FENCE_GATE()
@ -745,6 +777,7 @@ use function strtolower;
* @method static WoodenSlab SPRUCE_SLAB()
* @method static WoodenStairs SPRUCE_STAIRS()
* @method static WoodenTrapdoor SPRUCE_TRAPDOOR()
* @method static WallHangingSign SPRUCE_WALL_HANGING_SIGN()
* @method static WallSign SPRUCE_WALL_SIGN()
* @method static Wood SPRUCE_WOOD()
* @method static StainedHardenedClay STAINED_CLAY()
@ -788,6 +821,8 @@ use function strtolower;
* @method static WallBanner WALL_BANNER()
* @method static WallCoralFan WALL_CORAL_FAN()
* @method static WoodenButton WARPED_BUTTON()
* @method static CeilingCenterHangingSign WARPED_CEILING_CENTER_HANGING_SIGN()
* @method static CeilingEdgesHangingSign WARPED_CEILING_EDGES_HANGING_SIGN()
* @method static WoodenDoor WARPED_DOOR()
* @method static WoodenFence WARPED_FENCE()
* @method static FenceGate WARPED_FENCE_GATE()
@ -800,6 +835,7 @@ use function strtolower;
* @method static WoodenStairs WARPED_STAIRS()
* @method static Wood WARPED_STEM()
* @method static WoodenTrapdoor WARPED_TRAPDOOR()
* @method static WallHangingSign WARPED_WALL_HANGING_SIGN()
* @method static WallSign WARPED_WALL_SIGN()
* @method static Opaque WARPED_WART_BLOCK()
* @method static Water WATER()
@ -873,6 +909,8 @@ final class VanillaBlocks{
$bannerBreakInfo = new Info(BreakInfo::axe(1.0));
self::register("banner", fn(BID $id) => new FloorBanner($id, "Banner", $bannerBreakInfo), TileBanner::class);
self::register("wall_banner", fn(BID $id) => new WallBanner($id, "Wall Banner", $bannerBreakInfo), TileBanner::class);
self::register("ominous_banner", fn(BID $id) => new OminousFloorBanner($id, "Ominous Banner", $bannerBreakInfo), TileBanner::class);
self::register("ominous_wall_banner", fn(BID $id) => new OminousWallBanner($id, "Ominous Wall Banner", $bannerBreakInfo), TileBanner::class);
self::register("barrel", fn(BID $id) => new Barrel($id, "Barrel", new Info(BreakInfo::axe(2.5))), TileBarrel::class);
self::register("barrier", fn(BID $id) => new Transparent($id, "Barrier", new Info(BreakInfo::indestructible())));
self::register("beacon", fn(BID $id) => new Beacon($id, "Beacon", new Info(new BreakInfo(3.0))), TileBeacon::class);
@ -1392,6 +1430,23 @@ final class VanillaBlocks{
};
self::register($idName("sign"), fn(BID $id) => new FloorSign($id, $name . " Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
self::register($idName("wall_sign"), fn(BID $id) => new WallSign($id, $name . " Wall Sign", $signBreakInfo, $woodType, $signAsItem), TileSign::class);
$hangingSignAsItem = match($woodType){
WoodType::OAK => VanillaItems::OAK_HANGING_SIGN(...),
WoodType::SPRUCE => VanillaItems::SPRUCE_HANGING_SIGN(...),
WoodType::BIRCH => VanillaItems::BIRCH_HANGING_SIGN(...),
WoodType::JUNGLE => VanillaItems::JUNGLE_HANGING_SIGN(...),
WoodType::ACACIA => VanillaItems::ACACIA_HANGING_SIGN(...),
WoodType::DARK_OAK => VanillaItems::DARK_OAK_HANGING_SIGN(...),
WoodType::MANGROVE => VanillaItems::MANGROVE_HANGING_SIGN(...),
WoodType::CRIMSON => VanillaItems::CRIMSON_HANGING_SIGN(...),
WoodType::WARPED => VanillaItems::WARPED_HANGING_SIGN(...),
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);
}
}

View File

@ -35,6 +35,10 @@ use pocketmine\world\BlockTransaction;
final class WallBanner extends BaseBanner implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getOminousVersion() : Block{
return VanillaBlocks::OMINOUS_WALL_BANNER()->setFacing($this->facing);
}
protected function getSupportingFace() : int{
return Facing::opposite($this->facing);
}

View File

@ -0,0 +1,63 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\HorizontalFacingTrait;
use pocketmine\item\Item;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
use pocketmine\player\Player;
use pocketmine\world\BlockTransaction;
final class WallHangingSign extends BaseSign implements HorizontalFacing{
use HorizontalFacingTrait;
protected function getSupportingFace() : int{
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 place(BlockTransaction $tx, Item $item, Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector, ?Player $player = null) : bool{
if(Facing::axis($face) === Axis::Y){
return false;
}
$this->facing = Facing::rotateY($face, clockwise: true);
//the front should always face the player if possible
if($player !== null && $this->facing === $player->getHorizontalFacing()){
$this->facing = Facing::opposite($this->facing);
}
return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player);
}
}

View File

@ -41,6 +41,10 @@ class Banner extends Spawnable{
public const TAG_PATTERNS = "Patterns";
public const TAG_PATTERN_COLOR = "Color";
public const TAG_PATTERN_NAME = "Pattern";
public const TAG_TYPE = "Type";
public const TYPE_NORMAL = 0;
public const TYPE_OMINOUS = 1;
private DyeColor $baseColor = DyeColor::BLACK;
@ -50,6 +54,8 @@ class Banner extends Spawnable{
*/
private array $patterns = [];
private int $type = self::TYPE_NORMAL;
public function readSaveData(CompoundTag $nbt) : void{
$colorIdMap = DyeColorIdMap::getInstance();
if(
@ -75,6 +81,8 @@ class Banner extends Spawnable{
$this->patterns[] = new BannerPatternLayer($patternType, $patternColor);
}
}
$this->type = $nbt->getInt(self::TAG_TYPE);
}
protected function writeSaveData(CompoundTag $nbt) : void{
@ -89,6 +97,7 @@ class Banner extends Spawnable{
);
}
$nbt->setTag(self::TAG_PATTERNS, $patterns);
$nbt->setInt(self::TAG_TYPE, $this->type);
}
protected function addAdditionalSpawnData(CompoundTag $nbt) : void{
@ -103,6 +112,7 @@ class Banner extends Spawnable{
);
}
$nbt->setTag(self::TAG_PATTERNS, $patterns);
$nbt->setInt(self::TAG_TYPE, $this->type);
}
/**
@ -136,6 +146,10 @@ class Banner extends Spawnable{
$this->patterns = $patterns;
}
public function getType() : int{ return $this->type; }
public function setType(int $type) : void{ $this->type = $type; }
public function getDefaultName() : string{
return "Banner";
}

View File

@ -0,0 +1,31 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\block\tile;
/**
* @deprecated
*/
final class HangingSign extends Sign{
}

View File

@ -79,6 +79,7 @@ final class TileFactory{
$this->register(SporeBlossom::class, ["SporeBlossom", "minecraft:spore_blossom"]);
$this->register(MobHead::class, ["Skull", "minecraft:skull"]);
$this->register(GlowingItemFrame::class, ["GlowItemFrame"]);
$this->register(HangingSign::class, ["HangingSign", "minecraft:hanging_sign"]);
//TODO: ChalkboardBlock
//TODO: ChemistryTable

View File

@ -24,29 +24,21 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock;
use pocketmine\block\utils\MushroomBlockType;
use pocketmine\data\bedrock\block\BlockLegacyMetadata as LegacyMeta;
use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\utils\SingletonTrait;
/**
* @deprecated
*/
final class MushroomBlockTypeIdMap{
use SingletonTrait;
/** @phpstan-use IntSaveIdMapTrait<MushroomBlockType> */
use IntSaveIdMapTrait;
public function __construct(){
$newMapping = ValueMappings::getInstance()->mushroomBlockType;
foreach(MushroomBlockType::cases() as $case){
$this->register(match($case){
MushroomBlockType::PORES => LegacyMeta::MUSHROOM_BLOCK_ALL_PORES,
MushroomBlockType::CAP_NORTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER,
MushroomBlockType::CAP_NORTH => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE,
MushroomBlockType::CAP_NORTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER,
MushroomBlockType::CAP_WEST => LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE,
MushroomBlockType::CAP_MIDDLE => LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY,
MushroomBlockType::CAP_EAST => LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE,
MushroomBlockType::CAP_SOUTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER,
MushroomBlockType::CAP_SOUTH => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE,
MushroomBlockType::CAP_SOUTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER,
MushroomBlockType::ALL_CAP => LegacyMeta::MUSHROOM_BLOCK_ALL_CAP,
}, $case);
$this->register($newMapping->valueToRaw($case), $case);
}
}
}

View File

@ -38,6 +38,8 @@ final class BlockLegacyMetadata{
public const CORAL_VARIANT_FIRE = 3;
public const CORAL_VARIANT_HORN = 4;
public const LIQUID_FALLING_FLAG = 0x08;
public const MULTI_FACE_DIRECTION_FLAG_DOWN = 0x01;
public const MULTI_FACE_DIRECTION_FLAG_UP = 0x02;
public const MULTI_FACE_DIRECTION_FLAG_SOUTH = 0x04;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Block;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
use pocketmine\block\utils\Colored;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer;
use pocketmine\data\bedrock\block\convert\property\CommonProperties;
use pocketmine\data\bedrock\block\convert\property\StringProperty;
use function array_map;
use function count;
use function implode;
use function is_string;
/**
* Registers serializers and deserializers for block data in a unified style, to avoid code duplication.
* Not all blocks can be registered this way, but we can avoid a lot of repetition for the ones that can.
*/
final class BlockSerializerDeserializerRegistrar{
public function __construct(
public readonly BlockStateToObjectDeserializer $deserializer,
public readonly BlockObjectToStateSerializer $serializer
){}
/**
* @param string[]|StringProperty[] $components
*
* @phpstan-param list<string|StringProperty<*>> $components
*
* @return string[][]
* @phpstan-return list<list<string>>
*/
private static function compileFlattenedIdPartMatrix(array $components) : array{
$result = [];
foreach($components as $component){
$column = is_string($component) ? [$component] : $component->getPossibleValues();
if(count($result) === 0){
$result = array_map(fn($value) => [$value], $column);
}else{
$stepResult = [];
foreach($result as $parts){
foreach($column as $value){
$stepPart = $parts;
$stepPart[] = $value;
$stepResult[] = $stepPart;
}
}
$result = $stepResult;
}
}
return $result;
}
/**
* @param string[]|StringProperty[] $idComponents
*
* @phpstan-template TBlock of Block
*
* @phpstan-param TBlock $block
* @phpstan-param list<string|StringProperty<contravariant TBlock>> $idComponents
*/
private static function serializeFlattenedId(Block $block, array $idComponents) : string{
$id = "";
foreach($idComponents as $infix){
$id .= is_string($infix) ? $infix : $infix->serializePlain($block);
}
return $id;
}
/**
* @param string[]|StringProperty[] $idComponents
* @param string[] $idPropertyValues
*
* @phpstan-template TBlock of Block
*
* @phpstan-param TBlock $baseBlock
* @phpstan-param list<string|StringProperty<contravariant TBlock>> $idComponents
* @phpstan-param list<string> $idPropertyValues
*
* @phpstan-return TBlock
*/
private static function deserializeFlattenedId(Block $baseBlock, array $idComponents, array $idPropertyValues) : Block{
$preparedBlock = clone $baseBlock;
foreach($idComponents as $k => $component){
if($component instanceof StringProperty){
$fakeValue = $idPropertyValues[$k];
$component->deserializePlain($preparedBlock, $fakeValue);
}
}
return $preparedBlock;
}
public function mapSimple(Block $block, string $id) : void{
$this->deserializer->mapSimple($id, fn() => clone $block);
$this->serializer->mapSimple($block, $id);
}
/**
* @phpstan-template TBlock of Block
* @phpstan-param FlattenedIdModel<TBlock, true> $model
*/
public function mapFlattenedId(FlattenedIdModel $model) : void{
$block = $model->getBlock();
$idComponents = $model->getIdComponents();
if(count($idComponents) === 0){
throw new \InvalidArgumentException("No ID components provided");
}
$properties = $model->getProperties();
//This is a really cursed hack that lets us essentially write flattened properties as blockstate properties, and
//then pull them out to compile an ID :D
//This works surprisingly well and is much more elegant than I would've expected
if(count($properties) > 0){
$this->serializer->map($block, function(Block $block) use ($idComponents, $properties) : Writer{
$id = self::serializeFlattenedId($block, $idComponents);
$writer = new Writer($id);
foreach($properties as $property){
$property->serialize($block, $writer);
}
return $writer;
});
}else{
$this->serializer->map($block, function(Block $block) use ($idComponents) : BlockStateData{
//fast path for blocks with no state properties
$id = self::serializeFlattenedId($block, $idComponents);
return BlockStateData::current($id, []);
});
}
$idPermutations = self::compileFlattenedIdPartMatrix($idComponents);
foreach($idPermutations as $idParts){
//deconstruct the ID into a partial state
//we can do this at registration time since there will be multiple deserializers
$preparedBlock = self::deserializeFlattenedId($block, $idComponents, $idParts);
$id = implode("", $idParts);
if(count($properties) > 0){
$this->deserializer->map($id, function(Reader $reader) use ($preparedBlock, $properties) : Block{
$block = clone $preparedBlock;
foreach($properties as $property){
$property->deserialize($block, $reader);
}
return $block;
});
}else{
//fast path for blocks with no state properties
$this->deserializer->map($id, fn() => clone $preparedBlock);
}
}
}
/**
* @phpstan-template TBlock of Block&Colored
* @phpstan-param TBlock $block
*/
public function mapColored(Block $block, string $idPrefix, string $idSuffix) : void{
$this->mapFlattenedId(FlattenedIdModel::create($block)
->idComponents([
$idPrefix,
CommonProperties::getInstance()->dyeColorIdInfix,
$idSuffix
])
);
}
public function mapSlab(Slab $block, string $type) : void{
$commonProperties = CommonProperties::getInstance();
$this->mapFlattenedId(FlattenedIdModel::create($block)
->idComponents(["minecraft:", $type, "_", $commonProperties->slabIdInfix, "slab"])
->properties([$commonProperties->slabPositionProperty])
);
}
public function mapStairs(Stair $block, string $id) : void{
$this->mapModel(Model::create($block, $id)->properties(CommonProperties::getInstance()->stairProperties));
}
/**
* @phpstan-template TBlock of Block
* @phpstan-param Model<TBlock> $model
*/
public function mapModel(Model $model) : void{
$id = $model->getId();
$block = $model->getBlock();
$propertyDescriptors = $model->getProperties();
$this->deserializer->map($id, static function(Reader $in) use ($block, $propertyDescriptors) : Block{
$newBlock = clone $block;
foreach($propertyDescriptors as $descriptor){
$descriptor->deserialize($newBlock, $in);
}
return $newBlock;
});
$this->serializer->map($block, static function(Block $block) use ($id, $propertyDescriptors) : Writer{
$writer = new Writer($id);
foreach($propertyDescriptors as $descriptor){
$descriptor->serialize($block, $writer);
}
return $writer;
});
}
}

View File

@ -56,11 +56,13 @@ use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\utils\AssumptionFailedError;
/**
* @deprecated
*/
final class BlockStateDeserializerHelper{
/** @throws BlockStateDeserializeException */
@ -71,6 +73,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TCandle of Candle
* @phpstan-param TCandle $block
* @phpstan-return TCandle
@ -103,6 +106,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TBlock of CopperMaterial
*
* @phpstan-param TBlock $block
@ -115,6 +119,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TBlock of CopperMaterial
*
* @phpstan-param TBlock $block
@ -133,6 +138,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TDoor of Door
* @phpstan-param TDoor $block
* @phpstan-return TDoor
@ -155,7 +161,10 @@ final class BlockStateDeserializerHelper{
->setTop($in->readBool(BlockStateNames::UPPER_BLOCK_BIT));
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public static function decodeFenceGate(FenceGate $block, BlockStateReader $in) : FenceGate{
return $block
->setFacing($in->readCardinalHorizontalFacing())
@ -163,17 +172,19 @@ final class BlockStateDeserializerHelper{
->setOpen($in->readBool(BlockStateNames::OPEN_BIT));
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public static function decodeFloorCoralFan(FloorCoralFan $block, BlockStateReader $in) : FloorCoralFan{
return $block
->setAxis(match($in->readBoundedInt(BlockStateNames::CORAL_FAN_DIRECTION, 0, 1)){
0 => Axis::X,
1 => Axis::Z,
default => throw new AssumptionFailedError("readBoundedInt() should have prevented this"),
});
->setAxis($in->mapIntFromInt(BlockStateNames::CORAL_FAN_DIRECTION, ValueMappings::getInstance()->coralAxis));
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public static function decodeFloorSign(FloorSign $block, BlockStateReader $in) : FloorSign{
return $block
->setRotation($in->readBoundedInt(BlockStateNames::GROUND_SIGN_DIRECTION, 0, 15));
@ -186,7 +197,10 @@ final class BlockStateDeserializerHelper{
->setHasMap($in->readBool(StateNames::ITEM_FRAME_MAP_BIT));
}
/** @throws BlockStateDeserializeException */
/**
* @throws BlockStateDeserializeException
* @deprecated
*/
public static function decodeLeaves(Leaves $block, BlockStateReader $in) : Leaves{
return $block
->setNoDecay($in->readBool(StateNames::PERSISTENT_BIT))
@ -236,7 +250,10 @@ final class BlockStateDeserializerHelper{
->setDelay($in->readBoundedInt(BlockStateNames::REPEATER_DELAY, 0, 3) + 1);
}
/** @throws BlockStateDeserializeException */
/**
* @throws BlockStateDeserializeException
* @deprecated
*/
public static function decodeSapling(Sapling $block, BlockStateReader $in) : Sapling{
return $block
->setReady($in->readBool(BlockStateNames::AGE_BIT));
@ -273,6 +290,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TStair of Stair
* @phpstan-param TStair $block
* @phpstan-return TStair
@ -296,6 +314,7 @@ final class BlockStateDeserializerHelper{
}
/**
* @deprecated
* @phpstan-template TTrapdoor of Trapdoor
* @phpstan-param TTrapdoor $block
* @phpstan-return TTrapdoor
@ -320,12 +339,19 @@ final class BlockStateDeserializerHelper{
return $block;
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public static function decodeWallSign(WallSign $block, BlockStateReader $in) : WallSign{
return $block
->setFacing($in->readHorizontalFacing());
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public static function decodeWeightedPressurePlate(WeightedPressurePlate $block, BlockStateReader $in) : WeightedPressurePlate{
return $block
->setOutputSignalStrength($in->readBoundedInt(BlockStateNames::REDSTONE_SIGNAL, 0, 15));

View File

@ -31,6 +31,9 @@ use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\block\convert\property\EnumFromRawStateMap;
use pocketmine\data\bedrock\block\convert\property\IntFromRawStateMap;
use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\nbt\tag\ByteTag;
@ -112,45 +115,45 @@ final class BlockStateReader{
}
/**
* @param int[] $mapping
* @phpstan-param array<int, int> $mapping
* @phpstan-return int
* @deprecated
* @phpstan-param IntFromRawStateMap<string> $map
* @throws BlockStateDeserializeException
*/
private function parseFacingValue(int $value, array $mapping) : int{
$result = $mapping[$value] ?? null;
if($result === null){
throw new BlockStateDeserializeException("Unmapped facing value " . $value);
}
return $result;
}
public function mapIntFromString(string $name, IntFromRawStateMap $map) : int{
$raw = $this->readString($name);
/** @throws BlockStateDeserializeException */
public function readFacingDirection() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::FACING_DIRECTION), [
0 => Facing::DOWN,
1 => Facing::UP,
2 => Facing::NORTH,
3 => Facing::SOUTH,
4 => Facing::WEST,
5 => Facing::EAST
]);
}
/** @throws BlockStateDeserializeException */
public function readBlockFace() : int{
return match($raw = $this->readString(BlockStateNames::MC_BLOCK_FACE)){
StringValues::MC_BLOCK_FACE_DOWN => Facing::DOWN,
StringValues::MC_BLOCK_FACE_UP => Facing::UP,
StringValues::MC_BLOCK_FACE_NORTH => Facing::NORTH,
StringValues::MC_BLOCK_FACE_SOUTH => Facing::SOUTH,
StringValues::MC_BLOCK_FACE_WEST => Facing::WEST,
StringValues::MC_BLOCK_FACE_EAST => Facing::EAST,
default => throw $this->badValueException(BlockStateNames::MC_BLOCK_FACE, $raw)
};
return $map->rawToValue($raw) ?? throw $this->badValueException($name, $raw);
}
/**
* @deprecated
* @phpstan-param IntFromRawStateMap<int> $map
* @throws BlockStateDeserializeException
*/
public function mapIntFromInt(string $name, IntFromRawStateMap $map) : int{
$raw = $this->readInt($name);
return $map->rawToValue($raw) ?? throw $this->badValueException($name, (string) $raw);
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readFacingDirection() : int{
return $this->mapIntFromInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->facing);
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readBlockFace() : int{
return $this->mapIntFromString(BlockStateNames::MC_BLOCK_FACE, ValueMappings::getInstance()->blockFace);
}
/**
* @deprecated
* @return int[]
* @phpstan-return array<int, int>
*/
@ -173,82 +176,69 @@ final class BlockStateReader{
return $result;
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readEndRodFacingDirection() : int{
$result = $this->readFacingDirection();
return Facing::axis($result) !== Axis::Y ? Facing::opposite($result) : $result;
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readHorizontalFacing() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::FACING_DIRECTION), [
0 => Facing::NORTH, //should be illegal, but 1.13 allows it
1 => Facing::NORTH, //also should be illegal
2 => Facing::NORTH,
3 => Facing::SOUTH,
4 => Facing::WEST,
5 => Facing::EAST
]);
}
/** @throws BlockStateDeserializeException */
public function readWeirdoHorizontalFacing() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::WEIRDO_DIRECTION), [
0 => Facing::EAST,
1 => Facing::WEST,
2 => Facing::SOUTH,
3 => Facing::NORTH
]);
}
/** @throws BlockStateDeserializeException */
public function readLegacyHorizontalFacing() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::DIRECTION), [
0 => Facing::SOUTH,
1 => Facing::WEST,
2 => Facing::NORTH,
3 => Facing::EAST
]);
return $this->mapIntFromInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->horizontalFacingClassic);
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readWeirdoHorizontalFacing() : int{
return $this->mapIntFromInt(BlockStateNames::WEIRDO_DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus);
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readLegacyHorizontalFacing() : int{
return $this->mapIntFromInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacingSWNE);
}
/**
* @deprecated
* This is for trapdoors, because Mojang botched the conversion in 1.13
* @throws BlockStateDeserializeException
*/
public function read5MinusHorizontalFacing() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::DIRECTION), [
0 => Facing::EAST,
1 => Facing::WEST,
2 => Facing::SOUTH,
3 => Facing::NORTH
]);
return $this->mapIntFromInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus);
}
/**
* @deprecated
* Used by pumpkins as of 1.20.0.23 beta
* @throws BlockStateDeserializeException
*/
public function readCardinalHorizontalFacing() : int{
return match($raw = $this->readString(BlockStateNames::MC_CARDINAL_DIRECTION)){
StringValues::MC_CARDINAL_DIRECTION_NORTH => Facing::NORTH,
StringValues::MC_CARDINAL_DIRECTION_SOUTH => Facing::SOUTH,
StringValues::MC_CARDINAL_DIRECTION_WEST => Facing::WEST,
StringValues::MC_CARDINAL_DIRECTION_EAST => Facing::EAST,
default => throw $this->badValueException(BlockStateNames::MC_CARDINAL_DIRECTION, $raw)
};
return $this->mapIntFromString(BlockStateNames::MC_CARDINAL_DIRECTION, ValueMappings::getInstance()->cardinalDirection);
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readCoralFacing() : int{
return $this->parseFacingValue($this->readInt(BlockStateNames::CORAL_DIRECTION), [
0 => Facing::WEST,
1 => Facing::EAST,
2 => Facing::NORTH,
3 => Facing::SOUTH
]);
return $this->mapIntFromInt(BlockStateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral);
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readFacingWithoutDown() : int{
$result = $this->readFacingDirection();
if($result === Facing::DOWN){ //shouldn't be legal, but 1.13 allows it
@ -257,6 +247,10 @@ final class BlockStateReader{
return $result;
}
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readFacingWithoutUp() : int{
$result = $this->readFacingDirection();
if($result === Facing::UP){
@ -266,23 +260,17 @@ final class BlockStateReader{
}
/**
* @phpstan-return Axis::*
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readPillarAxis() : int{
$rawValue = $this->readString(BlockStateNames::PILLAR_AXIS);
$value = [
StringValues::PILLAR_AXIS_X => Axis::X,
StringValues::PILLAR_AXIS_Y => Axis::Y,
StringValues::PILLAR_AXIS_Z => Axis::Z
][$rawValue] ?? null;
if($value === null){
throw $this->badValueException(BlockStateNames::PILLAR_AXIS, $rawValue, "Invalid axis value");
}
return $value;
return $this->mapIntFromString(BlockStateNames::PILLAR_AXIS, ValueMappings::getInstance()->pillarAxis);
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readSlabPosition() : SlabType{
return match($rawValue = $this->readString(BlockStateNames::MC_VERTICAL_HALF)){
StringValues::MC_VERTICAL_HALF_BOTTOM => SlabType::BOTTOM,
@ -292,34 +280,25 @@ final class BlockStateReader{
}
/**
* @phpstan-return Facing::UP|Facing::NORTH|Facing::SOUTH|Facing::WEST|Facing::EAST
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readTorchFacing() : int{
//TODO: horizontal directions are flipped (MCPE bug: https://bugs.mojang.com/browse/MCPE-152036)
return match($rawValue = $this->readString(BlockStateNames::TORCH_FACING_DIRECTION)){
StringValues::TORCH_FACING_DIRECTION_EAST => Facing::WEST,
StringValues::TORCH_FACING_DIRECTION_NORTH => Facing::SOUTH,
StringValues::TORCH_FACING_DIRECTION_SOUTH => Facing::NORTH,
StringValues::TORCH_FACING_DIRECTION_TOP => Facing::UP,
StringValues::TORCH_FACING_DIRECTION_UNKNOWN => Facing::UP, //should be illegal, but 1.13 allows it
StringValues::TORCH_FACING_DIRECTION_WEST => Facing::EAST,
default => throw $this->badValueException(BlockStateNames::TORCH_FACING_DIRECTION, $rawValue, "Invalid torch facing"),
};
return $this->mapIntFromString(BlockStateNames::TORCH_FACING_DIRECTION, ValueMappings::getInstance()->torchFacing);
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readBellAttachmentType() : BellAttachmentType{
return match($type = $this->readString(BlockStateNames::ATTACHMENT)){
StringValues::ATTACHMENT_HANGING => BellAttachmentType::CEILING,
StringValues::ATTACHMENT_STANDING => BellAttachmentType::FLOOR,
StringValues::ATTACHMENT_SIDE => BellAttachmentType::ONE_WALL,
StringValues::ATTACHMENT_MULTIPLE => BellAttachmentType::TWO_WALLS,
default => throw $this->badValueException(BlockStateNames::ATTACHMENT, $type),
};
return $this->readUnitEnum(BlockStateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType);
}
/** @throws BlockStateDeserializeException */
/**
* @deprecated
* @throws BlockStateDeserializeException
*/
public function readWallConnectionType(string $name) : ?WallConnectionType{
return match($type = $this->readString($name)){
//TODO: this looks a bit confusing due to use of EAST, but the values are the same for all connections
@ -332,6 +311,23 @@ final class BlockStateReader{
};
}
/**
* @deprecated
* @phpstan-template TEnum of \UnitEnum
* @phpstan-param EnumFromRawStateMap<TEnum, string> $map
* @phpstan-return TEnum
* @throws BlockStateDeserializeException
*/
public function readUnitEnum(string $name, EnumFromRawStateMap $map) : \UnitEnum{
$value = $this->readString($name);
$mapped = $map->rawToValue($value);
if($mapped === null){
throw $this->badValueException($name, $value);
}
return $mapped;
}
/**
* Explicitly mark a property as unused, so it doesn't get flagged as an error when debug mode is enabled
*/

View File

@ -55,6 +55,9 @@ use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Facing;
/**
* @deprecated
*/
final class BlockStateSerializerHelper{
public static function encodeButton(Button $block, Writer $out) : Writer{
return $out
@ -77,6 +80,9 @@ final class BlockStateSerializerHelper{
return $out->writeInt(BlockStateNames::GROWTH, $block->getAge());
}
/**
* @deprecated
*/
public static function encodeTorch(Torch $block, Writer $out) : Writer{
return $out
->writeTorchFacing($block->getFacing());
@ -97,6 +103,9 @@ final class BlockStateSerializerHelper{
};
}
/**
* @deprecated
*/
public static function encodeDoor(Door $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
@ -111,6 +120,9 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop());
}
/**
* @deprecated
*/
public static function encodeFenceGate(FenceGate $block, Writer $out) : Writer{
return $out
->writeCardinalHorizontalFacing($block->getFacing())
@ -118,6 +130,9 @@ final class BlockStateSerializerHelper{
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
/**
* @deprecated
*/
public static function encodeFloorSign(FloorSign $block, Writer $out) : Writer{
return $out
->writeInt(BlockStateNames::GROUND_SIGN_DIRECTION, $block->getRotation());
@ -135,6 +150,9 @@ final class BlockStateSerializerHelper{
->writeFacingDirection($block->getFacing());
}
/**
* @deprecated
*/
public static function encodeLeaves(Leaves $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::PERSISTENT_BIT, $block->isNoDecay())
@ -159,11 +177,17 @@ final class BlockStateSerializerHelper{
->writeInt(BlockStateNames::HUGE_MUSHROOM_BITS, MushroomBlockTypeIdMap::getInstance()->toId($block->getMushroomBlockType()));
}
/**
* @deprecated
*/
public static function encodeQuartz(int $axis, Writer $out) : Writer{
return $out
->writePillarAxis($axis); //this isn't needed for all types, but we have to write it anyway
}
/**
* @deprecated
*/
public static function encodeSapling(Sapling $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::AGE_BIT, $block->isReady());
@ -193,6 +217,9 @@ final class BlockStateSerializerHelper{
self::encodeSingleSlab($block, $singleId);
}
/**
* @deprecated
*/
public static function encodeStairs(Stair $block, Writer $out) : Writer{
return $out
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isUpsideDown())
@ -208,6 +235,9 @@ final class BlockStateSerializerHelper{
->writeFacingWithoutUp($facing === Facing::UP ? Facing::DOWN : $facing);
}
/**
* @deprecated
*/
public static function encodeTrapdoor(Trapdoor $block, Writer $out) : Writer{
return $out
->write5MinusHorizontalFacing($block->getFacing())
@ -224,6 +254,9 @@ final class BlockStateSerializerHelper{
->writeWallConnectionType(BlockStateNames::WALL_CONNECTION_TYPE_WEST, $block->getConnection(Facing::WEST));
}
/**
* @deprecated
*/
public static function encodeWallSign(WallSign $block, Writer $out) : Writer{
return $out
->writeHorizontalFacing($block->getFacing());

View File

@ -31,6 +31,9 @@ use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockStateNames;
use pocketmine\data\bedrock\block\BlockStateSerializeException;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\block\convert\property\EnumFromRawStateMap;
use pocketmine\data\bedrock\block\convert\property\IntFromRawStateMap;
use pocketmine\data\bedrock\block\convert\property\ValueMappings;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\nbt\tag\ByteTag;
@ -73,35 +76,47 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
public function writeFacingDirection(int $value) : self{
$this->writeInt(BlockStateNames::FACING_DIRECTION, match($value){
Facing::DOWN => 0,
Facing::UP => 1,
Facing::NORTH => 2,
Facing::SOUTH => 3,
Facing::WEST => 4,
Facing::EAST => 5,
default => throw new BlockStateSerializeException("Invalid Facing $value")
});
return $this;
}
/** @return $this */
public function writeBlockFace(int $value) : self{
$this->writeString(BlockStateNames::MC_BLOCK_FACE, match($value){
Facing::DOWN => StringValues::MC_BLOCK_FACE_DOWN,
Facing::UP => StringValues::MC_BLOCK_FACE_UP,
Facing::NORTH => StringValues::MC_BLOCK_FACE_NORTH,
Facing::SOUTH => StringValues::MC_BLOCK_FACE_SOUTH,
Facing::WEST => StringValues::MC_BLOCK_FACE_WEST,
Facing::EAST => StringValues::MC_BLOCK_FACE_EAST,
default => throw new BlockStateSerializeException("Invalid Facing $value")
});
/**
* @deprecated
* @phpstan-param IntFromRawStateMap<string> $map
* @return $this
*/
public function mapIntToString(string $name, IntFromRawStateMap $map, int $value) : self{
$raw = $map->valueToRaw($value);
$this->writeString($name, $raw);
return $this;
}
/**
* @deprecated
* @phpstan-param IntFromRawStateMap<int> $map
* @return $this
*/
public function mapIntToInt(string $name, IntFromRawStateMap $map, int $value) : self{
$raw = $map->valueToRaw($value);
$this->writeInt($name, $raw);
return $this;
}
/**
* @deprecated
* @return $this
*/
public function writeFacingDirection(int $value) : self{
return $this->mapIntToInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->facing, $value);
}
/**
* @deprecated
* @return $this
*/
public function writeBlockFace(int $value) : self{
$this->mapIntToString(BlockStateNames::MC_BLOCK_FACE, ValueMappings::getInstance()->blockFace, $value);
return $this;
}
/**
* @deprecated
* @param int[] $faces
* @phpstan-param array<int, int> $faces
* @return $this
@ -123,86 +138,69 @@ final class BlockStateWriter{
return $this->writeInt(BlockStateNames::MULTI_FACE_DIRECTION_BITS, $result);
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeEndRodFacingDirection(int $value) : self{
//end rods are stupid in bedrock and have everything except up/down the wrong way round
return $this->writeFacingDirection(Facing::axis($value) !== Axis::Y ? Facing::opposite($value) : $value);
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeHorizontalFacing(int $value) : self{
if($value === Facing::UP || $value === Facing::DOWN){
throw new BlockStateSerializeException("Y-axis facing is not allowed");
}
return $this->writeFacingDirection($value);
}
/** @return $this */
public function writeWeirdoHorizontalFacing(int $value) : self{
$this->writeInt(BlockStateNames::WEIRDO_DIRECTION, match($value){
Facing::EAST => 0,
Facing::WEST => 1,
Facing::SOUTH => 2,
Facing::NORTH => 3,
default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
});
return $this;
}
/** @return $this */
public function writeLegacyHorizontalFacing(int $value) : self{
$this->writeInt(BlockStateNames::DIRECTION, match($value){
Facing::SOUTH => 0,
Facing::WEST => 1,
Facing::NORTH => 2,
Facing::EAST => 3,
default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
});
return $this;
return $this->mapIntToInt(BlockStateNames::FACING_DIRECTION, ValueMappings::getInstance()->horizontalFacingClassic, $value);
}
/**
* @deprecated
* @return $this
*/
public function writeWeirdoHorizontalFacing(int $value) : self{
return $this->mapIntToInt(BlockStateNames::WEIRDO_DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus, $value);
}
/**
* @deprecated
* @return $this
*/
public function writeLegacyHorizontalFacing(int $value) : self{
return $this->mapIntToInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacingSWNE, $value);
}
/**
* @deprecated
* This is for trapdoors, because Mojang botched the conversion in 1.13
* @return $this
*/
public function write5MinusHorizontalFacing(int $value) : self{
return $this->writeInt(BlockStateNames::DIRECTION, match($value){
Facing::EAST => 0,
Facing::WEST => 1,
Facing::SOUTH => 2,
Facing::NORTH => 3,
default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
});
return $this->mapIntToInt(BlockStateNames::DIRECTION, ValueMappings::getInstance()->horizontalFacing5Minus, $value);
}
/**
* @deprecated
* Used by pumpkins as of 1.20.0.23 beta
* @return $this
*/
public function writeCardinalHorizontalFacing(int $value) : self{
return $this->writeString(BlockStateNames::MC_CARDINAL_DIRECTION, match($value){
Facing::SOUTH => StringValues::MC_CARDINAL_DIRECTION_SOUTH,
Facing::WEST => StringValues::MC_CARDINAL_DIRECTION_WEST,
Facing::NORTH => StringValues::MC_CARDINAL_DIRECTION_NORTH,
Facing::EAST => StringValues::MC_CARDINAL_DIRECTION_EAST,
default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
});
return $this->mapIntToString(BlockStateNames::MC_CARDINAL_DIRECTION, ValueMappings::getInstance()->cardinalDirection, $value);
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeCoralFacing(int $value) : self{
$this->writeInt(BlockStateNames::CORAL_DIRECTION, match($value){
Facing::WEST => 0,
Facing::EAST => 1,
Facing::NORTH => 2,
Facing::SOUTH => 3,
default => throw new BlockStateSerializeException("Invalid horizontal facing $value")
});
return $this;
return $this->mapIntToInt(BlockStateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral, $value);
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeFacingWithoutDown(int $value) : self{
if($value === Facing::DOWN){
throw new BlockStateSerializeException("Invalid facing DOWN");
@ -211,7 +209,10 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeFacingWithoutUp(int $value) : self{
if($value === Facing::UP){
throw new BlockStateSerializeException("Invalid facing UP");
@ -220,18 +221,19 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writePillarAxis(int $axis) : self{
$this->writeString(BlockStateNames::PILLAR_AXIS, match($axis){
Axis::X => StringValues::PILLAR_AXIS_X,
Axis::Y => StringValues::PILLAR_AXIS_Y,
Axis::Z => StringValues::PILLAR_AXIS_Z,
default => throw new BlockStateSerializeException("Invalid axis $axis")
});
$this->mapIntToString(BlockStateNames::PILLAR_AXIS, ValueMappings::getInstance()->pillarAxis, $axis);
return $this;
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeSlabPosition(SlabType $slabType) : self{
$this->writeString(BlockStateNames::MC_VERTICAL_HALF, match($slabType){
SlabType::TOP => StringValues::MC_VERTICAL_HALF_TOP,
@ -241,32 +243,27 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeTorchFacing(int $facing) : self{
//TODO: horizontal directions are flipped (MCPE bug: https://bugs.mojang.com/browse/MCPE-152036)
$this->writeString(BlockStateNames::TORCH_FACING_DIRECTION, match($facing){
Facing::UP => StringValues::TORCH_FACING_DIRECTION_TOP,
Facing::SOUTH => StringValues::TORCH_FACING_DIRECTION_NORTH,
Facing::NORTH => StringValues::TORCH_FACING_DIRECTION_SOUTH,
Facing::EAST => StringValues::TORCH_FACING_DIRECTION_WEST,
Facing::WEST => StringValues::TORCH_FACING_DIRECTION_EAST,
default => throw new BlockStateSerializeException("Invalid Torch facing $facing")
});
$this->mapIntToString(BlockStateNames::TORCH_FACING_DIRECTION, ValueMappings::getInstance()->torchFacing, $facing);
return $this;
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeBellAttachmentType(BellAttachmentType $attachmentType) : self{
$this->writeString(BlockStateNames::ATTACHMENT, match($attachmentType){
BellAttachmentType::FLOOR => StringValues::ATTACHMENT_STANDING,
BellAttachmentType::CEILING => StringValues::ATTACHMENT_HANGING,
BellAttachmentType::ONE_WALL => StringValues::ATTACHMENT_SIDE,
BellAttachmentType::TWO_WALLS => StringValues::ATTACHMENT_MULTIPLE,
});
return $this;
return $this->writeUnitEnum(BlockStateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType, $attachmentType);
}
/** @return $this */
/**
* @deprecated
* @return $this
*/
public function writeWallConnectionType(string $name, ?WallConnectionType $wallConnectionType) : self{
$this->writeString($name, match($wallConnectionType){
null => StringValues::WALL_CONNECTION_TYPE_EAST_NONE,
@ -276,6 +273,21 @@ final class BlockStateWriter{
return $this;
}
/**
* @deprecated
* @phpstan-template TEnum of \UnitEnum
* @phpstan-param EnumFromRawStateMap<TEnum, string> $map
* @phpstan-param TEnum $case
*
* @return $this
*/
public function writeUnitEnum(string $name, EnumFromRawStateMap $map, \UnitEnum $case) : self{
$value = $map->valueToRaw($case);
$this->writeString($name, $value);
return $this;
}
public function getBlockStateData() : BlockStateData{
return BlockStateData::current($this->id, $this->states);
}

View File

@ -0,0 +1,107 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Block;
use pocketmine\data\bedrock\block\convert\property\Property;
use pocketmine\data\bedrock\block\convert\property\StringProperty;
/**
* This class works around a limitation in PHPStan.
* Ideally, we'd just have a function that accepted ($block, $id, $properties) all together and just have the template
* type inferred from $block alone.
* However, there's no way to tell PHPStan to ignore $properties for inference, so we're stuck with this hack.
*
* @phpstan-template TBlock of Block
* @phpstan-template THasIdComponents of bool
*/
final class FlattenedIdModel{
/**
* @var string[]|StringProperty[]
* @phpstan-var list<string|StringProperty<contravariant TBlock>>
*/
private array $idComponents = [];
/**
* @var Property[]
* @phpstan-var list<Property<contravariant TBlock>>
*/
private array $properties = [];
/**
* @phpstan-param TBlock $block
*/
private function __construct(
private Block $block
){}
/**
* @phpstan-template TBlock_ of Block
* @phpstan-param TBlock_ $block
* @return self<TBlock_, false>
*/
public static function create(Block $block) : self{
/** @phpstan-var self<TBlock_, false> $result */
$result = new self($block);
return $result;
}
/** @phpstan-return TBlock */
public function getBlock() : Block{ return $this->block; }
/**
* @return string[]|StringProperty[]
* @phpstan-return list<string|StringProperty<contravariant TBlock>>
*/
public function getIdComponents() : array{ return $this->idComponents; }
/**
* @return Property[]
* @phpstan-return list<Property<contravariant TBlock>>
*/
public function getProperties() : array{ return $this->properties; }
/**
* @param string[]|StringProperty[] $components
* @phpstan-param non-empty-list<string|StringProperty<contravariant TBlock>> $components
* @return $this
* @phpstan-this-out self<TBlock, true>
*/
public function idComponents(array $components) : self{
$this->idComponents = $components;
return $this;
}
/**
* @param Property[] $properties
* @phpstan-param non-empty-list<Property<contravariant TBlock>> $properties
* @return $this
* @phpstan-this-out self<TBlock, THasIdComponents>
*/
public function properties(array $properties) : self{
$this->properties = $properties;
return $this;
}
}

View File

@ -0,0 +1,82 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\Block;
use pocketmine\data\bedrock\block\convert\property\Property;
/**
* This class works around a limitation in PHPStan.
* Ideally, we'd just have a function that accepted ($block, $id, $properties) all together and just have the template
* type inferred from $block alone.
* However, there's no way to tell PHPStan to ignore $properties for inference, so we're stuck with this hack.
*
* @phpstan-template TBlock of Block
*/
final class Model{
/**
* @var Property[]
* @phpstan-var list<Property<contravariant TBlock>>
*/
private array $properties = [];
/**
* @phpstan-param TBlock $block
*/
private function __construct(
private Block $block,
private string $id
){}
/** @phpstan-return TBlock */
public function getBlock() : Block{ return $this->block; }
public function getId() : string{ return $this->id; }
/**
* @return Property[]
* @phpstan-return list<Property<contravariant TBlock>>
*/
public function getProperties() : array{ return $this->properties; }
/**
* @phpstan-template TBlock_ of Block
* @phpstan-param TBlock_ $block
* @phpstan-return self<TBlock_>
*/
public static function create(Block $block, string $id) : self{
return new self($block, $id);
}
/**
* @param Property[] $properties
* @phpstan-param list<Property<contravariant TBlock>> $properties
* @phpstan-return $this
*/
public function properties(array $properties) : self{
$this->properties = $properties;
return $this;
}
}

View File

@ -1,78 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use function spl_object_id;
/**
* @phpstan-template TEnum of \UnitEnum
*/
class StringEnumMap{
/**
* @var string[]
* @phpstan-var array<int, string>
*/
private array $enumToValue = [];
/**
* @var \UnitEnum[]
* @phpstan-var array<string, TEnum>
*/
private array $valueToEnum = [];
/**
* @phpstan-param class-string<TEnum> $class
* @phpstan-param \Closure(TEnum) : string $mapper
*/
public function __construct(
private string $class,
\Closure $mapper
){
foreach($class::cases() as $case){
$string = $mapper($case);
$this->valueToEnum[$string] = $case;
$this->enumToValue[spl_object_id($case)] = $string;
}
}
/**
* @phpstan-param TEnum $enum
*/
public function enumToValue(\UnitEnum $enum) : string{
return $this->enumToValue[spl_object_id($enum)];
}
public function valueToEnum(string $string) : ?\UnitEnum{
return $this->valueToEnum[$string] ?? throw new BlockStateDeserializeException("No $this->class enum mapping for \"$string\"");
}
/**
* @return \UnitEnum[]
* @phpstan-return array<string, TEnum>
*/
public function getValueToEnum() : array{
return $this->valueToEnum;
}
}

View File

@ -1,83 +0,0 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert;
use pocketmine\block\utils\DyeColor;
use pocketmine\utils\SingletonTrait;
final class ValueMappings{
use SingletonTrait; //???
/**
* @var StringEnumMap[]
* @phpstan-var array<class-string<covariant \UnitEnum>, StringEnumMap<covariant \UnitEnum>>
*/
private array $enumMappings = [];
public function __construct(){
$this->addEnum(DyeColor::class, fn(DyeColor $case) => match ($case) {
DyeColor::BLACK => "black",
DyeColor::BLUE => "blue",
DyeColor::BROWN => "brown",
DyeColor::CYAN => "cyan",
DyeColor::GRAY => "gray",
DyeColor::GREEN => "green",
DyeColor::LIGHT_BLUE => "light_blue",
DyeColor::LIGHT_GRAY => "light_gray",
DyeColor::LIME => "lime",
DyeColor::MAGENTA => "magenta",
DyeColor::ORANGE => "orange",
DyeColor::PINK => "pink",
DyeColor::PURPLE => "purple",
DyeColor::RED => "red",
DyeColor::WHITE => "white",
DyeColor::YELLOW => "yellow"
});
}
/**
* @phpstan-template TEnum of \UnitEnum
* @phpstan-param class-string<TEnum> $class
* @phpstan-param \Closure(TEnum): string $mapper
*/
private function addEnum(string $class, \Closure $mapper) : void{
$this->enumMappings[$class] = new StringEnumMap($class, $mapper);
}
/**
* @phpstan-template TEnum of \UnitEnum
* @phpstan-param class-string<TEnum> $class
* @phpstan-return StringEnumMap<TEnum>
*/
public function getEnumMap(string $class) : StringEnumMap{
if(!isset($this->enumMappings[$class])){
throw new \InvalidArgumentException("No enum mapping found for class: $class");
}
/**
* @phpstan-var StringEnumMap<TEnum> $map
*/
$map = $this->enumMappings[$class];
return $map;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\BlockStateSerializeException;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
/**
* @phpstan-template TBlock of object
* @phpstan-implements StringProperty<TBlock>
*/
final class BoolFromStringProperty implements StringProperty{
/**
* @param \Closure(TBlock) : bool $getter
* @param \Closure(TBlock, bool) : mixed $setter
*/
public function __construct(
private string $name,
private string $falseValue,
private string $trueValue,
private \Closure $getter,
private \Closure $setter
){}
public function getName() : string{
return $this->name;
}
public function getPossibleValues() : array{
return [$this->falseValue, $this->trueValue];
}
public function deserialize(object $block, BlockStateReader $in) : void{
$this->deserializePlain($block, $in->readString($this->name));
}
public function deserializePlain(object $block, string $raw) : void{
$value = match($raw){
$this->falseValue => false,
$this->trueValue => true,
default => throw new BlockStateSerializeException("Invalid value for {$this->name}: $raw"),
};
($this->setter)($block, $value);
}
public function serialize(object $block, BlockStateWriter $out) : void{
$out->writeString($this->name, $this->serializePlain($block));
}
public function serializePlain(object $block) : string{
$value = ($this->getter)($block);
return $value ? $this->trueValue : $this->falseValue;
}
}

View File

@ -0,0 +1,71 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
/**
* @phpstan-template TBlock of object
* @phpstan-implements Property<TBlock>
*/
final class BoolProperty implements Property{
/**
* @phpstan-param \Closure(TBlock) : bool $getter
* @phpstan-param \Closure(TBlock, bool) : mixed $setter
*/
public function __construct(
private string $name,
private \Closure $getter,
private \Closure $setter,
private bool $inverted = false //we don't *need* this, but it avoids accidentally forgetting a ! in the getter/setter closures (and makes it analysable)
){}
/**
* @phpstan-return self<object>
*/
public static function unused(string $name, bool $serializedValue) : self{
return new self($name, fn() => $serializedValue, fn() => null);
}
public function getName() : string{ return $this->name; }
/**
* @phpstan-param TBlock $block
*/
public function deserialize(object $block, BlockStateReader $in) : void{
$raw = $in->readBool($this->name);
$value = $raw !== $this->inverted;
($this->setter)($block, $value);
}
/**
* @phpstan-param TBlock $block
*/
public function serialize(object $block, BlockStateWriter $out) : void{
$value = ($this->getter)($block);
$raw = $value !== $this->inverted;
$out->writeBool($this->name, $raw);
}
}

View File

@ -0,0 +1,428 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\block\Button;
use pocketmine\block\Door;
use pocketmine\block\DoublePlant;
use pocketmine\block\FenceGate;
use pocketmine\block\ItemFrame;
use pocketmine\block\Liquid;
use pocketmine\block\SimplePressurePlate;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
use pocketmine\block\Stem;
use pocketmine\block\Torch;
use pocketmine\block\Trapdoor;
use pocketmine\block\utils\Ageable;
use pocketmine\block\utils\AnalogRedstoneSignalEmitter;
use pocketmine\block\utils\AnyFacing;
use pocketmine\block\utils\Colored;
use pocketmine\block\utils\CopperMaterial;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\CoralMaterial;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\HorizontalFacing;
use pocketmine\block\utils\Lightable;
use pocketmine\block\utils\MultiFacing;
use pocketmine\block\utils\PillarRotation;
use pocketmine\block\utils\SignLikeRotation;
use pocketmine\block\utils\SlabType;
use pocketmine\block\Wall;
use pocketmine\block\Wood;
use pocketmine\data\bedrock\block\BlockLegacyMetadata;
use pocketmine\data\bedrock\block\BlockStateNames as StateNames;
use pocketmine\data\bedrock\block\BlockStateStringValues;
use pocketmine\math\Facing;
use pocketmine\utils\SingletonTrait;
final class CommonProperties{
use SingletonTrait;
/** @phpstan-var ValueFromStringProperty<AnyFacing, int> */
public readonly ValueFromStringProperty $blockFace;
/** @phpstan-var ValueFromStringProperty<PillarRotation, int> */
public readonly ValueFromStringProperty $pillarAxis;
/** @phpstan-var ValueFromStringProperty<Torch, int> */
public readonly ValueFromStringProperty $torchFacing;
/** @phpstan-var ValueFromStringProperty<HorizontalFacing, int> */
public readonly ValueFromStringProperty $horizontalFacingCardinal;
/** @phpstan-var ValueFromIntProperty<HorizontalFacing, int> */
public readonly ValueFromIntProperty $horizontalFacingSWNE;
/** @phpstan-var ValueFromIntProperty<HorizontalFacing, int> */
public readonly ValueFromIntProperty $horizontalFacingSWNEInverted;
/** @phpstan-var ValueFromIntProperty<HorizontalFacing, int> */
public readonly ValueFromIntProperty $horizontalFacingClassic;
/** @phpstan-var ValueFromIntProperty<AnyFacing, int> */
public readonly ValueFromIntProperty $anyFacingClassic;
/** @phpstan-var OptionSetFromIntProperty<MultiFacing, int> */
public readonly OptionSetFromIntProperty $multiFacingFlags;
/** @phpstan-var IntProperty<SignLikeRotation> */
public readonly IntProperty $floorSignLikeRotation;
/** @phpstan-var IntProperty<AnalogRedstoneSignalEmitter> */
public readonly IntProperty $analogRedstoneSignal;
/** @phpstan-var IntProperty<Ageable> */
public readonly IntProperty $cropAgeMax7;
/** @phpstan-var BoolProperty<DoublePlant> */
public readonly BoolProperty $doublePlantHalf;
/** @phpstan-var IntProperty<Liquid> */
public readonly IntProperty $liquidData;
/** @phpstan-var BoolProperty<Lightable> */
public readonly BoolProperty $lit;
public readonly DummyProperty $dummyCardinalDirection;
public readonly DummyProperty $dummyPillarAxis;
/** @phpstan-var ValueFromStringProperty<Colored, DyeColor> */
public readonly ValueFromStringProperty $dyeColorIdInfix;
/** @phpstan-var BoolFromStringProperty<Lightable> */
public readonly BoolFromStringProperty $litIdInfix;
/** @phpstan-var BoolFromStringProperty<Slab> */
public readonly BoolFromStringProperty $slabIdInfix;
/** @phpstan-var BoolFromStringProperty<Slab> */
public readonly BoolFromStringProperty $slabPositionProperty;
/**
* @var StringProperty[]
* @phpstan-var non-empty-list<string|StringProperty<CoralMaterial>>
*/
public readonly array $coralIdPrefixes;
/**
* @var StringProperty[]
* @phpstan-var non-empty-list<string|StringProperty<CopperMaterial>>
*/
public readonly array $copperIdPrefixes;
/**
* @var StringProperty[]
* @phpstan-var non-empty-list<string|StringProperty<contravariant Lightable>>
*/
public readonly array $furnaceIdPrefixes;
/**
* @var StringProperty[]|string[]
* @phpstan-var non-empty-list<string|StringProperty<contravariant Liquid>>
*/
public readonly array $liquidIdPrefixes;
/**
* @var StringProperty[]
* @phpstan-var non-empty-list<string|StringProperty<contravariant Wood>>
*/
public readonly array $woodIdPrefixes;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Button>>
*/
public readonly array $buttonProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Lightable & HorizontalFacing>>
*/
public readonly array $campfireProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Door>>
*/
public readonly array $doorProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant FenceGate>>
*/
public readonly array $fenceGateProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant ItemFrame>>
*/
public readonly array $itemFrameProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant SimplePressurePlate>>
*/
public readonly array $simplePressurePlateProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Stair>>
*/
public readonly array $stairProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Stem>>
*/
public readonly array $stemProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Trapdoor>>
*/
public readonly array $trapdoorProperties;
/**
* @var Property[]
* @phpstan-var non-empty-list<Property<contravariant Wall>>
*/
public readonly array $wallProperties;
private function __construct(){
$vm = ValueMappings::getInstance();
$hfGet = fn(HorizontalFacing $v) => $v->getFacing();
$hfSet = fn(HorizontalFacing $v, int $facing) => $v->setFacing($facing);
$this->horizontalFacingCardinal = new ValueFromStringProperty(StateNames::MC_CARDINAL_DIRECTION, $vm->cardinalDirection, $hfGet, $hfSet);
$this->blockFace = new ValueFromStringProperty(
StateNames::MC_BLOCK_FACE,
$vm->blockFace,
fn(AnyFacing $b) => $b->getFacing(),
fn(AnyFacing $b, int $v) => $b->setFacing($v)
);
$this->pillarAxis = new ValueFromStringProperty(
StateNames::PILLAR_AXIS,
$vm->pillarAxis,
fn(PillarRotation $b) => $b->getAxis(),
fn(PillarRotation $b, int $v) => $b->setAxis($v)
);
$this->torchFacing = new ValueFromStringProperty(
StateNames::TORCH_FACING_DIRECTION,
$vm->torchFacing,
fn(Torch $b) => $b->getFacing(),
fn(Torch $b, int $v) => $b->setFacing($v)
);
$this->horizontalFacingSWNE = new ValueFromIntProperty(StateNames::DIRECTION, $vm->horizontalFacingSWNE, $hfGet, $hfSet);
$this->horizontalFacingSWNEInverted = new ValueFromIntProperty(StateNames::DIRECTION, $vm->horizontalFacingSWNEInverted, $hfGet, $hfSet);
$this->horizontalFacingClassic = new ValueFromIntProperty(StateNames::FACING_DIRECTION, $vm->horizontalFacingClassic, $hfGet, $hfSet);
$this->anyFacingClassic = new ValueFromIntProperty(
StateNames::FACING_DIRECTION,
$vm->facing,
fn(AnyFacing $b) => $b->getFacing(),
fn(AnyFacing $b, int $v) => $b->setFacing($v)
);
$this->multiFacingFlags = new OptionSetFromIntProperty(
StateNames::MULTI_FACE_DIRECTION_BITS,
IntFromRawStateMap::int([
Facing::DOWN => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_DOWN,
Facing::UP => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_UP,
Facing::NORTH => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_NORTH,
Facing::SOUTH => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_SOUTH,
Facing::WEST => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_WEST,
Facing::EAST => BlockLegacyMetadata::MULTI_FACE_DIRECTION_FLAG_EAST
]),
fn(MultiFacing $b) => $b->getFaces(),
fn(MultiFacing $b, array $v) => $b->setFaces($v)
);
$this->floorSignLikeRotation = new IntProperty(StateNames::GROUND_SIGN_DIRECTION, 0, 15, fn(SignLikeRotation $b) => $b->getRotation(), fn(SignLikeRotation $b, int $v) => $b->setRotation($v));
$this->analogRedstoneSignal = new IntProperty(StateNames::REDSTONE_SIGNAL, 0, 15, fn(AnalogRedstoneSignalEmitter $b) => $b->getOutputSignalStrength(), fn(AnalogRedstoneSignalEmitter $b, int $v) => $b->setOutputSignalStrength($v));
$this->cropAgeMax7 = new IntProperty(StateNames::GROWTH, 0, 7, fn(Ageable $b) => $b->getAge(), fn(Ageable $b, int $v) => $b->setAge($v));
$this->doublePlantHalf = new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePlant $b) => $b->isTop(), fn(DoublePlant $b, bool $v) => $b->setTop($v));
$fallingFlag = BlockLegacyMetadata::LIQUID_FALLING_FLAG;
$this->liquidData = new IntProperty(
StateNames::LIQUID_DEPTH,
0,
15,
fn(Liquid $b) => $b->getDecay() | ($b->isFalling() ? $fallingFlag : 0),
fn(Liquid $b, int $v) => $b->setDecay($v & ~$fallingFlag)->setFalling(($v & $fallingFlag) !== 0)
);
$this->lit = new BoolProperty(StateNames::LIT, fn(Lightable $b) => $b->isLit(), fn(Lightable $b, bool $v) => $b->setLit($v));
$this->dummyCardinalDirection = new DummyProperty(StateNames::MC_CARDINAL_DIRECTION, BlockStateStringValues::MC_CARDINAL_DIRECTION_SOUTH);
$this->dummyPillarAxis = new DummyProperty(StateNames::PILLAR_AXIS, BlockStateStringValues::PILLAR_AXIS_Y);
$this->dyeColorIdInfix = new ValueFromStringProperty("color", $vm->dyeColor, fn(Colored $b) => $b->getColor(), fn(Colored $b, DyeColor $v) => $b->setColor($v));
$this->litIdInfix = new BoolFromStringProperty("lit", "", "lit_", fn(Lightable $b) => $b->isLit(), fn(Lightable $b, bool $v) => $b->setLit($v));
$this->slabIdInfix = new BoolFromStringProperty(
"double",
"",
"double_",
fn(Slab $b) => $b->getSlabType() === SlabType::DOUBLE,
//we don't know this is actually a bottom slab yet but we don't have enough information to set the
//correct type in this handler
//BOTTOM serves as a signal value for the state deserializer to decide whether to ignore the
//upper_block_bit property
fn(Slab $b, bool $v) => $b->setSlabType($v ? SlabType::DOUBLE : SlabType::BOTTOM)
);
$this->slabPositionProperty = new BoolFromStringProperty(
StateNames::MC_VERTICAL_HALF,
BlockStateStringValues::MC_VERTICAL_HALF_BOTTOM,
BlockStateStringValues::MC_VERTICAL_HALF_TOP,
fn(Slab $b) => $b->getSlabType() === SlabType::TOP,
//Ignore the value for double slabs (should be set by ID component before this is reached)
fn(Slab $b, bool $v) => $b->getSlabType() !== SlabType::DOUBLE ? $b->setSlabType($v ? SlabType::TOP : SlabType::BOTTOM) : null
);
$this->coralIdPrefixes = [
"minecraft:",
new BoolFromStringProperty("dead", "", "dead_", fn(CoralMaterial $b) => $b->isDead(), fn(CoralMaterial $b, bool $v) => $b->setDead($v)),
new ValueFromStringProperty("type", EnumFromRawStateMap::string(CoralType::class, fn(CoralType $case) => match ($case) {
CoralType::BRAIN => "brain",
CoralType::BUBBLE => "bubble",
CoralType::FIRE => "fire",
CoralType::HORN => "horn",
CoralType::TUBE => "tube"
}), fn(CoralMaterial $b) => $b->getCoralType(), fn(CoralMaterial $b, CoralType $v) => $b->setCoralType($v)),
];
$this->copperIdPrefixes = [
"minecraft:",
new BoolFromStringProperty("waxed", "", "waxed_", fn(CopperMaterial $b) => $b->isWaxed(), fn(CopperMaterial $b, bool $v) => $b->setWaxed($v)),
new ValueFromStringProperty("oxidation", EnumFromRawStateMap::string(CopperOxidation::class, fn(CopperOxidation $case) => match ($case) {
CopperOxidation::NONE => "",
CopperOxidation::EXPOSED => "exposed_",
CopperOxidation::WEATHERED => "weathered_",
CopperOxidation::OXIDIZED => "oxidized_",
}), fn(CopperMaterial $b) => $b->getOxidation(), fn(CopperMaterial $b, CopperOxidation $v) => $b->setOxidation($v))
];
$this->furnaceIdPrefixes = ["minecraft:", $this->litIdInfix];
$this->liquidIdPrefixes = [
"minecraft:",
new BoolFromStringProperty("still", "flowing_", "", fn(Liquid $b) => $b->isStill(), fn(Liquid $b, bool $v) => $b->setStill($v))
];
$this->woodIdPrefixes = [
"minecraft:",
new BoolFromStringProperty("stripped", "", "stripped_", fn(Wood $b) => $b->isStripped(), fn(Wood $b, bool $v) => $b->setStripped($v)),
];
$this->buttonProperties = [
$this->anyFacingClassic,
new BoolProperty(StateNames::BUTTON_PRESSED_BIT, fn(Button $b) => $b->isPressed(), fn(Button $b, bool $v) => $b->setPressed($v)),
];
$this->campfireProperties = [
$this->horizontalFacingCardinal,
new BoolProperty(StateNames::EXTINGUISHED, fn(Lightable $b) => $b->isLit(), fn(Lightable $b, bool $v) => $b->setLit($v), inverted: true),
];
//TODO: check if these need any special treatment to get the appropriate data to both halves of the door
$this->doorProperties = [
new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(Door $b) => $b->isTop(), fn(Door $b, bool $v) => $b->setTop($v)),
new BoolProperty(StateNames::DOOR_HINGE_BIT, fn(Door $b) => $b->isHingeRight(), fn(Door $b, bool $v) => $b->setHingeRight($v)),
new BoolProperty(StateNames::OPEN_BIT, fn(Door $b) => $b->isOpen(), fn(Door $b, bool $v) => $b->setOpen($v)),
new ValueFromStringProperty(
StateNames::MC_CARDINAL_DIRECTION,
IntFromRawStateMap::string([
//a door facing "east" is actually facing north - thanks mojang
Facing::NORTH => BlockStateStringValues::MC_CARDINAL_DIRECTION_EAST,
Facing::EAST => BlockStateStringValues::MC_CARDINAL_DIRECTION_SOUTH,
Facing::SOUTH => BlockStateStringValues::MC_CARDINAL_DIRECTION_WEST,
Facing::WEST => BlockStateStringValues::MC_CARDINAL_DIRECTION_NORTH
]),
fn(HorizontalFacing $b) => $b->getFacing(),
fn(HorizontalFacing $b, int $v) => $b->setFacing($v)
)
];
$this->fenceGateProperties = [
new BoolProperty(StateNames::IN_WALL_BIT, fn(FenceGate $b) => $b->isInWall(), fn(FenceGate $b, bool $v) => $b->setInWall($v)),
new BoolProperty(StateNames::OPEN_BIT, fn(FenceGate $b) => $b->isOpen(), fn(FenceGate $b, bool $v) => $b->setOpen($v)),
$this->horizontalFacingCardinal,
];
$this->itemFrameProperties = [
new DummyProperty(StateNames::ITEM_FRAME_PHOTO_BIT, false), //TODO: not sure what the point of this is
new BoolProperty(StateNames::ITEM_FRAME_MAP_BIT, fn(ItemFrame $b) => $b->hasMap(), fn(ItemFrame $b, bool $v) => $b->setHasMap($v)),
$this->anyFacingClassic
];
$this->simplePressurePlateProperties = [
//TODO: not sure what the deal is here ... seems like a mojang bug / artifact of bad implementation?
//best to keep this separate from weighted plates anyway...
new IntProperty(
StateNames::REDSTONE_SIGNAL,
0,
15,
fn(SimplePressurePlate $b) => $b->isPressed() ? 15 : 0,
fn(SimplePressurePlate $b, int $v) => $b->setPressed($v !== 0)
)
];
$this->stairProperties = [
new BoolProperty(StateNames::UPSIDE_DOWN_BIT, fn(Stair $b) => $b->isUpsideDown(), fn(Stair $b, bool $v) => $b->setUpsideDown($v)),
new ValueFromIntProperty(StateNames::WEIRDO_DIRECTION, $vm->horizontalFacing5Minus, $hfGet, $hfSet),
];
$this->stemProperties = [
new ValueFromIntProperty(StateNames::FACING_DIRECTION, $vm->facingStem, fn(Stem $b) => $b->getFacing(), fn(Stem $b, int $v) => $b->setFacing($v)),
$this->cropAgeMax7
];
$this->trapdoorProperties = [
//this uses the same values as stairs, but the state is named differently
new ValueFromIntProperty(StateNames::DIRECTION, $vm->horizontalFacing5Minus, $hfGet, $hfSet),
new BoolProperty(StateNames::UPSIDE_DOWN_BIT, fn(Trapdoor $b) => $b->isTop(), fn(Trapdoor $b, bool $v) => $b->setTop($v)),
new BoolProperty(StateNames::OPEN_BIT, fn(Trapdoor $b) => $b->isOpen(), fn(Trapdoor $b, bool $v) => $b->setOpen($v)),
];
$wallProperties = [
new BoolProperty(StateNames::WALL_POST_BIT, fn(Wall $b) => $b->isPost(), fn(Wall $b, bool $v) => $b->setPost($v)),
];
foreach([
Facing::NORTH => StateNames::WALL_CONNECTION_TYPE_NORTH,
Facing::SOUTH => StateNames::WALL_CONNECTION_TYPE_SOUTH,
Facing::WEST => StateNames::WALL_CONNECTION_TYPE_WEST,
Facing::EAST => StateNames::WALL_CONNECTION_TYPE_EAST
] as $facing => $stateName){
$wallProperties[] = new ValueFromStringProperty(
$stateName,
EnumFromRawStateMap::string(WallConnectionTypeShim::class, fn(WallConnectionTypeShim $case) => $case->getValue()),
fn(Wall $b) => WallConnectionTypeShim::serialize($b->getConnection($facing)),
fn(Wall $b, WallConnectionTypeShim $v) => $b->setConnection($facing, $v->deserialize())
);
}
$this->wallProperties = $wallProperties;
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use pocketmine\utils\AssumptionFailedError;
use function is_bool;
use function is_int;
use function is_string;
/**
* @phpstan-implements Property<object>
*/
final class DummyProperty implements Property{
public function __construct(
private string $name,
private bool|int|string $value
){}
public function getName() : string{
return $this->name;
}
public function deserialize(object $block, BlockStateReader $in) : void{
$in->ignored($this->name);
}
public function serialize(object $block, BlockStateWriter $out) : void{
if(is_bool($this->value)){
$out->writeBool($this->name, $this->value);
}elseif(is_int($this->value)){
$out->writeInt($this->name, $this->value);
}elseif(is_string($this->value)){
$out->writeString($this->name, $this->value);
}else{
throw new AssumptionFailedError();
}
}
}

View File

@ -0,0 +1,109 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use function spl_object_id;
/**
* @phpstan-template TEnum of \UnitEnum
* @phpstan-template TRaw of int|string
* @phpstan-implements StateMap<TEnum, TRaw>
*/
class EnumFromRawStateMap implements StateMap{
/**
* @var int[]
* @phpstan-var array<int, TRaw>
*/
private array $enumToValue = [];
/**
* @var \UnitEnum[]
* @phpstan-var array<TRaw, TEnum>
*/
private array $valueToEnum = [];
/**
* @phpstan-param class-string<TEnum> $class
* @phpstan-param \Closure(TEnum) : TRaw $mapper
* @phpstan-param ?\Closure(TEnum) : list<TRaw> $aliasMapper
*/
public function __construct(
string $class,
\Closure $mapper,
?\Closure $aliasMapper = null
){
foreach($class::cases() as $case){
$int = $mapper($case);
$this->valueToEnum[$int] = $case;
$this->enumToValue[spl_object_id($case)] = $int;
if($aliasMapper !== null){
$aliases = $aliasMapper($case);
foreach($aliases as $alias){
$this->valueToEnum[$alias] = $case;
}
}
}
}
/**
* Workaround PHPStan too-specific literal type inference - if it ever gets fixed we can get rid of these functions
*
* @phpstan-template TEnum_ of \UnitEnum
* @phpstan-param class-string<TEnum_> $class
* @param \Closure(TEnum_) : string $mapper
* @param ?\Closure(TEnum_) : list<string> $aliasMapper
*
* @phpstan-return EnumFromRawStateMap<TEnum_, string>
*/
public static function string(string $class, \Closure $mapper, ?\Closure $aliasMapper = null) : self{ return new self($class, $mapper, $aliasMapper); }
/**
* Workaround PHPStan too-specific literal type inference - if it ever gets fixed we can get rid of these functions
*
* @phpstan-template TEnum_ of \UnitEnum
* @phpstan-param class-string<TEnum_> $class
* @param \Closure(TEnum_) : int $mapper
* @param ?\Closure(TEnum_) : list<int> $aliasMapper
*
* @phpstan-return EnumFromRawStateMap<TEnum_, int>
*/
public static function int(string $class, \Closure $mapper, ?\Closure $aliasMapper = null) : self{ return new self($class, $mapper, $aliasMapper); }
public function getRawToValueMap() : array{
return $this->valueToEnum;
}
public function valueToRaw(mixed $value) : int|string{
return $this->enumToValue[spl_object_id($value)];
}
public function rawToValue(int|string $raw) : ?\UnitEnum{
return $this->valueToEnum[$raw] ?? null;
}
public function printableValue(mixed $value) : string{
return $value::class . "::" . $value->name;
}
}

View File

@ -0,0 +1,35 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
/**
* In PM we treat head/body as a bool and berries/no berries as a second bool.
* However, Bedrock doesn't have IDs to represent a separate head/body without berries, so this enum lets us use an
* EnumFromStringProperty to deal with this using special getter/setter logic.
*/
enum FlattenedCaveVinesVariant : string{
case NO_BERRIES = "";
case HEAD_WITH_BERRIES = "_head_with_berries";
case BODY_WITH_BERRIES = "_body_with_berries";
}

View File

@ -0,0 +1,104 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use function array_flip;
use function is_array;
/**
* @phpstan-template TRaw of int|string
* @phpstan-implements StateMap<int, TRaw>
*/
class IntFromRawStateMap implements StateMap{
/**
* @var int[]
* @phpstan-var array<TRaw, int>
*/
private array $deserializeMap;
/**
* Constructs a bidirectional mapping, given a mapping of internal values -> serialized values, and an optional set
* of aliases per internal value (used for deserializing invalid serialized values).
*
* @param (int|string)[] $serializeMap
* @param (int|int[])|(string|string[]) $deserializeAliases
*
* @phpstan-param array<int, TRaw> $serializeMap
* @phpstan-param array<int, TRaw|list<TRaw>> $deserializeAliases
*/
public function __construct(
private array $serializeMap,
array $deserializeAliases = []
){
$this->deserializeMap = array_flip($this->serializeMap);
foreach($deserializeAliases as $pmValue => $mcValues){
if(!is_array($mcValues)){
$this->deserializeMap[$mcValues] = $pmValue;
}else{
foreach($mcValues as $mcValue){
$this->deserializeMap[$mcValue] = $pmValue;
}
}
}
}
/**
* @param int[] $serializeMap
* @param (int|int[]) $deserializeAliases
*
* @phpstan-param array<int, int> $serializeMap
* @phpstan-param array<int, int|list<int>> $deserializeAliases
*
* @phpstan-return self<int>
*/
public static function int(array $serializeMap, array $deserializeAliases = []) : self{ return new self($serializeMap, $deserializeAliases); }
/**
* @param string[] $serializeMap
* @param (string|string[]) $deserializeAliases
*
* @phpstan-param array<int, string> $serializeMap
* @phpstan-param array<int, string|list<string>> $deserializeAliases
*
* @phpstan-return self<string>
*/
public static function string(array $serializeMap, array $deserializeAliases = []) : self{ return new self($serializeMap, $deserializeAliases); }
public function getRawToValueMap() : array{
return $this->deserializeMap;
}
public function valueToRaw(mixed $value) : int|string{
return $this->serializeMap[$value];
}
public function rawToValue(int|string $raw) : mixed{
return $this->deserializeMap[$raw] ?? null;
}
public function printableValue(mixed $value) : string{
return "$value";
}
}

View File

@ -0,0 +1,70 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use pocketmine\utils\Limits;
/**
* @phpstan-template TBlock of object
* @phpstan-implements Property<TBlock>
*/
final class IntProperty implements Property{
/**
* @phpstan-param \Closure(TBlock) : int $getter
* @phpstan-param \Closure(TBlock, int) : mixed $setter
*/
public function __construct(
private string $name,
private int $min,
private int $max,
private \Closure $getter,
private \Closure $setter,
private int $offset = 0
){
if($min > $max){
throw new \InvalidArgumentException("Min value cannot be greater than max value");
}
}
public function getName() : string{ return $this->name; }
/**
* @phpstan-return self<object>
*/
public static function unused(string $name, int $serializedValue) : self{
return new self($name, Limits::INT32_MIN, Limits::INT32_MAX, fn() => $serializedValue, fn() => null);
}
public function deserialize(object $block, BlockStateReader $in) : void{
$value = $in->readBoundedInt($this->name, $this->min, $this->max);
($this->setter)($block, $value + $this->offset);
}
public function serialize(object $block, BlockStateWriter $out) : void{
$value = ($this->getter)($block);
$out->writeInt($this->name, $value - $this->offset);
}
}

View File

@ -0,0 +1,93 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use pocketmine\utils\AssumptionFailedError;
/**
* @phpstan-template TBlock of object
* @phpstan-template TOption of int|\UnitEnum
* @phpstan-implements Property<TBlock>
*/
class OptionSetFromIntProperty implements Property{
private int $maxValue = 0;
/**
* @phpstan-param StateMap<TOption, int> $map
* @phpstan-param \Closure(TBlock) : array<TOption> $getter
* @phpstan-param \Closure(TBlock, array<TOption>) : mixed $setter
*/
public function __construct(
private string $name,
private StateMap $map,
private \Closure $getter,
private \Closure $setter
){
$flagsToCases = $this->map->getRawToValueMap();
foreach($flagsToCases as $possibleFlag => $option){
if(($this->maxValue & $possibleFlag) !== 0){
foreach($flagsToCases as $otherFlag => $otherOption){
if(($possibleFlag & $otherFlag) === $otherFlag && $otherOption !== $option){
$printableOption = $this->map->printableValue($option);
$printableOtherOption = $this->map->printableValue($otherOption);
throw new \InvalidArgumentException("Flag for option $printableOption overlaps with flag for option $printableOtherOption in property $this->name");
}
}
throw new AssumptionFailedError("Unreachable");
}
$this->maxValue |= $possibleFlag;
}
}
public function getName() : string{ return $this->name; }
public function deserialize(object $block, BlockStateReader $in) : void{
$flags = $in->readBoundedInt($this->name, 0, $this->maxValue);
$value = [];
foreach($this->map->getRawToValueMap() as $possibleFlag => $option){
if(($flags & $possibleFlag) === $possibleFlag){
$value[] = $option;
}
}
($this->setter)($block, $value);
}
public function serialize(object $block, BlockStateWriter $out) : void{
$flags = 0;
$value = ($this->getter)($block);
foreach($value as $option){
$flags |= $this->map->valueToRaw($option);
}
$out->writeInt($this->name, $flags);
}
}

View File

@ -0,0 +1,44 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
/**
* @phpstan-template TBlock of object
*/
interface Property{
public function getName() : string;
/**
* @phpstan-param TBlock $block
*/
public function deserialize(object $block, BlockStateReader $in) : void;
/**
* @phpstan-param TBlock $block
*/
public function serialize(object $block, BlockStateWriter $out) : void;
}

View File

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
/**
* @phpstan-template TValue
* @phpstan-template TRaw of int|string
*/
interface StateMap{
/**
* @phpstan-return array<TRaw, TValue>
*/
public function getRawToValueMap() : array;
/**
* @phpstan-param TValue $value
* @phpstan-return TRaw
*/
public function valueToRaw(mixed $value) : int|string;
/**
* @phpstan-param TRaw $raw
* @phpstan-return TValue|null
*/
public function rawToValue(int|string $raw) : mixed;
/**
* @phpstan-param TValue $value
*/
public function printableValue(mixed $value) : string;
}

View File

@ -0,0 +1,50 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
/**
* @phpstan-template TBlock of object
* @phpstan-extends Property<TBlock>
*/
interface StringProperty extends Property{
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getPossibleValues() : array;
/**
* TODO: These are only used for flattened IDs for now, we should expand their use to all properties
* in the future and remove the dependencies on BlockStateReader and BlockStateWriter
* @phpstan-param TBlock $block
*/
public function deserializePlain(object $block, string $raw) : void;
/**
* TODO: These are only used for flattened IDs for now, we should expand their use to all properties
* in the future and remove the dependencies on BlockStateReader and BlockStateWriter
* @phpstan-param TBlock $block
*/
public function serializePlain(object $block) : string;
}

View File

@ -0,0 +1,75 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use function array_keys;
/**
* @phpstan-template TBlock of object
* @phpstan-template TValue of int|\UnitEnum
* @phpstan-implements Property<TBlock>
*/
final class ValueFromIntProperty implements Property{
/**
* @phpstan-param StateMap<TValue, int> $map
* @phpstan-param \Closure(TBlock) : TValue $getter
* @phpstan-param \Closure(TBlock, TValue) : mixed $setter
*/
public function __construct(
private string $name,
private StateMap $map,
private \Closure $getter,
private \Closure $setter
){}
public function getName() : string{ return $this->name; }
/**
* @return int[]
* @phpstan-return list<int>
*/
public function getPossibleValues() : array{
return array_keys($this->map->getRawToValueMap());
}
public function deserialize(object $block, BlockStateReader $in) : void{
$raw = $in->readInt($this->name);
$value = $this->map->rawToValue($raw);
if($value === null){
throw $in->badValueException($this->name, (string) $raw);
}
($this->setter)($block, $value);
}
public function serialize(object $block, BlockStateWriter $out) : void{
$value = ($this->getter)($block);
$raw = $this->map->valueToRaw($value);
$out->writeInt($this->name, $raw);
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\bedrock\block\convert\BlockStateReader;
use pocketmine\data\bedrock\block\convert\BlockStateWriter;
use function array_keys;
use function array_map;
use function strval;
/**
* @phpstan-template TBlock of object
* @phpstan-template TValue of int|\UnitEnum
* @phpstan-implements StringProperty<TBlock>
*/
final class ValueFromStringProperty implements StringProperty{
/**
* @phpstan-param StateMap<TValue, string> $map
* @phpstan-param \Closure(TBlock) : TValue $getter
* @phpstan-param \Closure(TBlock, TValue) : mixed $setter
*/
public function __construct(
private string $name,
private StateMap $map,
private \Closure $getter,
private \Closure $setter
){}
public function getName() : string{ return $this->name; }
/**
* @return string[]
* @phpstan-return list<string>
*/
public function getPossibleValues() : array{
//PHP sucks
return array_map(strval(...), array_keys($this->map->getRawToValueMap()));
}
public function deserialize(object $block, BlockStateReader $in) : void{
$this->deserializePlain($block, $in->readString($this->name));
}
public function deserializePlain(object $block, string $raw) : void{
//TODO: duplicated code from BlockStateReader :(
$value = $this->map->rawToValue($raw) ?? throw new BlockStateDeserializeException("Property \"$this->name\" has invalid value \"$raw\"");
($this->setter)($block, $value);
}
public function serialize(object $block, BlockStateWriter $out) : void{
$out->writeString($this->name, $this->serializePlain($block));
}
public function serializePlain(object $block) : string{
$value = ($this->getter)($block);
return $this->map->valueToRaw($value);
}
}

View File

@ -0,0 +1,305 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\block\Bamboo;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\DirtType;
use pocketmine\block\utils\DripleafState;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\FroglightType;
use pocketmine\block\utils\LeverFacing;
use pocketmine\block\utils\MobHeadType;
use pocketmine\block\utils\MushroomBlockType;
use pocketmine\data\bedrock\block\BlockLegacyMetadata as LegacyMeta;
use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\block\BlockTypeNames as Ids;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\utils\SingletonTrait;
final class ValueMappings{
use SingletonTrait; //???
/** @phpstan-var EnumFromRawStateMap<DyeColor, string> */
public readonly EnumFromRawStateMap $dyeColor;
/** @phpstan-var EnumFromRawStateMap<DyeColor, string> */
public readonly EnumFromRawStateMap $dyeColorWithSilver;
/** @phpstan-var EnumFromRawStateMap<MobHeadType, string> */
public readonly EnumFromRawStateMap $mobHeadType;
/** @phpstan-var EnumFromRawStateMap<FroglightType, string> */
public readonly EnumFromRawStateMap $froglightType;
/** @phpstan-var EnumFromRawStateMap<DirtType, string> */
public readonly EnumFromRawStateMap $dirtType;
/** @phpstan-var EnumFromRawStateMap<DripleafState, string> */
public readonly EnumFromRawStateMap $dripleafState;
/** @phpstan-var EnumFromRawStateMap<BellAttachmentType, string> */
public readonly EnumFromRawStateMap $bellAttachmentType;
/** @phpstan-var EnumFromRawStateMap<LeverFacing, string> */
public readonly EnumFromRawStateMap $leverFacing;
/** @phpstan-var EnumFromRawStateMap<MushroomBlockType, int> */
public readonly EnumFromRawStateMap $mushroomBlockType;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $cardinalDirection;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $blockFace;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $pillarAxis;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $torchFacing;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $portalAxis;
/** @phpstan-var IntFromRawStateMap<string> */
public readonly IntFromRawStateMap $bambooLeafSize;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $horizontalFacing5Minus;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $horizontalFacingSWNE;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $horizontalFacingSWNEInverted;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $horizontalFacingCoral;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $horizontalFacingClassic;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $facing;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $facingEndRod;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $coralAxis;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $facingExceptDown;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $facingExceptUp;
/** @phpstan-var IntFromRawStateMap<int> */
public readonly IntFromRawStateMap $facingStem;
public function __construct(){
//flattened ID components - we can't generate constants for these
$this->dyeColor = EnumFromRawStateMap::string(DyeColor::class, fn(DyeColor $case) => match ($case) {
DyeColor::BLACK => "black",
DyeColor::BLUE => "blue",
DyeColor::BROWN => "brown",
DyeColor::CYAN => "cyan",
DyeColor::GRAY => "gray",
DyeColor::GREEN => "green",
DyeColor::LIGHT_BLUE => "light_blue",
DyeColor::LIGHT_GRAY => "light_gray",
DyeColor::LIME => "lime",
DyeColor::MAGENTA => "magenta",
DyeColor::ORANGE => "orange",
DyeColor::PINK => "pink",
DyeColor::PURPLE => "purple",
DyeColor::RED => "red",
DyeColor::WHITE => "white",
DyeColor::YELLOW => "yellow"
});
$this->dyeColorWithSilver = EnumFromRawStateMap::string(DyeColor::class, fn(DyeColor $case) => match ($case) {
DyeColor::LIGHT_GRAY => "silver",
default => $this->dyeColor->valueToRaw($case)
});
$this->mobHeadType = EnumFromRawStateMap::string(MobHeadType::class, fn(MobHeadType $case) => match ($case) {
MobHeadType::CREEPER => Ids::CREEPER_HEAD,
MobHeadType::DRAGON => Ids::DRAGON_HEAD,
MobHeadType::PIGLIN => Ids::PIGLIN_HEAD,
MobHeadType::PLAYER => Ids::PLAYER_HEAD,
MobHeadType::SKELETON => Ids::SKELETON_SKULL,
MobHeadType::WITHER_SKELETON => Ids::WITHER_SKELETON_SKULL,
MobHeadType::ZOMBIE => Ids::ZOMBIE_HEAD
});
$this->froglightType = EnumFromRawStateMap::string(FroglightType::class, fn(FroglightType $case) => match ($case) {
FroglightType::OCHRE => Ids::OCHRE_FROGLIGHT,
FroglightType::PEARLESCENT => Ids::PEARLESCENT_FROGLIGHT,
FroglightType::VERDANT => Ids::VERDANT_FROGLIGHT,
});
$this->dirtType = EnumFromRawStateMap::string(DirtType::class, fn(DirtType $case) => match ($case) {
DirtType::NORMAL => Ids::DIRT,
DirtType::COARSE => Ids::COARSE_DIRT,
DirtType::ROOTED => Ids::DIRT_WITH_ROOTS,
});
//state value mappings
$this->dripleafState = EnumFromRawStateMap::string(DripleafState::class, fn(DripleafState $case) => match ($case) {
DripleafState::STABLE => StringValues::BIG_DRIPLEAF_TILT_NONE,
DripleafState::UNSTABLE => StringValues::BIG_DRIPLEAF_TILT_UNSTABLE,
DripleafState::PARTIAL_TILT => StringValues::BIG_DRIPLEAF_TILT_PARTIAL_TILT,
DripleafState::FULL_TILT => StringValues::BIG_DRIPLEAF_TILT_FULL_TILT
});
$this->bellAttachmentType = EnumFromRawStateMap::string(BellAttachmentType::class, fn(BellAttachmentType $case) => match ($case) {
BellAttachmentType::FLOOR => StringValues::ATTACHMENT_STANDING,
BellAttachmentType::CEILING => StringValues::ATTACHMENT_HANGING,
BellAttachmentType::ONE_WALL => StringValues::ATTACHMENT_SIDE,
BellAttachmentType::TWO_WALLS => StringValues::ATTACHMENT_MULTIPLE,
});
$this->leverFacing = EnumFromRawStateMap::string(LeverFacing::class, fn(LeverFacing $case) => match ($case) {
LeverFacing::DOWN_AXIS_Z => StringValues::LEVER_DIRECTION_DOWN_NORTH_SOUTH,
LeverFacing::DOWN_AXIS_X => StringValues::LEVER_DIRECTION_DOWN_EAST_WEST,
LeverFacing::UP_AXIS_Z => StringValues::LEVER_DIRECTION_UP_NORTH_SOUTH,
LeverFacing::UP_AXIS_X => StringValues::LEVER_DIRECTION_UP_EAST_WEST,
LeverFacing::NORTH => StringValues::LEVER_DIRECTION_NORTH,
LeverFacing::SOUTH => StringValues::LEVER_DIRECTION_SOUTH,
LeverFacing::WEST => StringValues::LEVER_DIRECTION_WEST,
LeverFacing::EAST => StringValues::LEVER_DIRECTION_EAST
});
$this->mushroomBlockType = EnumFromRawStateMap::int(
MushroomBlockType::class,
fn(MushroomBlockType $case) => match ($case) {
MushroomBlockType::PORES => LegacyMeta::MUSHROOM_BLOCK_ALL_PORES,
MushroomBlockType::CAP_NORTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHWEST_CORNER,
MushroomBlockType::CAP_NORTH => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTH_SIDE,
MushroomBlockType::CAP_NORTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_NORTHEAST_CORNER,
MushroomBlockType::CAP_WEST => LegacyMeta::MUSHROOM_BLOCK_CAP_WEST_SIDE,
MushroomBlockType::CAP_MIDDLE => LegacyMeta::MUSHROOM_BLOCK_CAP_TOP_ONLY,
MushroomBlockType::CAP_EAST => LegacyMeta::MUSHROOM_BLOCK_CAP_EAST_SIDE,
MushroomBlockType::CAP_SOUTHWEST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHWEST_CORNER,
MushroomBlockType::CAP_SOUTH => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTH_SIDE,
MushroomBlockType::CAP_SOUTHEAST => LegacyMeta::MUSHROOM_BLOCK_CAP_SOUTHEAST_CORNER,
MushroomBlockType::ALL_CAP => LegacyMeta::MUSHROOM_BLOCK_ALL_CAP,
},
fn(MushroomBlockType $case) => match ($case) {
MushroomBlockType::ALL_CAP => [11, 12, 13],
default => []
}
);
$this->cardinalDirection = IntFromRawStateMap::string([
Facing::NORTH => StringValues::MC_CARDINAL_DIRECTION_NORTH,
Facing::SOUTH => StringValues::MC_CARDINAL_DIRECTION_SOUTH,
Facing::WEST => StringValues::MC_CARDINAL_DIRECTION_WEST,
Facing::EAST => StringValues::MC_CARDINAL_DIRECTION_EAST,
]);
$this->blockFace = IntFromRawStateMap::string([
Facing::DOWN => StringValues::MC_BLOCK_FACE_DOWN,
Facing::UP => StringValues::MC_BLOCK_FACE_UP,
Facing::NORTH => StringValues::MC_BLOCK_FACE_NORTH,
Facing::SOUTH => StringValues::MC_BLOCK_FACE_SOUTH,
Facing::WEST => StringValues::MC_BLOCK_FACE_WEST,
Facing::EAST => StringValues::MC_BLOCK_FACE_EAST,
]);
$this->pillarAxis = IntFromRawStateMap::string([
Axis::X => StringValues::PILLAR_AXIS_X,
Axis::Y => StringValues::PILLAR_AXIS_Y,
Axis::Z => StringValues::PILLAR_AXIS_Z
]);
$this->torchFacing = IntFromRawStateMap::string([
//TODO: horizontal directions are flipped (MCPE bug: https://bugs.mojang.com/browse/MCPE-152036)
Facing::WEST => StringValues::TORCH_FACING_DIRECTION_EAST,
Facing::SOUTH => StringValues::TORCH_FACING_DIRECTION_NORTH,
Facing::NORTH => StringValues::TORCH_FACING_DIRECTION_SOUTH,
Facing::UP => StringValues::TORCH_FACING_DIRECTION_TOP,
Facing::EAST => StringValues::TORCH_FACING_DIRECTION_WEST,
], deserializeAliases: [
Facing::UP => StringValues::TORCH_FACING_DIRECTION_UNKNOWN //should be illegal, but still supported
]);
$this->portalAxis = IntFromRawStateMap::string([
Axis::X => StringValues::PORTAL_AXIS_X,
Axis::Z => StringValues::PORTAL_AXIS_Z,
], deserializeAliases: [
Axis::X => StringValues::PORTAL_AXIS_UNKNOWN,
]);
$this->bambooLeafSize = IntFromRawStateMap::string([
Bamboo::NO_LEAVES => StringValues::BAMBOO_LEAF_SIZE_NO_LEAVES,
Bamboo::SMALL_LEAVES => StringValues::BAMBOO_LEAF_SIZE_SMALL_LEAVES,
Bamboo::LARGE_LEAVES => StringValues::BAMBOO_LEAF_SIZE_LARGE_LEAVES,
]);
$this->horizontalFacing5Minus = IntFromRawStateMap::int([
Facing::EAST => 0,
Facing::WEST => 1,
Facing::SOUTH => 2,
Facing::NORTH => 3
]);
$this->horizontalFacingSWNE = IntFromRawStateMap::int([
Facing::SOUTH => 0,
Facing::WEST => 1,
Facing::NORTH => 2,
Facing::EAST => 3
]);
$this->horizontalFacingSWNEInverted = IntFromRawStateMap::int([
Facing::NORTH => 0,
Facing::EAST => 1,
Facing::SOUTH => 2,
Facing::WEST => 3,
]);
$this->horizontalFacingCoral = IntFromRawStateMap::int([
Facing::WEST => 0,
Facing::EAST => 1,
Facing::NORTH => 2,
Facing::SOUTH => 3
]);
$horizontalFacingClassicTable = [
Facing::NORTH => 2,
Facing::SOUTH => 3,
Facing::WEST => 4,
Facing::EAST => 5
];
$this->horizontalFacingClassic = IntFromRawStateMap::int($horizontalFacingClassicTable, deserializeAliases: [
Facing::NORTH => [0, 1] //should be illegal but still technically possible
]);
$this->facing = IntFromRawStateMap::int([
Facing::DOWN => 0,
Facing::UP => 1
] + $horizontalFacingClassicTable);
//end rods have all the horizontal facing values opposite to classic facing
$this->facingEndRod = IntFromRawStateMap::int([
Facing::DOWN => 0,
Facing::UP => 1,
Facing::SOUTH => 2,
Facing::NORTH => 3,
Facing::EAST => 4,
Facing::WEST => 5,
]);
$this->coralAxis = IntFromRawStateMap::int([
Axis::X => 0,
Axis::Z => 1,
]);
//TODO: shitty copy pasta job, we can do this better but this is good enough for now
$this->facingExceptDown = IntFromRawStateMap::int(
[Facing::UP => 1] + $horizontalFacingClassicTable,
deserializeAliases: [Facing::UP => 0]);
$this->facingExceptUp = IntFromRawStateMap::int(
[Facing::DOWN => 0] + $horizontalFacingClassicTable,
deserializeAliases: [Facing::DOWN => 1]
);
//In PM, we use Facing::UP to indicate that the stem is not attached to a pumpkin/melon, since this makes the
//most intuitive sense (the stem is pointing at the sky). However, Bedrock uses the DOWN state for this, which
//is absurd, and I refuse to make our API similarly absurd.
$this->facingStem = IntFromRawStateMap::int(
[Facing::UP => 0] + $horizontalFacingClassicTable,
deserializeAliases: [Facing::UP => 1]
);
}
}

View File

@ -0,0 +1,66 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\block\convert\property;
use pocketmine\block\utils\WallConnectionType;
use pocketmine\data\bedrock\block\BlockStateStringValues;
/**
* Internally we use null for no connections, but accepting this in the mapping code would require a fair amount of
* extra complexity for this one case. This shim allows us to use the regular systems for handling walls.
* TODO: get rid of this in PM6 and make the internal enum have a NONE case
*/
enum WallConnectionTypeShim{
case NONE;
case SHORT;
case TALL;
/**
* TODO: Would've just put this as enum values, but enum backing values can't reference constants in other files in
* PHP 8.1 :(
*/
public function getValue() : string{
return match($this){
self::NONE => BlockStateStringValues::WALL_CONNECTION_TYPE_EAST_NONE,
self::SHORT => BlockStateStringValues::WALL_CONNECTION_TYPE_EAST_SHORT,
self::TALL => BlockStateStringValues::WALL_CONNECTION_TYPE_EAST_TALL,
};
}
public function deserialize() : ?WallConnectionType{
return match($this){
self::NONE => null,
self::SHORT => WallConnectionType::SHORT,
self::TALL => WallConnectionType::TALL,
};
}
public static function serialize(?WallConnectionType $value) : self{
return match($value){
null => self::NONE,
WallConnectionType::SHORT => self::SHORT,
WallConnectionType::TALL => self::TALL,
};
}
}

View File

@ -26,6 +26,7 @@ namespace pocketmine\data\bedrock\item;
use pocketmine\block\Bed;
use pocketmine\block\Block;
use pocketmine\block\CopperDoor;
use pocketmine\block\tile\Banner as TileBanner;
use pocketmine\block\utils\CopperOxidation;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\VanillaBlocks as Blocks;
@ -46,6 +47,7 @@ use pocketmine\item\Potion;
use pocketmine\item\SplashPotion;
use pocketmine\item\SuspiciousStew;
use pocketmine\item\VanillaItems as Items;
use pocketmine\nbt\tag\CompoundTag;
final class ItemSerializerDeserializerRegistrar{
@ -165,6 +167,7 @@ final class ItemSerializerDeserializerRegistrar{
*/
private function register1to1ItemMappings() : void{
$this->map1to1Item(Ids::ACACIA_BOAT, Items::ACACIA_BOAT());
$this->map1to1Item(Ids::ACACIA_HANGING_SIGN, Items::ACACIA_HANGING_SIGN());
$this->map1to1Item(Ids::ACACIA_SIGN, Items::ACACIA_SIGN());
$this->map1to1Item(Ids::AMETHYST_SHARD, Items::AMETHYST_SHARD());
$this->map1to1Item(Ids::APPLE, Items::APPLE());
@ -174,6 +177,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::BEETROOT_SEEDS, Items::BEETROOT_SEEDS());
$this->map1to1Item(Ids::BEETROOT_SOUP, Items::BEETROOT_SOUP());
$this->map1to1Item(Ids::BIRCH_BOAT, Items::BIRCH_BOAT());
$this->map1to1Item(Ids::BIRCH_HANGING_SIGN, Items::BIRCH_HANGING_SIGN());
$this->map1to1Item(Ids::BIRCH_SIGN, Items::BIRCH_SIGN());
$this->map1to1Item(Ids::BLAZE_POWDER, Items::BLAZE_POWDER());
$this->map1to1Item(Ids::BLAZE_ROD, Items::BLAZE_ROD());
@ -192,6 +196,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::CHAINMAIL_HELMET, Items::CHAINMAIL_HELMET());
$this->map1to1Item(Ids::CHAINMAIL_LEGGINGS, Items::CHAINMAIL_LEGGINGS());
$this->map1to1Item(Ids::CHARCOAL, Items::CHARCOAL());
$this->map1to1Item(Ids::CHERRY_HANGING_SIGN, Items::CHERRY_HANGING_SIGN());
$this->map1to1Item(Ids::CHERRY_SIGN, Items::CHERRY_SIGN());
$this->map1to1Item(Ids::CHICKEN, Items::RAW_CHICKEN());
$this->map1to1Item(Ids::CHORUS_FRUIT, Items::CHORUS_FRUIT());
@ -211,8 +216,10 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::COOKED_SALMON, Items::COOKED_SALMON());
$this->map1to1Item(Ids::COOKIE, Items::COOKIE());
$this->map1to1Item(Ids::COPPER_INGOT, Items::COPPER_INGOT());
$this->map1to1Item(Ids::CRIMSON_HANGING_SIGN, Items::CRIMSON_HANGING_SIGN());
$this->map1to1Item(Ids::CRIMSON_SIGN, Items::CRIMSON_SIGN());
$this->map1to1Item(Ids::DARK_OAK_BOAT, Items::DARK_OAK_BOAT());
$this->map1to1Item(Ids::DARK_OAK_HANGING_SIGN, Items::DARK_OAK_HANGING_SIGN());
$this->map1to1Item(Ids::DARK_OAK_SIGN, Items::DARK_OAK_SIGN());
$this->map1to1Item(Ids::DIAMOND, Items::DIAMOND());
$this->map1to1Item(Ids::DIAMOND_AXE, Items::DIAMOND_AXE());
@ -281,6 +288,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::IRON_SHOVEL, Items::IRON_SHOVEL());
$this->map1to1Item(Ids::IRON_SWORD, Items::IRON_SWORD());
$this->map1to1Item(Ids::JUNGLE_BOAT, Items::JUNGLE_BOAT());
$this->map1to1Item(Ids::JUNGLE_HANGING_SIGN, Items::JUNGLE_HANGING_SIGN());
$this->map1to1Item(Ids::JUNGLE_SIGN, Items::JUNGLE_SIGN());
$this->map1to1Item(Ids::LAPIS_LAZULI, Items::LAPIS_LAZULI());
$this->map1to1Item(Ids::LAVA_BUCKET, Items::LAVA_BUCKET());
@ -291,6 +299,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::LEATHER_LEGGINGS, Items::LEATHER_PANTS());
$this->map1to1Item(Ids::MAGMA_CREAM, Items::MAGMA_CREAM());
$this->map1to1Item(Ids::MANGROVE_BOAT, Items::MANGROVE_BOAT());
$this->map1to1Item(Ids::MANGROVE_HANGING_SIGN, Items::MANGROVE_HANGING_SIGN());
$this->map1to1Item(Ids::MANGROVE_SIGN, Items::MANGROVE_SIGN());
$this->map1to1Item(Ids::MELON_SEEDS, Items::MELON_SEEDS());
$this->map1to1Item(Ids::MELON_SLICE, Items::MELON());
@ -334,8 +343,10 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::NETHERITE_SWORD, Items::NETHERITE_SWORD());
$this->map1to1Item(Ids::NETHERITE_UPGRADE_SMITHING_TEMPLATE, Items::NETHERITE_UPGRADE_SMITHING_TEMPLATE());
$this->map1to1Item(Ids::OAK_BOAT, Items::OAK_BOAT());
$this->map1to1Item(Ids::OAK_HANGING_SIGN, Items::OAK_HANGING_SIGN());
$this->map1to1Item(Ids::OAK_SIGN, Items::OAK_SIGN());
$this->map1to1Item(Ids::PAINTING, Items::PAINTING());
$this->map1to1Item(Ids::PALE_OAK_HANGING_SIGN, Items::PALE_OAK_HANGING_SIGN());
$this->map1to1Item(Ids::PALE_OAK_SIGN, Items::PALE_OAK_SIGN());
$this->map1to1Item(Ids::PAPER, Items::PAPER());
$this->map1to1Item(Ids::PHANTOM_MEMBRANE, Items::PHANTOM_MEMBRANE());
@ -376,6 +387,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::SPIDER_EYE, Items::SPIDER_EYE());
$this->map1to1Item(Ids::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE, Items::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE());
$this->map1to1Item(Ids::SPRUCE_BOAT, Items::SPRUCE_BOAT());
$this->map1to1Item(Ids::SPRUCE_HANGING_SIGN, Items::SPRUCE_HANGING_SIGN());
$this->map1to1Item(Ids::SPRUCE_SIGN, Items::SPRUCE_SIGN());
$this->map1to1Item(Ids::SPYGLASS, Items::SPYGLASS());
$this->map1to1Item(Ids::SQUID_SPAWN_EGG, Items::SQUID_SPAWN_EGG());
@ -396,6 +408,7 @@ final class ItemSerializerDeserializerRegistrar{
$this->map1to1Item(Ids::VEX_ARMOR_TRIM_SMITHING_TEMPLATE, Items::VEX_ARMOR_TRIM_SMITHING_TEMPLATE());
$this->map1to1Item(Ids::VILLAGER_SPAWN_EGG, Items::VILLAGER_SPAWN_EGG());
$this->map1to1Item(Ids::WARD_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WARD_ARMOR_TRIM_SMITHING_TEMPLATE());
$this->map1to1Item(Ids::WARPED_HANGING_SIGN, Items::WARPED_HANGING_SIGN());
$this->map1to1Item(Ids::WARPED_SIGN, Items::WARPED_SIGN());
$this->map1to1Item(Ids::WATER_BUCKET, Items::WATER_BUCKET());
$this->map1to1Item(Ids::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE, Items::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE());
@ -487,14 +500,6 @@ final class ItemSerializerDeserializerRegistrar{
* in a unified manner.
*/
private function register1to1ItemWithMetaMappings() : void{
$this->map1to1ItemWithMeta(
Ids::BANNER,
Items::BANNER(),
function(Banner $item, int $meta) : void{
$item->setColor(DyeColorIdMap::getInstance()->fromInvertedId($meta) ?? throw new ItemTypeDeserializeException("Unknown banner meta $meta"));
},
fn(Banner $item) => DyeColorIdMap::getInstance()->toInvertedId($item->getColor())
);
$this->map1to1ItemWithMeta(
Ids::GOAT_HORN,
Items::GOAT_HORN(),
@ -550,6 +555,21 @@ final class ItemSerializerDeserializerRegistrar{
$this->deserializer?->map($id, fn() => Items::DYE()->setColor($color));
}
$this->serializer?->map(Items::DYE(), fn(Dye $item) => new Data(DyeColorIdMap::getInstance()->toItemId($item->getColor())));
$this->deserializer?->map(Ids::BANNER, function(Data $data) : Item{
$type = $data->getTag()?->getInt(TileBanner::TAG_TYPE, TileBanner::TYPE_NORMAL) ?? TileBanner::TYPE_NORMAL;
if($type === TileBanner::TYPE_OMINOUS){
return Items::OMINOUS_BANNER();
}
$color = DyeColorIdMap::getInstance()->fromInvertedId($data->getMeta()) ?? throw new ItemTypeDeserializeException("Unknown banner meta " . $data->getMeta());
return Items::BANNER()->setColor($color);
});
$this->serializer?->map(Items::OMINOUS_BANNER(), fn() => new Data(Ids::BANNER, tag: CompoundTag::create()
->setInt(TileBanner::TAG_TYPE, TileBanner::TYPE_OMINOUS))
);
$this->serializer?->map(Items::BANNER(), function(Banner $item) : Data{
return new Data(Ids::BANNER, DyeColorIdMap::getInstance()->toInvertedId($item->getColor()));
});
}
/**

65
src/item/HangingSign.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\item;
use pocketmine\block\Block;
use pocketmine\block\utils\SupportType;
use pocketmine\math\Facing;
use pocketmine\math\Vector3;
final class HangingSign extends Item{
public function __construct(
ItemIdentifier $identifier,
string $name,
private Block $centerPointCeilingVariant,
private Block $edgePointCeilingVariant,
private Block $wallVariant
){
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 getBlock(?int $clickedFace = null) : Block{
//we don't have enough information here to decide which ceiling type to use
return $clickedFace === Facing::DOWN ? clone $this->centerPointCeilingVariant : clone $this->wallVariant;
}
public function getMaxStackSize() : int{
return 16;
}
public function getFuelTime() : int{
return 200;
}
}

View File

@ -488,6 +488,10 @@ class Item implements \JsonSerializable{
return $this->getBlock()->canBePlaced();
}
public function getPlacementBlock(Block $blockReplace, Block $blockClicked, int $face, Vector3 $clickVector) : Block{
return $this->getBlock($face);
}
/**
* Returns the block corresponding to this Item.
*/

View File

@ -334,8 +334,20 @@ final class ItemTypeIds{
public const RECORD_CREATOR = 20295;
public const RECORD_CREATOR_MUSIC_BOX = 20296;
public const RECORD_PRECIPICE = 20297;
public const OMINOUS_BANNER = 20298;
public const ACACIA_HANGING_SIGN = 20299;
public const BIRCH_HANGING_SIGN = 20300;
public const CHERRY_HANGING_SIGN = 20301;
public const CRIMSON_HANGING_SIGN = 20302;
public const DARK_OAK_HANGING_SIGN = 20303;
public const JUNGLE_HANGING_SIGN = 20304;
public const MANGROVE_HANGING_SIGN = 20305;
public const OAK_HANGING_SIGN = 20306;
public const PALE_OAK_HANGING_SIGN = 20307;
public const SPRUCE_HANGING_SIGN = 20308;
public const WARPED_HANGING_SIGN = 20309;
public const FIRST_UNUSED_ITEM_ID = 20298;
public const FIRST_UNUSED_ITEM_ID = 20310;
private static int $nextDynamicId = self::FIRST_UNUSED_ITEM_ID;

View File

@ -1232,6 +1232,7 @@ final class StringToItemParser extends StringToTParser{
private static function registerItems(self $result) : void{
$result->register("acacia_boat", fn() => Items::ACACIA_BOAT());
$result->register("acacia_hanging_sign", fn() => Items::ACACIA_HANGING_SIGN());
$result->register("amethyst_shard", fn() => Items::AMETHYST_SHARD());
$result->register("antidote", fn() => Items::MEDICINE()->setType(MedicineType::ANTIDOTE));
$result->register("apple", fn() => Items::APPLE());
@ -1246,6 +1247,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("beetroot_seeds", fn() => Items::BEETROOT_SEEDS());
$result->register("beetroot_soup", fn() => Items::BEETROOT_SOUP());
$result->register("birch_boat", fn() => Items::BIRCH_BOAT());
$result->register("birch_hanging_sign", fn() => Items::BIRCH_HANGING_SIGN());
$result->register("blaze_powder", fn() => Items::BLAZE_POWDER());
$result->register("blaze_rod", fn() => Items::BLAZE_ROD());
$result->register("bleach", fn() => Items::BLEACH());
@ -1307,6 +1309,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("chemical_sulphate", fn() => Items::CHEMICAL_SULPHATE());
$result->register("chemical_tungsten_chloride", fn() => Items::CHEMICAL_TUNGSTEN_CHLORIDE());
$result->register("chemical_water", fn() => Items::CHEMICAL_WATER());
$result->register("cherry_hanging_sign", fn() => Items::CHERRY_HANGING_SIGN());
$result->register("chicken", fn() => Items::RAW_CHICKEN());
$result->register("chorus_fruit", fn() => Items::CHORUS_FRUIT());
$result->register("chorus_fruit_popped", fn() => Items::POPPED_CHORUS_FRUIT());
@ -1331,7 +1334,9 @@ final class StringToItemParser extends StringToTParser{
$result->register("cooked_salmon", fn() => Items::COOKED_SALMON());
$result->register("cookie", fn() => Items::COOKIE());
$result->register("copper_ingot", fn() => Items::COPPER_INGOT());
$result->register("crimson_hanging_sign", fn() => Items::CRIMSON_HANGING_SIGN());
$result->register("dark_oak_boat", fn() => Items::DARK_OAK_BOAT());
$result->register("dark_oak_hanging_sign", fn() => Items::DARK_OAK_HANGING_SIGN());
$result->register("diamond", fn() => Items::DIAMOND());
$result->register("diamond_axe", fn() => Items::DIAMOND_AXE());
$result->register("diamond_boots", fn() => Items::DIAMOND_BOOTS());
@ -1416,6 +1421,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("iron_shovel", fn() => Items::IRON_SHOVEL());
$result->register("iron_sword", fn() => Items::IRON_SWORD());
$result->register("jungle_boat", fn() => Items::JUNGLE_BOAT());
$result->register("jungle_hanging_sign", fn() => Items::JUNGLE_HANGING_SIGN());
$result->register("lapis_lazuli", fn() => Items::LAPIS_LAZULI());
$result->register("lava_bucket", fn() => Items::LAVA_BUCKET());
$result->register("leather", fn() => Items::LEATHER());
@ -1427,6 +1433,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("leather_pants", fn() => Items::LEATHER_PANTS());
$result->register("leather_tunic", fn() => Items::LEATHER_TUNIC());
$result->register("magma_cream", fn() => Items::MAGMA_CREAM());
$result->register("mangrove_hanging_sign", fn() => Items::MANGROVE_HANGING_SIGN());
$result->register("melon", fn() => Items::MELON());
$result->register("melon_seeds", fn() => Items::MELON_SEEDS());
$result->register("melon_slice", fn() => Items::MELON());
@ -1458,7 +1465,9 @@ final class StringToItemParser extends StringToTParser{
$result->register("netherstar", fn() => Items::NETHER_STAR());
$result->register("netherite_upgrade_smithing_template", fn() => Items::NETHERITE_UPGRADE_SMITHING_TEMPLATE());
$result->register("oak_boat", fn() => Items::OAK_BOAT());
$result->register("oak_hanging_sign", fn() => Items::OAK_HANGING_SIGN());
$result->register("painting", fn() => Items::PAINTING());
$result->register("pale_oak_hanging_sign", fn() => Items::PALE_OAK_HANGING_SIGN());
$result->register("paper", fn() => Items::PAPER());
$result->register("phantom_membrane", fn() => Items::PHANTOM_MEMBRANE());
$result->register("pitcher_pod", fn() => Items::PITCHER_POD());
@ -1532,6 +1541,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("spire_armor_trim_smithing_template", fn() => Items::SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE());
$result->register("splash_potion", fn() => Items::SPLASH_POTION());
$result->register("spruce_boat", fn() => Items::SPRUCE_BOAT());
$result->register("spruce_hanging_sign", fn() => Items::SPRUCE_HANGING_SIGN());
$result->register("spyglass", fn() => Items::SPYGLASS());
$result->register("squid_spawn_egg", fn() => Items::SQUID_SPAWN_EGG());
$result->register("steak", fn() => Items::STEAK());
@ -1555,6 +1565,7 @@ final class StringToItemParser extends StringToTParser{
$result->register("turtle_shell_piece", fn() => Items::SCUTE());
$result->register("villager_spawn_egg", fn() => Items::VILLAGER_SPAWN_EGG());
$result->register("ward_armor_trim_smithing_template", fn() => Items::WARD_ARMOR_TRIM_SMITHING_TEMPLATE());
$result->register("warped_hanging_sign", fn() => Items::WARPED_HANGING_SIGN());
$result->register("water_bucket", fn() => Items::WATER_BUCKET());
$result->register("wayfinder_armor_trim_smithing_template", fn() => Items::WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE());
$result->register("wheat", fn() => Items::WHEAT());

View File

@ -48,6 +48,7 @@ use function strtolower;
* @generate-registry-docblock
*
* @method static Boat ACACIA_BOAT()
* @method static HangingSign ACACIA_HANGING_SIGN()
* @method static ItemBlockWallOrFloor ACACIA_SIGN()
* @method static ItemBlock AIR()
* @method static Item AMETHYST_SHARD()
@ -60,6 +61,7 @@ use function strtolower;
* @method static BeetrootSeeds BEETROOT_SEEDS()
* @method static BeetrootSoup BEETROOT_SOUP()
* @method static Boat BIRCH_BOAT()
* @method static HangingSign BIRCH_HANGING_SIGN()
* @method static ItemBlockWallOrFloor BIRCH_SIGN()
* @method static Item BLAZE_POWDER()
* @method static BlazeRod BLAZE_ROD()
@ -116,6 +118,7 @@ use function strtolower;
* @method static Item CHEMICAL_SULPHATE()
* @method static Item CHEMICAL_TUNGSTEN_CHLORIDE()
* @method static Item CHEMICAL_WATER()
* @method static HangingSign CHERRY_HANGING_SIGN()
* @method static ItemBlockWallOrFloor CHERRY_SIGN()
* @method static ChorusFruit CHORUS_FRUIT()
* @method static Item CLAY()
@ -134,8 +137,10 @@ use function strtolower;
* @method static Cookie COOKIE()
* @method static Item COPPER_INGOT()
* @method static CoralFan CORAL_FAN()
* @method static HangingSign CRIMSON_HANGING_SIGN()
* @method static ItemBlockWallOrFloor CRIMSON_SIGN()
* @method static Boat DARK_OAK_BOAT()
* @method static HangingSign DARK_OAK_HANGING_SIGN()
* @method static ItemBlockWallOrFloor DARK_OAK_SIGN()
* @method static Item DIAMOND()
* @method static Axe DIAMOND_AXE()
@ -206,6 +211,7 @@ use function strtolower;
* @method static Shovel IRON_SHOVEL()
* @method static Sword IRON_SWORD()
* @method static Boat JUNGLE_BOAT()
* @method static HangingSign JUNGLE_HANGING_SIGN()
* @method static ItemBlockWallOrFloor JUNGLE_SIGN()
* @method static Item LAPIS_LAZULI()
* @method static LiquidBucket LAVA_BUCKET()
@ -216,6 +222,7 @@ use function strtolower;
* @method static Armor LEATHER_TUNIC()
* @method static Item MAGMA_CREAM()
* @method static Boat MANGROVE_BOAT()
* @method static HangingSign MANGROVE_HANGING_SIGN()
* @method static ItemBlockWallOrFloor MANGROVE_SIGN()
* @method static Medicine MEDICINE()
* @method static Melon MELON()
@ -241,8 +248,11 @@ use function strtolower;
* @method static Item NETHER_QUARTZ()
* @method static Item NETHER_STAR()
* @method static Boat OAK_BOAT()
* @method static HangingSign OAK_HANGING_SIGN()
* @method static ItemBlockWallOrFloor OAK_SIGN()
* @method static ItemBlockWallOrFloor OMINOUS_BANNER()
* @method static PaintingItem PAINTING()
* @method static HangingSign PALE_OAK_HANGING_SIGN()
* @method static ItemBlockWallOrFloor PALE_OAK_SIGN()
* @method static Item PAPER()
* @method static Item PHANTOM_MEMBRANE()
@ -307,6 +317,7 @@ use function strtolower;
* @method static Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE()
* @method static SplashPotion SPLASH_POTION()
* @method static Boat SPRUCE_BOAT()
* @method static HangingSign SPRUCE_HANGING_SIGN()
* @method static ItemBlockWallOrFloor SPRUCE_SIGN()
* @method static Spyglass SPYGLASS()
* @method static SpawnEgg SQUID_SPAWN_EGG()
@ -328,6 +339,7 @@ use function strtolower;
* @method static Item VEX_ARMOR_TRIM_SMITHING_TEMPLATE()
* @method static SpawnEgg VILLAGER_SPAWN_EGG()
* @method static Item WARD_ARMOR_TRIM_SMITHING_TEMPLATE()
* @method static HangingSign WARPED_HANGING_SIGN()
* @method static ItemBlockWallOrFloor WARPED_SIGN()
* @method static LiquidBucket WATER_BUCKET()
* @method static Item WAYFINDER_ARMOR_TRIM_SMITHING_TEMPLATE()
@ -397,6 +409,7 @@ final class VanillaItems{
self::_registryRegister("air", Blocks::AIR()->asItem()->setCount(0));
self::register("acacia_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::ACACIA_SIGN(), Blocks::ACACIA_WALL_SIGN()));
self::register("acacia_hanging_sign", fn(IID $id) => new HangingSign($id, "Acacia Hanging Sign", Blocks::ACACIA_CEILING_CENTER_HANGING_SIGN(), Blocks::ACACIA_CEILING_EDGES_HANGING_SIGN(), Blocks::ACACIA_WALL_HANGING_SIGN()));
self::register("amethyst_shard", fn(IID $id) => new Item($id, "Amethyst Shard"));
self::register("apple", fn(IID $id) => new Apple($id, "Apple"));
self::register("arrow", fn(IID $id) => new Arrow($id, "Arrow"));
@ -407,6 +420,7 @@ final class VanillaItems{
self::register("beetroot_seeds", fn(IID $id) => new BeetrootSeeds($id, "Beetroot Seeds"));
self::register("beetroot_soup", fn(IID $id) => new BeetrootSoup($id, "Beetroot Soup"));
self::register("birch_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::BIRCH_SIGN(), Blocks::BIRCH_WALL_SIGN()));
self::register("birch_hanging_sign", fn(IID $id) => new HangingSign($id, "Birch Hanging Sign", Blocks::BIRCH_CEILING_CENTER_HANGING_SIGN(), Blocks::BIRCH_CEILING_EDGES_HANGING_SIGN(), Blocks::BIRCH_WALL_HANGING_SIGN()));
self::register("blaze_powder", fn(IID $id) => new Item($id, "Blaze Powder"));
self::register("blaze_rod", fn(IID $id) => new BlazeRod($id, "Blaze Rod"));
self::register("bleach", fn(IID $id) => new Item($id, "Bleach"));
@ -421,6 +435,7 @@ final class VanillaItems{
self::register("carrot", fn(IID $id) => new Carrot($id, "Carrot"));
self::register("charcoal", fn(IID $id) => new Coal($id, "Charcoal"));
self::register("cherry_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CHERRY_SIGN(), Blocks::CHERRY_WALL_SIGN()));
self::register("cherry_hanging_sign", fn(IID $id) => new HangingSign($id, "Cherry Hanging Sign", Blocks::CHERRY_CEILING_CENTER_HANGING_SIGN(), Blocks::CHERRY_CEILING_EDGES_HANGING_SIGN(), Blocks::CHERRY_WALL_HANGING_SIGN()));
self::register("chemical_aluminium_oxide", fn(IID $id) => new Item($id, "Aluminium Oxide"));
self::register("chemical_ammonia", fn(IID $id) => new Item($id, "Ammonia"));
self::register("chemical_barium_sulphate", fn(IID $id) => new Item($id, "Barium Sulphate"));
@ -476,7 +491,9 @@ final class VanillaItems{
self::register("copper_ingot", fn(IID $id) => new Item($id, "Copper Ingot"));
self::register("coral_fan", fn(IID $id) => new CoralFan($id));
self::register("crimson_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::CRIMSON_SIGN(), Blocks::CRIMSON_WALL_SIGN()));
self::register("crimson_hanging_sign", fn(IID $id) => new HangingSign($id, "Crimson Hanging Sign", Blocks::CRIMSON_CEILING_CENTER_HANGING_SIGN(), Blocks::CRIMSON_CEILING_EDGES_HANGING_SIGN(), Blocks::CRIMSON_WALL_HANGING_SIGN()));
self::register("dark_oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::DARK_OAK_SIGN(), Blocks::DARK_OAK_WALL_SIGN()));
self::register("dark_oak_hanging_sign", fn(IID $id) => new HangingSign($id, "Dark Oak Hanging Sign", Blocks::DARK_OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::DARK_OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::DARK_OAK_WALL_HANGING_SIGN()));
self::register("diamond", fn(IID $id) => new Item($id, "Diamond"));
self::register("disc_fragment_5", fn(IID $id) => new Item($id, "Disc Fragment (5)"));
self::register("dragon_breath", fn(IID $id) => new Item($id, "Dragon's Breath"));
@ -517,11 +534,13 @@ final class VanillaItems{
self::register("iron_ingot", fn(IID $id) => new Item($id, "Iron Ingot"));
self::register("iron_nugget", fn(IID $id) => new Item($id, "Iron Nugget"));
self::register("jungle_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::JUNGLE_SIGN(), Blocks::JUNGLE_WALL_SIGN()));
self::register("jungle_hanging_sign", fn(IID $id) => new HangingSign($id, "Jungle Hanging Sign", Blocks::JUNGLE_CEILING_CENTER_HANGING_SIGN(), Blocks::JUNGLE_CEILING_EDGES_HANGING_SIGN(), Blocks::JUNGLE_WALL_HANGING_SIGN()));
self::register("lapis_lazuli", fn(IID $id) => new Item($id, "Lapis Lazuli"));
self::register("lava_bucket", fn(IID $id) => new LiquidBucket($id, "Lava Bucket", Blocks::LAVA()));
self::register("leather", fn(IID $id) => new Item($id, "Leather"));
self::register("magma_cream", fn(IID $id) => new Item($id, "Magma Cream"));
self::register("mangrove_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::MANGROVE_SIGN(), Blocks::MANGROVE_WALL_SIGN()));
self::register("mangrove_hanging_sign", fn(IID $id) => new HangingSign($id, "Mangrove Hanging Sign", Blocks::MANGROVE_CEILING_CENTER_HANGING_SIGN(), Blocks::MANGROVE_CEILING_EDGES_HANGING_SIGN(), Blocks::MANGROVE_WALL_HANGING_SIGN()));
self::register("medicine", fn(IID $id) => new Medicine($id, "Medicine"));
self::register("melon", fn(IID $id) => new Melon($id, "Melon"));
self::register("melon_seeds", fn(IID $id) => new MelonSeeds($id, "Melon Seeds"));
@ -540,8 +559,11 @@ final class VanillaItems{
public function isFireProof() : bool{ return true; }
});
self::register("oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::OAK_SIGN(), Blocks::OAK_WALL_SIGN()));
self::register("oak_hanging_sign", fn(IID $id) => new HangingSign($id, "Oak Hanging Sign", Blocks::OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::OAK_WALL_HANGING_SIGN()));
self::register("ominous_banner", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::OMINOUS_BANNER(), Blocks::OMINOUS_WALL_BANNER()));
self::register("painting", fn(IID $id) => new PaintingItem($id, "Painting"));
self::register("pale_oak_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::PALE_OAK_SIGN(), Blocks::PALE_OAK_WALL_SIGN()));
self::register("pale_oak_hanging_sign", fn(IID $id) => new HangingSign($id, "Pale Oak Hanging Sign", Blocks::PALE_OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::PALE_OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::PALE_OAK_WALL_HANGING_SIGN()));
self::register("paper", fn(IID $id) => new Item($id, "Paper"));
self::register("phantom_membrane", fn(IID $id) => new Item($id, "Phantom Membrane"));
self::register("pitcher_pod", fn(IID $id) => new PitcherPod($id, "Pitcher Pod"));
@ -598,6 +620,7 @@ final class VanillaItems{
self::register("spider_eye", fn(IID $id) => new SpiderEye($id, "Spider Eye"));
self::register("splash_potion", fn(IID $id) => new SplashPotion($id, "Splash Potion"));
self::register("spruce_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::SPRUCE_SIGN(), Blocks::SPRUCE_WALL_SIGN()));
self::register("spruce_hanging_sign", fn(IID $id) => new HangingSign($id, "Spruce Hanging Sign", Blocks::SPRUCE_CEILING_CENTER_HANGING_SIGN(), Blocks::SPRUCE_CEILING_EDGES_HANGING_SIGN(), Blocks::SPRUCE_WALL_HANGING_SIGN()));
self::register("spyglass", fn(IID $id) => new Spyglass($id, "Spyglass"));
self::register("steak", fn(IID $id) => new Steak($id, "Steak"));
self::register("stick", fn(IID $id) => new Stick($id, "Stick"));
@ -608,6 +631,7 @@ final class VanillaItems{
self::register("torchflower_seeds", fn(IID $id) => new TorchflowerSeeds($id, "Torchflower Seeds"));
self::register("totem", fn(IID $id) => new Totem($id, "Totem of Undying"));
self::register("warped_sign", fn(IID $id) => new ItemBlockWallOrFloor($id, Blocks::WARPED_SIGN(), Blocks::WARPED_WALL_SIGN()));
self::register("warped_hanging_sign", fn(IID $id) => new HangingSign($id, "Warped Hanging Sign", Blocks::WARPED_CEILING_CENTER_HANGING_SIGN(), Blocks::WARPED_CEILING_EDGES_HANGING_SIGN(), Blocks::WARPED_WALL_HANGING_SIGN()));
self::register("water_bucket", fn(IID $id) => new LiquidBucket($id, "Water Bucket", Blocks::WATER()));
self::register("wheat", fn(IID $id) => new Item($id, "Wheat"));
self::register("wheat_seeds", fn(IID $id) => new WheatSeeds($id, "Wheat Seeds"));

View File

@ -2279,7 +2279,7 @@ class World implements ChunkManager{
if($item->isNull() || !$item->canBePlaced()){
return false;
}
$hand = $item->getBlock($face);
$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)){
@ -2959,7 +2959,7 @@ class World implements ChunkManager{
unset($this->blockCache[$chunkHash]);
unset($this->blockCollisionBoxCache[$chunkHash]);
$this->initChunk($x, $z, $chunkData);
$this->initChunk($x, $z, $chunkData, $chunk);
if(ChunkLoadEvent::hasHandlers()){
(new ChunkLoadEvent($this, $x, $z, $this->chunks[$chunkHash], false))->call();
@ -2979,7 +2979,7 @@ class World implements ChunkManager{
return $this->chunks[$chunkHash];
}
private function initChunk(int $chunkX, int $chunkZ, ChunkData $chunkData) : void{
private function initChunk(int $chunkX, int $chunkZ, ChunkData $chunkData, Chunk $chunk) : void{
$logger = new \PrefixedLogger($this->logger, "Loading chunk $chunkX $chunkZ");
if(count($chunkData->getEntityNBT()) !== 0){
@ -3044,6 +3044,16 @@ class World implements ChunkManager{
}else{
$this->addTile($tile);
}
$expectedStateId = $chunk->getBlockStateId($tilePosition->getFloorX() & Chunk::COORD_MASK, $tilePosition->getFloorY(), $tilePosition->getFloorZ() & Chunk::COORD_MASK);
$actualStateId = $this->getBlock($tilePosition)->getStateId();
if($expectedStateId !== $actualStateId){
//state ID was updated by readStateFromWorld - typically because the block pulled some data from the tile
//make sure this is synced to the chunk
//TODO: in the future we should pull tile reading logic out of readStateFromWorld() and do it only
//when the tile is loaded - this would be cleaner and faster
$chunk->setBlockStateId($tilePosition->getFloorX() & Chunk::COORD_MASK, $tilePosition->getFloorY(), $tilePosition->getFloorZ() & Chunk::COORD_MASK, $actualStateId);
$this->logger->debug("Tile " . $tile::class . " at x=$tilePosition->x,y=$tilePosition->y,z=$tilePosition->z updated block state ID from $expectedStateId to $actualStateId");
}
}
foreach(Utils::promoteKeys($deletedTiles) as $saveId => $count){

View File

@ -26,7 +26,9 @@ namespace pocketmine\world\format\io;
use pocketmine\data\bedrock\block\BlockStateData;
use pocketmine\data\bedrock\block\BlockTypeNames;
use pocketmine\data\bedrock\block\convert\BlockObjectToStateSerializer;
use pocketmine\data\bedrock\block\convert\BlockSerializerDeserializerRegistrar;
use pocketmine\data\bedrock\block\convert\BlockStateToObjectDeserializer;
use pocketmine\data\bedrock\block\convert\VanillaBlockMappings;
use pocketmine\data\bedrock\block\upgrade\BlockDataUpgrader;
use pocketmine\data\bedrock\block\upgrade\BlockIdMetaUpgrader;
use pocketmine\data\bedrock\block\upgrade\BlockStateUpgrader;
@ -44,20 +46,28 @@ use const pocketmine\BEDROCK_BLOCK_UPGRADE_SCHEMA_PATH;
* benefits for now.
*/
final class GlobalBlockStateHandlers{
private static ?BlockObjectToStateSerializer $blockStateSerializer = null;
private static ?BlockStateToObjectDeserializer $blockStateDeserializer = null;
private static ?BlockDataUpgrader $blockDataUpgrader = null;
private static ?BlockStateData $unknownBlockStateData = null;
private static ?BlockSerializerDeserializerRegistrar $registrar = null;
public static function getRegistrar() : BlockSerializerDeserializerRegistrar{
if(self::$registrar === null){
$deserializer = new BlockStateToObjectDeserializer();
$serializer = new BlockObjectToStateSerializer();
self::$registrar = new BlockSerializerDeserializerRegistrar($deserializer, $serializer);
VanillaBlockMappings::init(self::$registrar);
}
return self::$registrar;
}
public static function getDeserializer() : BlockStateToObjectDeserializer{
return self::$blockStateDeserializer ??= new BlockStateToObjectDeserializer();
return self::getRegistrar()->deserializer;
}
public static function getSerializer() : BlockObjectToStateSerializer{
return self::$blockStateSerializer ??= new BlockObjectToStateSerializer();
return self::getRegistrar()->serializer;
}
public static function getUpgrader() : BlockDataUpgrader{

View File

@ -600,6 +600,12 @@ parameters:
count: 1
path: ../../../src/crash/CrashDumpRenderer.php
-
message: '#^Parameter \#1 \$faces of method pocketmine\\block\\Vine\:\:setFaces\(\) expects list\<2\|3\|4\|5\>, array\<int\> given\.$#'
identifier: argument.type
count: 1
path: ../../../src/data/bedrock/block/convert/VanillaBlockMappings.php
-
message: '#^Parameter \#1 \$blockToItemId of class pocketmine\\data\\bedrock\\item\\BlockItemIdMap constructor expects array\<string, string\>, array\<mixed, mixed\> given\.$#'
identifier: argument.type

View File

@ -18,78 +18,138 @@ parameters:
count: 1
path: ../../../src/Server.php
-
message: '#^Method pocketmine\\block\\Block\:\:readStateFromWorld\(\) is marked as impure but does not have any side effects\.$#'
identifier: impureMethod.pure
count: 1
path: ../../../src/block/Block.php
-
message: '#^Method pocketmine\\block\\DoubleTallGrass\:\:traitGetDropsForIncompatibleTool\(\) return type has no value type specified in iterable type array\.$#'
identifier: missingType.iterableValue
count: 1
path: ../../../src/block/DoubleTallGrass.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:ACACIA_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:ACACIA_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:BIRCH_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:BIRCH_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CHERRY_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CHERRY_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CRIMSON_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:CRIMSON_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:DARK_OAK_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:DARK_OAK_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:JUNGLE_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:JUNGLE_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:MANGROVE_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:MANGROVE_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:OAK_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:OAK_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:PALE_OAK_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:PALE_OAK_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:SPRUCE_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:SPRUCE_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:WARPED_HANGING_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
count: 1
path: ../../../src/block/VanillaBlocks.php
-
message: '#^Creating callable from a non\-native static method pocketmine\\item\\VanillaItems\:\:WARPED_SIGN\(\)\.$#'
identifier: callable.nonNativeMethod
@ -252,9 +312,3 @@ parameters:
count: 2
path: ../../phpunit/promise/PromiseTest.php
-
message: '#^Strict comparison using \=\=\= between 0 and 0 will always evaluate to true\.$#'
identifier: identical.alwaysTrue
count: 1
path: ../rules/UnsafeForeachArrayWithStringKeysRule.php

View File

@ -1,6 +1,8 @@
{
"stateCounts": {
"ACACIA_BUTTON": 12,
"ACACIA_CEILING_CENTER_HANGING_SIGN": 16,
"ACACIA_CEILING_EDGES_HANGING_SIGN": 4,
"ACACIA_DOOR": 32,
"ACACIA_FENCE": 1,
"ACACIA_FENCE_GATE": 16,
@ -13,6 +15,7 @@
"ACACIA_SLAB": 3,
"ACACIA_STAIRS": 8,
"ACACIA_TRAPDOOR": 16,
"ACACIA_WALL_HANGING_SIGN": 4,
"ACACIA_WALL_SIGN": 4,
"ACACIA_WOOD": 6,
"ACTIVATOR_RAIL": 12,
@ -43,6 +46,8 @@
"BIG_DRIPLEAF_HEAD": 16,
"BIG_DRIPLEAF_STEM": 4,
"BIRCH_BUTTON": 12,
"BIRCH_CEILING_CENTER_HANGING_SIGN": 16,
"BIRCH_CEILING_EDGES_HANGING_SIGN": 4,
"BIRCH_DOOR": 32,
"BIRCH_FENCE": 1,
"BIRCH_FENCE_GATE": 16,
@ -55,6 +60,7 @@
"BIRCH_SLAB": 3,
"BIRCH_STAIRS": 8,
"BIRCH_TRAPDOOR": 16,
"BIRCH_WALL_HANGING_SIGN": 4,
"BIRCH_WALL_SIGN": 4,
"BIRCH_WOOD": 6,
"BLACKSTONE": 1,
@ -91,6 +97,8 @@
"CHAIN": 3,
"CHEMICAL_HEAT": 1,
"CHERRY_BUTTON": 12,
"CHERRY_CEILING_CENTER_HANGING_SIGN": 16,
"CHERRY_CEILING_EDGES_HANGING_SIGN": 4,
"CHERRY_DOOR": 32,
"CHERRY_FENCE": 1,
"CHERRY_FENCE_GATE": 16,
@ -102,6 +110,7 @@
"CHERRY_SLAB": 3,
"CHERRY_STAIRS": 8,
"CHERRY_TRAPDOOR": 16,
"CHERRY_WALL_HANGING_SIGN": 4,
"CHERRY_WALL_SIGN": 4,
"CHERRY_WOOD": 6,
"CHEST": 4,
@ -152,6 +161,8 @@
"CRACKED_STONE_BRICKS": 1,
"CRAFTING_TABLE": 1,
"CRIMSON_BUTTON": 12,
"CRIMSON_CEILING_CENTER_HANGING_SIGN": 16,
"CRIMSON_CEILING_EDGES_HANGING_SIGN": 4,
"CRIMSON_DOOR": 32,
"CRIMSON_FENCE": 1,
"CRIMSON_FENCE_GATE": 16,
@ -164,6 +175,7 @@
"CRIMSON_STAIRS": 8,
"CRIMSON_STEM": 6,
"CRIMSON_TRAPDOOR": 16,
"CRIMSON_WALL_HANGING_SIGN": 4,
"CRIMSON_WALL_SIGN": 4,
"CRYING_OBSIDIAN": 1,
"CUT_COPPER": 8,
@ -175,6 +187,8 @@
"CUT_SANDSTONE_SLAB": 3,
"DANDELION": 1,
"DARK_OAK_BUTTON": 12,
"DARK_OAK_CEILING_CENTER_HANGING_SIGN": 16,
"DARK_OAK_CEILING_EDGES_HANGING_SIGN": 4,
"DARK_OAK_DOOR": 32,
"DARK_OAK_FENCE": 1,
"DARK_OAK_FENCE_GATE": 16,
@ -187,6 +201,7 @@
"DARK_OAK_SLAB": 3,
"DARK_OAK_STAIRS": 8,
"DARK_OAK_TRAPDOOR": 16,
"DARK_OAK_WALL_HANGING_SIGN": 4,
"DARK_OAK_WALL_SIGN": 4,
"DARK_OAK_WOOD": 6,
"DARK_PRISMARINE": 1,
@ -409,6 +424,8 @@
"ITEM_FRAME": 12,
"JUKEBOX": 1,
"JUNGLE_BUTTON": 12,
"JUNGLE_CEILING_CENTER_HANGING_SIGN": 16,
"JUNGLE_CEILING_EDGES_HANGING_SIGN": 4,
"JUNGLE_DOOR": 32,
"JUNGLE_FENCE": 1,
"JUNGLE_FENCE_GATE": 16,
@ -421,6 +438,7 @@
"JUNGLE_SLAB": 3,
"JUNGLE_STAIRS": 8,
"JUNGLE_TRAPDOOR": 16,
"JUNGLE_WALL_HANGING_SIGN": 4,
"JUNGLE_WALL_SIGN": 4,
"JUNGLE_WOOD": 6,
"LAB_TABLE": 4,
@ -443,6 +461,8 @@
"LOOM": 4,
"MAGMA": 1,
"MANGROVE_BUTTON": 12,
"MANGROVE_CEILING_CENTER_HANGING_SIGN": 16,
"MANGROVE_CEILING_EDGES_HANGING_SIGN": 4,
"MANGROVE_DOOR": 32,
"MANGROVE_FENCE": 1,
"MANGROVE_FENCE_GATE": 16,
@ -455,6 +475,7 @@
"MANGROVE_SLAB": 3,
"MANGROVE_STAIRS": 8,
"MANGROVE_TRAPDOOR": 16,
"MANGROVE_WALL_HANGING_SIGN": 4,
"MANGROVE_WALL_SIGN": 4,
"MANGROVE_WOOD": 6,
"MATERIAL_REDUCER": 4,
@ -493,6 +514,8 @@
"NETHER_WART_BLOCK": 1,
"NOTE_BLOCK": 1,
"OAK_BUTTON": 12,
"OAK_CEILING_CENTER_HANGING_SIGN": 16,
"OAK_CEILING_EDGES_HANGING_SIGN": 4,
"OAK_DOOR": 32,
"OAK_FENCE": 1,
"OAK_FENCE_GATE": 16,
@ -505,14 +528,19 @@
"OAK_SLAB": 3,
"OAK_STAIRS": 8,
"OAK_TRAPDOOR": 16,
"OAK_WALL_HANGING_SIGN": 4,
"OAK_WALL_SIGN": 4,
"OAK_WOOD": 6,
"OBSIDIAN": 1,
"OMINOUS_BANNER": 16,
"OMINOUS_WALL_BANNER": 4,
"ORANGE_TULIP": 1,
"OXEYE_DAISY": 1,
"PACKED_ICE": 1,
"PACKED_MUD": 1,
"PALE_OAK_BUTTON": 12,
"PALE_OAK_CEILING_CENTER_HANGING_SIGN": 16,
"PALE_OAK_CEILING_EDGES_HANGING_SIGN": 4,
"PALE_OAK_DOOR": 32,
"PALE_OAK_FENCE": 1,
"PALE_OAK_FENCE_GATE": 16,
@ -524,6 +552,7 @@
"PALE_OAK_SLAB": 3,
"PALE_OAK_STAIRS": 8,
"PALE_OAK_TRAPDOOR": 16,
"PALE_OAK_WALL_HANGING_SIGN": 4,
"PALE_OAK_WALL_SIGN": 4,
"PALE_OAK_WOOD": 6,
"PEONY": 2,
@ -654,6 +683,8 @@
"SPONGE": 2,
"SPORE_BLOSSOM": 1,
"SPRUCE_BUTTON": 12,
"SPRUCE_CEILING_CENTER_HANGING_SIGN": 16,
"SPRUCE_CEILING_EDGES_HANGING_SIGN": 4,
"SPRUCE_DOOR": 32,
"SPRUCE_FENCE": 1,
"SPRUCE_FENCE_GATE": 16,
@ -666,6 +697,7 @@
"SPRUCE_SLAB": 3,
"SPRUCE_STAIRS": 8,
"SPRUCE_TRAPDOOR": 16,
"SPRUCE_WALL_HANGING_SIGN": 4,
"SPRUCE_WALL_SIGN": 4,
"SPRUCE_WOOD": 6,
"STAINED_CLAY": 16,
@ -709,6 +741,8 @@
"WALL_BANNER": 64,
"WALL_CORAL_FAN": 40,
"WARPED_BUTTON": 12,
"WARPED_CEILING_CENTER_HANGING_SIGN": 16,
"WARPED_CEILING_EDGES_HANGING_SIGN": 4,
"WARPED_DOOR": 32,
"WARPED_FENCE": 1,
"WARPED_FENCE_GATE": 16,
@ -721,6 +755,7 @@
"WARPED_STAIRS": 8,
"WARPED_STEM": 6,
"WARPED_TRAPDOOR": 16,
"WARPED_WALL_HANGING_SIGN": 4,
"WARPED_WALL_SIGN": 4,
"WARPED_WART_BLOCK": 1,
"WATER": 32,
@ -734,26 +769,41 @@
"WOOL": 16
},
"tiles": {
"ACACIA_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"ACACIA_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"ACACIA_SIGN": "pocketmine\\block\\tile\\Sign",
"ACACIA_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"ACACIA_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"BANNER": "pocketmine\\block\\tile\\Banner",
"BARREL": "pocketmine\\block\\tile\\Barrel",
"BEACON": "pocketmine\\block\\tile\\Beacon",
"BED": "pocketmine\\block\\tile\\Bed",
"BELL": "pocketmine\\block\\tile\\Bell",
"BIRCH_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"BIRCH_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"BIRCH_SIGN": "pocketmine\\block\\tile\\Sign",
"BIRCH_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"BIRCH_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"BLAST_FURNACE": "pocketmine\\block\\tile\\BlastFurnace",
"BREWING_STAND": "pocketmine\\block\\tile\\BrewingStand",
"CAMPFIRE": "pocketmine\\block\\tile\\Campfire",
"CAULDRON": "pocketmine\\block\\tile\\Cauldron",
"CHERRY_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CHERRY_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CHERRY_SIGN": "pocketmine\\block\\tile\\Sign",
"CHERRY_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CHERRY_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"CHEST": "pocketmine\\block\\tile\\Chest",
"CHISELED_BOOKSHELF": "pocketmine\\block\\tile\\ChiseledBookshelf",
"CRIMSON_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CRIMSON_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CRIMSON_SIGN": "pocketmine\\block\\tile\\Sign",
"CRIMSON_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"CRIMSON_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"DARK_OAK_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"DARK_OAK_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"DARK_OAK_SIGN": "pocketmine\\block\\tile\\Sign",
"DARK_OAK_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"DARK_OAK_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"DAYLIGHT_SENSOR": "pocketmine\\block\\tile\\DaylightSensor",
"DYED_SHULKER_BOX": "pocketmine\\block\\tile\\ShulkerBox",
@ -765,29 +815,49 @@
"HOPPER": "pocketmine\\block\\tile\\Hopper",
"ITEM_FRAME": "pocketmine\\block\\tile\\ItemFrame",
"JUKEBOX": "pocketmine\\block\\tile\\Jukebox",
"JUNGLE_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"JUNGLE_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"JUNGLE_SIGN": "pocketmine\\block\\tile\\Sign",
"JUNGLE_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"JUNGLE_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"LAVA_CAULDRON": "pocketmine\\block\\tile\\Cauldron",
"LECTERN": "pocketmine\\block\\tile\\Lectern",
"MANGROVE_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"MANGROVE_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"MANGROVE_SIGN": "pocketmine\\block\\tile\\Sign",
"MANGROVE_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"MANGROVE_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"MOB_HEAD": "pocketmine\\block\\tile\\MobHead",
"MONSTER_SPAWNER": "pocketmine\\block\\tile\\MonsterSpawner",
"NOTE_BLOCK": "pocketmine\\block\\tile\\Note",
"OAK_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"OAK_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"OAK_SIGN": "pocketmine\\block\\tile\\Sign",
"OAK_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"OAK_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"OMINOUS_BANNER": "pocketmine\\block\\tile\\Banner",
"OMINOUS_WALL_BANNER": "pocketmine\\block\\tile\\Banner",
"PALE_OAK_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"PALE_OAK_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"PALE_OAK_SIGN": "pocketmine\\block\\tile\\Sign",
"PALE_OAK_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"PALE_OAK_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"POTION_CAULDRON": "pocketmine\\block\\tile\\Cauldron",
"REDSTONE_COMPARATOR": "pocketmine\\block\\tile\\Comparator",
"SHULKER_BOX": "pocketmine\\block\\tile\\ShulkerBox",
"SMOKER": "pocketmine\\block\\tile\\Smoker",
"SOUL_CAMPFIRE": "pocketmine\\block\\tile\\Campfire",
"SPRUCE_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"SPRUCE_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"SPRUCE_SIGN": "pocketmine\\block\\tile\\Sign",
"SPRUCE_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"SPRUCE_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"TRAPPED_CHEST": "pocketmine\\block\\tile\\Chest",
"WALL_BANNER": "pocketmine\\block\\tile\\Banner",
"WARPED_CEILING_CENTER_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"WARPED_CEILING_EDGES_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"WARPED_SIGN": "pocketmine\\block\\tile\\Sign",
"WARPED_WALL_HANGING_SIGN": "pocketmine\\block\\tile\\HangingSign",
"WARPED_WALL_SIGN": "pocketmine\\block\\tile\\Sign",
"WATER_CAULDRON": "pocketmine\\block\\tile\\Cauldron"
}

View File

@ -42,6 +42,8 @@ final class BlockSerializerDeserializerTest extends TestCase{
public function setUp() : void{
$this->deserializer = new BlockStateToObjectDeserializer();
$this->serializer = new BlockObjectToStateSerializer();
$registrar = new BlockSerializerDeserializerRegistrar($this->deserializer, $this->serializer);
VanillaBlockMappings::init($registrar);
}
public function testAllKnownBlockStatesSerializableAndDeserializable() : void{
@ -49,16 +51,21 @@ final class BlockSerializerDeserializerTest extends TestCase{
try{
$blockStateData = $this->serializer->serializeBlock($block);
}catch(BlockStateSerializeException $e){
self::fail($e->getMessage());
self::fail("Failed to serialize " . $block->getName() . ": " . $e->getMessage());
}
try{
$newBlock = $this->deserializer->deserializeBlock($blockStateData);
}catch(BlockStateDeserializeException $e){
self::fail($e->getMessage());
self::fail("Failed to deserialize " . $blockStateData->getName() . ": " . $e->getMessage() . " with data " . $blockStateData->toNbt());
}
if($block->getTypeId() === BlockTypeIds::POTION_CAULDRON){
//this pretends to be a water cauldron in the blockstate, and stores its actual data in the blockentity
if(match ($block->getTypeId()) {
BlockTypeIds::POTION_CAULDRON,
BlockTypeIds::OMINOUS_BANNER,
BlockTypeIds::OMINOUS_WALL_BANNER => true,
default => false
}){
//these pretend to be something else in the blockstate, and the variant switching is done via block entity data
continue;
}