diff --git a/src/block/BaseBanner.php b/src/block/BaseBanner.php index 376f1f9dc..71a892c20 100644 --- a/src/block/BaseBanner.php +++ b/src/block/BaseBanner.php @@ -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); diff --git a/src/block/BaseOminousBanner.php b/src/block/BaseOminousBanner.php new file mode 100644 index 000000000..192e6fac2 --- /dev/null +++ b/src/block/BaseOminousBanner.php @@ -0,0 +1,90 @@ +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(); + } +} diff --git a/src/block/BaseSign.php b/src/block/BaseSign.php index 0efaa603c..b01157343 100644 --- a/src/block/BaseSign.php +++ b/src/block/BaseSign.php @@ -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); } } diff --git a/src/block/BlockTypeIds.php b/src/block/BlockTypeIds.php index 4af1894bd..e4d49746f 100644 --- a/src/block/BlockTypeIds.php +++ b/src/block/BlockTypeIds.php @@ -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; diff --git a/src/block/CeilingCenterHangingSign.php b/src/block/CeilingCenterHangingSign.php new file mode 100644 index 000000000..7078f38d8 --- /dev/null +++ b/src/block/CeilingCenterHangingSign.php @@ -0,0 +1,52 @@ +rotation = self::getRotationFromYaw($player->getLocation()->getYaw()); + } + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } +} diff --git a/src/block/CeilingEdgesHangingSign.php b/src/block/CeilingEdgesHangingSign.php new file mode 100644 index 000000000..5dafe6932 --- /dev/null +++ b/src/block/CeilingEdgesHangingSign.php @@ -0,0 +1,51 @@ +facing = Facing::opposite($player->getHorizontalFacing()); + } + + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } +} diff --git a/src/block/FloorBanner.php b/src/block/FloorBanner.php index ba089b6c0..ff57b5973 100644 --- a/src/block/FloorBanner.php +++ b/src/block/FloorBanner.php @@ -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; } diff --git a/src/block/OminousFloorBanner.php b/src/block/OminousFloorBanner.php new file mode 100644 index 000000000..240aeccfc --- /dev/null +++ b/src/block/OminousFloorBanner.php @@ -0,0 +1,53 @@ +rotation = self::getRotationFromYaw($player->getLocation()->getYaw()); + } + return parent::place($tx, $item, $blockReplace, $blockClicked, $face, $clickVector, $player); + } +} diff --git a/src/block/OminousWallBanner.php b/src/block/OminousWallBanner.php new file mode 100644 index 000000000..1eb5ba753 --- /dev/null +++ b/src/block/OminousWallBanner.php @@ -0,0 +1,49 @@ +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); + } +} diff --git a/src/block/VanillaBlocks.php b/src/block/VanillaBlocks.php index 20107d41f..435fc6215 100644 --- a/src/block/VanillaBlocks.php +++ b/src/block/VanillaBlocks.php @@ -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); } } diff --git a/src/block/WallBanner.php b/src/block/WallBanner.php index ddb157cda..b631e0c81 100644 --- a/src/block/WallBanner.php +++ b/src/block/WallBanner.php @@ -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); } diff --git a/src/block/WallHangingSign.php b/src/block/WallHangingSign.php new file mode 100644 index 000000000..c167036b1 --- /dev/null +++ b/src/block/WallHangingSign.php @@ -0,0 +1,63 @@ +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); + } +} diff --git a/src/block/tile/Banner.php b/src/block/tile/Banner.php index 08a560707..97ffe630d 100644 --- a/src/block/tile/Banner.php +++ b/src/block/tile/Banner.php @@ -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"; } diff --git a/src/block/tile/HangingSign.php b/src/block/tile/HangingSign.php new file mode 100644 index 000000000..a5be9ba5c --- /dev/null +++ b/src/block/tile/HangingSign.php @@ -0,0 +1,31 @@ +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 diff --git a/src/data/bedrock/MushroomBlockTypeIdMap.php b/src/data/bedrock/MushroomBlockTypeIdMap.php index a25336d89..6357d3e14 100644 --- a/src/data/bedrock/MushroomBlockTypeIdMap.php +++ b/src/data/bedrock/MushroomBlockTypeIdMap.php @@ -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 */ 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); } } } diff --git a/src/data/bedrock/block/BlockLegacyMetadata.php b/src/data/bedrock/block/BlockLegacyMetadata.php index e094bd3bd..d324a7ccc 100644 --- a/src/data/bedrock/block/BlockLegacyMetadata.php +++ b/src/data/bedrock/block/BlockLegacyMetadata.php @@ -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; diff --git a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php index d0a2a4d95..90f6af97a 100644 --- a/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php +++ b/src/data/bedrock/block/convert/BlockObjectToStateSerializer.php @@ -23,160 +23,17 @@ declare(strict_types=1); namespace pocketmine\data\bedrock\block\convert; -use pocketmine\block\ActivatorRail; -use pocketmine\block\AmethystCluster; -use pocketmine\block\Anvil; -use pocketmine\block\Bamboo; -use pocketmine\block\BambooSapling; -use pocketmine\block\Barrel; -use pocketmine\block\Bed; -use pocketmine\block\Beetroot; -use pocketmine\block\Bell; -use pocketmine\block\BigDripleafHead; -use pocketmine\block\BigDripleafStem; use pocketmine\block\Block; -use pocketmine\block\BoneBlock; -use pocketmine\block\BrewingStand; -use pocketmine\block\BrownMushroomBlock; -use pocketmine\block\Button; -use pocketmine\block\Cactus; -use pocketmine\block\Cake; -use pocketmine\block\CakeWithCandle; -use pocketmine\block\CakeWithDyedCandle; -use pocketmine\block\Campfire; -use pocketmine\block\Candle; -use pocketmine\block\Carrot; -use pocketmine\block\CarvedPumpkin; -use pocketmine\block\CaveVines; -use pocketmine\block\Chain; -use pocketmine\block\ChemistryTable; -use pocketmine\block\Chest; -use pocketmine\block\ChiseledBookshelf; -use pocketmine\block\ChorusFlower; -use pocketmine\block\CocoaBlock; -use pocketmine\block\Copper; -use pocketmine\block\CopperBulb; -use pocketmine\block\CopperDoor; -use pocketmine\block\CopperGrate; -use pocketmine\block\CopperSlab; -use pocketmine\block\CopperStairs; -use pocketmine\block\CopperTrapdoor; -use pocketmine\block\Coral; -use pocketmine\block\CoralBlock; -use pocketmine\block\DaylightSensor; -use pocketmine\block\DetectorRail; -use pocketmine\block\Dirt; -use pocketmine\block\Door; -use pocketmine\block\DoublePitcherCrop; -use pocketmine\block\DoublePlant; -use pocketmine\block\DoubleTallGrass; -use pocketmine\block\EnderChest; -use pocketmine\block\EndPortalFrame; -use pocketmine\block\EndRod; -use pocketmine\block\Farmland; -use pocketmine\block\FenceGate; -use pocketmine\block\FillableCauldron; -use pocketmine\block\Fire; -use pocketmine\block\FloorBanner; -use pocketmine\block\FloorCoralFan; -use pocketmine\block\FloorSign; -use pocketmine\block\Froglight; -use pocketmine\block\FrostedIce; -use pocketmine\block\Furnace; -use pocketmine\block\GlazedTerracotta; -use pocketmine\block\GlowLichen; -use pocketmine\block\HayBale; -use pocketmine\block\Hopper; -use pocketmine\block\ItemFrame; -use pocketmine\block\Ladder; -use pocketmine\block\Lantern; -use pocketmine\block\Lava; -use pocketmine\block\Leaves; -use pocketmine\block\Lectern; -use pocketmine\block\Lever; -use pocketmine\block\Light; -use pocketmine\block\LightningRod; -use pocketmine\block\LitPumpkin; -use pocketmine\block\Loom; -use pocketmine\block\MelonStem; -use pocketmine\block\MobHead; -use pocketmine\block\NetherPortal; -use pocketmine\block\NetherVines; -use pocketmine\block\NetherWartPlant; -use pocketmine\block\PinkPetals; -use pocketmine\block\PitcherCrop; -use pocketmine\block\Potato; -use pocketmine\block\PoweredRail; -use pocketmine\block\PumpkinStem; -use pocketmine\block\Rail; -use pocketmine\block\RedMushroomBlock; -use pocketmine\block\RedstoneComparator; -use pocketmine\block\RedstoneLamp; -use pocketmine\block\RedstoneOre; -use pocketmine\block\RedstoneRepeater; -use pocketmine\block\RedstoneTorch; -use pocketmine\block\RedstoneWire; -use pocketmine\block\ResinClump; -use pocketmine\block\RespawnAnchor; use pocketmine\block\RuntimeBlockStateRegistry; -use pocketmine\block\Sapling; -use pocketmine\block\SeaPickle; -use pocketmine\block\SimplePillar; -use pocketmine\block\SimplePressurePlate; use pocketmine\block\Slab; -use pocketmine\block\SmallDripleaf; -use pocketmine\block\SnowLayer; -use pocketmine\block\SoulCampfire; -use pocketmine\block\Sponge; use pocketmine\block\Stair; -use pocketmine\block\StoneButton; -use pocketmine\block\Stonecutter; -use pocketmine\block\StonePressurePlate; -use pocketmine\block\Sugarcane; -use pocketmine\block\SweetBerryBush; -use pocketmine\block\TNT; -use pocketmine\block\Torch; -use pocketmine\block\TorchflowerCrop; -use pocketmine\block\Trapdoor; -use pocketmine\block\TrappedChest; -use pocketmine\block\Tripwire; -use pocketmine\block\TripwireHook; -use pocketmine\block\UnderwaterTorch; -use pocketmine\block\utils\BrewingStandSlot; -use pocketmine\block\utils\Colored; -use pocketmine\block\utils\CoralType; -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\VanillaBlocks as Blocks; -use pocketmine\block\Vine; -use pocketmine\block\Wall; -use pocketmine\block\WallBanner; -use pocketmine\block\WallCoralFan; -use pocketmine\block\WallSign; -use pocketmine\block\Water; -use pocketmine\block\WeightedPressurePlate; -use pocketmine\block\Wheat; use pocketmine\block\Wood; -use pocketmine\block\WoodenButton; -use pocketmine\block\WoodenDoor; -use pocketmine\block\WoodenPressurePlate; -use pocketmine\block\WoodenStairs; -use pocketmine\block\WoodenTrapdoor; -use pocketmine\data\bedrock\block\BlockLegacyMetadata; use pocketmine\data\bedrock\block\BlockStateData; -use pocketmine\data\bedrock\block\BlockStateNames as StateNames; use pocketmine\data\bedrock\block\BlockStateSerializeException; use pocketmine\data\bedrock\block\BlockStateSerializer; -use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues; use pocketmine\data\bedrock\block\BlockTypeNames as Ids; use pocketmine\data\bedrock\block\convert\BlockStateSerializerHelper as Helper; use pocketmine\data\bedrock\block\convert\BlockStateWriter as Writer; -use pocketmine\math\Axis; -use pocketmine\math\Facing; use function get_class; final class BlockObjectToStateSerializer implements BlockStateSerializer{ @@ -195,20 +52,6 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ */ private array $cache = []; - public function __construct(){ - $this->registerCandleSerializers(); - $this->registerFlatColorBlockSerializers(); - $this->registerFlatCoralSerializers(); - $this->registerCauldronSerializers(); - $this->registerFlatWoodBlockSerializers(); - $this->registerLeavesSerializers(); - $this->registerSaplingSerializers(); - $this->registerMobHeadSerializers(); - $this->registerCopperSerializers(); - $this->registerSimpleSerializers(); - $this->registerSerializers(); - } - public function serialize(int $stateId) : BlockStateData{ //TODO: singleton usage not ideal //TODO: we may want to deduplicate cache entries to avoid wasting memory @@ -226,24 +69,36 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ */ public function map(Block $block, \Closure|Writer|BlockStateData $serializer) : void{ if(isset($this->serializers[$block->getTypeId()])){ - throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " already has a serializer registered"); + throw new \InvalidArgumentException("Block type ID " . $block->getTypeId() . " (" . $block->getName() . ") already has a serializer registered"); } //writer accepted for convenience only $this->serializers[$block->getTypeId()] = $serializer instanceof Writer ? $serializer->getBlockStateData() : $serializer; } + /** + * @deprecated + */ public function mapSimple(Block $block, string $id) : void{ $this->map($block, BlockStateData::current($id, [])); } + /** + * @deprecated + */ public function mapSlab(Slab $block, string $singleId, string $doubleId) : void{ $this->map($block, fn(Slab $block) => Helper::encodeSlab($block, $singleId, $doubleId)); } + /** + * @deprecated + */ public function mapStairs(Stair $block, string $id) : void{ $this->map($block, fn(Stair $block) => Helper::encodeStairs($block, Writer::create($id))); } + /** + * @deprecated + */ public function mapLog(Wood $block, string $unstrippedId, string $strippedId) : void{ $this->map($block, fn(Wood $block) => Helper::encodeLog($block, $unstrippedId, $strippedId)); } @@ -278,1451 +133,4 @@ final class BlockObjectToStateSerializer implements BlockStateSerializer{ return $result instanceof Writer ? $result->getBlockStateData() : $result; } - - /** - * @phpstan-template TBlock of Block - * @phpstan-template TEnum of \UnitEnum - * - * @phpstan-param TBlock $block - * @phpstan-param StringEnumMap $mapProperty - * @phpstan-param \Closure(TBlock) : TEnum $getProperty - * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra - */ - public function mapFlattenedEnum( - Block $block, - StringEnumMap $mapProperty, - string $prefix, - string $suffix, - \Closure $getProperty, - ?\Closure $extra = null - ) : void{ - $this->map($block, function(Block $block) use ($getProperty, $mapProperty, $prefix, $suffix, $extra) : Writer{ - $property = $getProperty($block); - $infix = $mapProperty->enumToValue($property); - $id = $prefix . $infix . $suffix; - $writer = new Writer($id); - if($extra !== null){ - $extra($block, $writer); - } - return $writer; - }); - } - - /** - * @phpstan-template TBlock of Block&Colored - * @phpstan-param TBlock $block - * @phpstan-param ?\Closure(TBlock, Writer) : Writer $extra - */ - public function mapColored( - Block $block, - string $prefix, - string $suffix, - ?\Closure $extra = null - ) : void{ - $this->mapFlattenedEnum( - $block, - ValueMappings::getInstance()->getEnumMap(DyeColor::class), - $prefix, - $suffix, - fn(Colored $block) => $block->getColor(), - $extra - ); - } - - private function registerCandleSerializers() : void{ - $this->map(Blocks::CANDLE(), fn(Candle $block) => Helper::encodeCandle($block, new Writer(Ids::CANDLE))); - $this->mapColored( - Blocks::DYED_CANDLE(), - "minecraft:", - "_candle", - Helper::encodeCandle(...) - ); - $this->map(Blocks::CAKE_WITH_CANDLE(), fn(CakeWithCandle $block) => Writer::create(Ids::CANDLE_CAKE) - ->writeBool(StateNames::LIT, $block->isLit())); - $this->mapColored( - Blocks::CAKE_WITH_DYED_CANDLE(), - "minecraft:", - "_candle_cake", - fn(CakeWithDyedCandle $block, Writer $writer) => $writer->writeBool(StateNames::LIT, $block->isLit()) - ); - } - - public function registerFlatColorBlockSerializers() : void{ - $this->mapColored(Blocks::STAINED_HARDENED_GLASS(), "minecraft:hard_", "_stained_glass"); - $this->mapColored(Blocks::STAINED_HARDENED_GLASS_PANE(), "minecraft:hard_", "_stained_glass_pane"); - - $this->mapColored(Blocks::CARPET(), "minecraft:", "_carpet"); - $this->mapColored(Blocks::CONCRETE(), "minecraft:", "_concrete"); - $this->mapColored(Blocks::CONCRETE_POWDER(), "minecraft:", "_concrete_powder"); - $this->mapColored(Blocks::DYED_SHULKER_BOX(), "minecraft:", "_shulker_box"); - $this->mapColored(Blocks::STAINED_CLAY(), "minecraft:", "_terracotta"); - $this->mapColored(Blocks::STAINED_GLASS(), "minecraft:", "_stained_glass"); - $this->mapColored(Blocks::STAINED_GLASS_PANE(), "minecraft:", "_stained_glass_pane"); - $this->mapColored(Blocks::WOOL(), "minecraft:", "_wool"); - - $this->map(Blocks::GLAZED_TERRACOTTA(), function(GlazedTerracotta $block) : Writer{ - return Writer::create(match($block->getColor()){ - DyeColor::BLACK => Ids::BLACK_GLAZED_TERRACOTTA, - DyeColor::BLUE => Ids::BLUE_GLAZED_TERRACOTTA, - DyeColor::BROWN => Ids::BROWN_GLAZED_TERRACOTTA, - DyeColor::CYAN => Ids::CYAN_GLAZED_TERRACOTTA, - DyeColor::GRAY => Ids::GRAY_GLAZED_TERRACOTTA, - DyeColor::GREEN => Ids::GREEN_GLAZED_TERRACOTTA, - DyeColor::LIGHT_BLUE => Ids::LIGHT_BLUE_GLAZED_TERRACOTTA, - DyeColor::LIGHT_GRAY => Ids::SILVER_GLAZED_TERRACOTTA, //minecraft sadness - DyeColor::LIME => Ids::LIME_GLAZED_TERRACOTTA, - DyeColor::MAGENTA => Ids::MAGENTA_GLAZED_TERRACOTTA, - DyeColor::ORANGE => Ids::ORANGE_GLAZED_TERRACOTTA, - DyeColor::PINK => Ids::PINK_GLAZED_TERRACOTTA, - DyeColor::PURPLE => Ids::PURPLE_GLAZED_TERRACOTTA, - DyeColor::RED => Ids::RED_GLAZED_TERRACOTTA, - DyeColor::WHITE => Ids::WHITE_GLAZED_TERRACOTTA, - DyeColor::YELLOW => Ids::YELLOW_GLAZED_TERRACOTTA, - }) - ->writeHorizontalFacing($block->getFacing()); - }); - } - - private function registerFlatCoralSerializers() : void{ - $this->map(Blocks::CORAL(), fn(Coral $block) => BlockStateData::current(match($block->getCoralType()){ - CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL : Ids::BRAIN_CORAL, - CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL : Ids::BUBBLE_CORAL, - CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL : Ids::FIRE_CORAL, - CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL : Ids::HORN_CORAL, - CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL : Ids::TUBE_CORAL, - }, [])); - - $this->map(Blocks::CORAL_FAN(), fn(FloorCoralFan $block) => Writer::create( - match($block->getCoralType()){ - CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_FAN : Ids::BRAIN_CORAL_FAN, - CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_FAN : Ids::BUBBLE_CORAL_FAN, - CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_FAN : Ids::FIRE_CORAL_FAN, - CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_FAN : Ids::HORN_CORAL_FAN, - CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_FAN : Ids::TUBE_CORAL_FAN, - }) - ->writeInt(StateNames::CORAL_FAN_DIRECTION, match($axis = $block->getAxis()){ - Axis::X => 0, - Axis::Z => 1, - default => throw new BlockStateSerializeException("Invalid axis {$axis}"), - })); - - $this->map(Blocks::CORAL_BLOCK(), fn(CoralBlock $block) => BlockStateData::current(match($block->getCoralType()){ - CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_BLOCK : Ids::BRAIN_CORAL_BLOCK, - CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_BLOCK : Ids::BUBBLE_CORAL_BLOCK, - CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_BLOCK : Ids::FIRE_CORAL_BLOCK, - CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_BLOCK : Ids::HORN_CORAL_BLOCK, - CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_BLOCK : Ids::TUBE_CORAL_BLOCK, - }, [])); - - $this->map(Blocks::WALL_CORAL_FAN(), fn(WallCoralFan $block) => Writer::create( - match($block->getCoralType()){ - CoralType::TUBE => $block->isDead() ? Ids::DEAD_TUBE_CORAL_WALL_FAN : Ids::TUBE_CORAL_WALL_FAN, - CoralType::BRAIN => $block->isDead() ? Ids::DEAD_BRAIN_CORAL_WALL_FAN : Ids::BRAIN_CORAL_WALL_FAN, - CoralType::BUBBLE => $block->isDead() ? Ids::DEAD_BUBBLE_CORAL_WALL_FAN : Ids::BUBBLE_CORAL_WALL_FAN, - CoralType::FIRE => $block->isDead() ? Ids::DEAD_FIRE_CORAL_WALL_FAN : Ids::FIRE_CORAL_WALL_FAN, - CoralType::HORN => $block->isDead() ? Ids::DEAD_HORN_CORAL_WALL_FAN : Ids::HORN_CORAL_WALL_FAN, - }) - ->writeCoralFacing($block->getFacing()) - ); - } - - private function registerCauldronSerializers() : void{ - $this->map(Blocks::CAULDRON(), Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, 0)); - $this->map(Blocks::LAVA_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_LAVA, $b->getFillLevel())); - //potion cauldrons store their real information in the block actor data - $this->map(Blocks::POTION_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel())); - $this->map(Blocks::WATER_CAULDRON(), fn(FillableCauldron $b) => Helper::encodeCauldron(StringValues::CAULDRON_LIQUID_WATER, $b->getFillLevel())); - } - - private function registerFlatWoodBlockSerializers() : void{ - $this->map(Blocks::ACACIA_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::ACACIA_BUTTON))); - $this->map(Blocks::ACACIA_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::ACACIA_DOOR))); - $this->map(Blocks::ACACIA_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::ACACIA_FENCE_GATE))); - $this->map(Blocks::ACACIA_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::ACACIA_PRESSURE_PLATE))); - $this->map(Blocks::ACACIA_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::ACACIA_STANDING_SIGN))); - $this->map(Blocks::ACACIA_STAIRS(), fn(WoodenStairs $block) => Helper::encodeStairs($block, new Writer(Ids::ACACIA_STAIRS))); - $this->map(Blocks::ACACIA_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::ACACIA_TRAPDOOR))); - $this->map(Blocks::ACACIA_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::ACACIA_WALL_SIGN))); - $this->mapLog(Blocks::ACACIA_LOG(), Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG); - $this->mapLog(Blocks::ACACIA_WOOD(), Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD); - $this->mapSimple(Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE); - $this->mapSimple(Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS); - $this->mapSlab(Blocks::ACACIA_SLAB(), Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB); - - $this->map(Blocks::BIRCH_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::BIRCH_BUTTON))); - $this->map(Blocks::BIRCH_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::BIRCH_DOOR))); - $this->map(Blocks::BIRCH_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::BIRCH_FENCE_GATE))); - $this->map(Blocks::BIRCH_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::BIRCH_PRESSURE_PLATE))); - $this->map(Blocks::BIRCH_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::BIRCH_STANDING_SIGN))); - $this->map(Blocks::BIRCH_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::BIRCH_TRAPDOOR))); - $this->map(Blocks::BIRCH_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::BIRCH_WALL_SIGN))); - $this->mapLog(Blocks::BIRCH_LOG(), Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG); - $this->mapLog(Blocks::BIRCH_WOOD(), Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD); - $this->mapSimple(Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE); - $this->mapSimple(Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS); - $this->mapSlab(Blocks::BIRCH_SLAB(), Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB); - $this->mapStairs(Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS); - - $this->map(Blocks::CHERRY_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CHERRY_BUTTON))); - $this->map(Blocks::CHERRY_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CHERRY_DOOR))); - $this->map(Blocks::CHERRY_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::CHERRY_FENCE_GATE))); - $this->map(Blocks::CHERRY_LOG(), fn(Wood $block) => Helper::encodeLog($block, Ids::CHERRY_LOG, Ids::STRIPPED_CHERRY_LOG)); - $this->map(Blocks::CHERRY_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::CHERRY_PRESSURE_PLATE))); - $this->map(Blocks::CHERRY_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::CHERRY_STANDING_SIGN))); - $this->map(Blocks::CHERRY_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::CHERRY_TRAPDOOR))); - $this->map(Blocks::CHERRY_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::CHERRY_WALL_SIGN))); - $this->mapSimple(Blocks::CHERRY_FENCE(), Ids::CHERRY_FENCE); - $this->mapSimple(Blocks::CHERRY_PLANKS(), Ids::CHERRY_PLANKS); - $this->mapSlab(Blocks::CHERRY_SLAB(), Ids::CHERRY_SLAB, Ids::CHERRY_DOUBLE_SLAB); - $this->mapStairs(Blocks::CHERRY_STAIRS(), Ids::CHERRY_STAIRS); - $this->mapLog(Blocks::CHERRY_WOOD(), Ids::CHERRY_WOOD, Ids::STRIPPED_CHERRY_WOOD); - - $this->map(Blocks::CRIMSON_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::CRIMSON_BUTTON))); - $this->map(Blocks::CRIMSON_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::CRIMSON_DOOR))); - $this->map(Blocks::CRIMSON_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::CRIMSON_FENCE_GATE))); - $this->map(Blocks::CRIMSON_HYPHAE(), fn(Wood $block) => Helper::encodeLog($block, Ids::CRIMSON_HYPHAE, Ids::STRIPPED_CRIMSON_HYPHAE)); - $this->map(Blocks::CRIMSON_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::CRIMSON_PRESSURE_PLATE))); - $this->map(Blocks::CRIMSON_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::CRIMSON_STANDING_SIGN))); - $this->map(Blocks::CRIMSON_STEM(), fn(Wood $block) => Helper::encodeLog($block, Ids::CRIMSON_STEM, Ids::STRIPPED_CRIMSON_STEM)); - $this->map(Blocks::CRIMSON_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::CRIMSON_TRAPDOOR))); - $this->map(Blocks::CRIMSON_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::CRIMSON_WALL_SIGN))); - $this->mapSimple(Blocks::CRIMSON_FENCE(), Ids::CRIMSON_FENCE); - $this->mapSimple(Blocks::CRIMSON_PLANKS(), Ids::CRIMSON_PLANKS); - $this->mapSlab(Blocks::CRIMSON_SLAB(), Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB); - $this->mapStairs(Blocks::CRIMSON_STAIRS(), Ids::CRIMSON_STAIRS); - - $this->map(Blocks::DARK_OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::DARK_OAK_BUTTON))); - $this->map(Blocks::DARK_OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::DARK_OAK_DOOR))); - $this->map(Blocks::DARK_OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::DARK_OAK_FENCE_GATE))); - $this->map(Blocks::DARK_OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::DARK_OAK_PRESSURE_PLATE))); - $this->map(Blocks::DARK_OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::DARKOAK_STANDING_SIGN))); - $this->map(Blocks::DARK_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::DARK_OAK_TRAPDOOR))); - $this->map(Blocks::DARK_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::DARKOAK_WALL_SIGN))); - $this->mapLog(Blocks::DARK_OAK_LOG(), Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG); - $this->mapLog(Blocks::DARK_OAK_WOOD(), Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD); - $this->mapSimple(Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE); - $this->mapSimple(Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS); - $this->mapSlab(Blocks::DARK_OAK_SLAB(), Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB); - $this->mapStairs(Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS); - - $this->map(Blocks::JUNGLE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::JUNGLE_BUTTON))); - $this->map(Blocks::JUNGLE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::JUNGLE_DOOR))); - $this->map(Blocks::JUNGLE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::JUNGLE_FENCE_GATE))); - $this->map(Blocks::JUNGLE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::JUNGLE_PRESSURE_PLATE))); - $this->map(Blocks::JUNGLE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::JUNGLE_STANDING_SIGN))); - $this->map(Blocks::JUNGLE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::JUNGLE_TRAPDOOR))); - $this->map(Blocks::JUNGLE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::JUNGLE_WALL_SIGN))); - $this->mapLog(Blocks::JUNGLE_LOG(), Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG); - $this->mapLog(Blocks::JUNGLE_WOOD(), Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD); - $this->mapSimple(Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE); - $this->mapSimple(Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS); - $this->mapSlab(Blocks::JUNGLE_SLAB(), Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB); - $this->mapStairs(Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS); - - $this->map(Blocks::MANGROVE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::MANGROVE_BUTTON))); - $this->map(Blocks::MANGROVE_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::MANGROVE_DOOR))); - $this->map(Blocks::MANGROVE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::MANGROVE_FENCE_GATE))); - $this->map(Blocks::MANGROVE_LOG(), fn(Wood $block) => Helper::encodeLog($block, Ids::MANGROVE_LOG, Ids::STRIPPED_MANGROVE_LOG)); - $this->map(Blocks::MANGROVE_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::MANGROVE_PRESSURE_PLATE))); - $this->map(Blocks::MANGROVE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::MANGROVE_STANDING_SIGN))); - $this->map(Blocks::MANGROVE_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::MANGROVE_TRAPDOOR))); - $this->map(Blocks::MANGROVE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::MANGROVE_WALL_SIGN))); - $this->mapSimple(Blocks::MANGROVE_FENCE(), Ids::MANGROVE_FENCE); - $this->mapSimple(Blocks::MANGROVE_PLANKS(), Ids::MANGROVE_PLANKS); - $this->mapSlab(Blocks::MANGROVE_SLAB(), Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB); - $this->mapStairs(Blocks::MANGROVE_STAIRS(), Ids::MANGROVE_STAIRS); - $this->mapLog(Blocks::MANGROVE_WOOD(), Ids::MANGROVE_WOOD, Ids::STRIPPED_MANGROVE_WOOD); - - $this->map(Blocks::OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::WOODEN_BUTTON))); - $this->map(Blocks::OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::WOODEN_DOOR))); - $this->map(Blocks::OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::FENCE_GATE))); - $this->map(Blocks::OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::WOODEN_PRESSURE_PLATE))); - $this->map(Blocks::OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::STANDING_SIGN))); - $this->map(Blocks::OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::TRAPDOOR))); - $this->map(Blocks::OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WALL_SIGN))); - $this->mapLog(Blocks::OAK_LOG(), Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG); - $this->mapLog(Blocks::OAK_WOOD(), Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD); - $this->mapSimple(Blocks::OAK_FENCE(), Ids::OAK_FENCE); - $this->mapSimple(Blocks::OAK_PLANKS(), Ids::OAK_PLANKS); - $this->mapSlab(Blocks::OAK_SLAB(), Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB); - $this->mapStairs(Blocks::OAK_STAIRS(), Ids::OAK_STAIRS); - - $this->map(Blocks::PALE_OAK_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::PALE_OAK_BUTTON))); - $this->map(Blocks::PALE_OAK_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::PALE_OAK_DOOR))); - $this->map(Blocks::PALE_OAK_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::PALE_OAK_FENCE_GATE))); - $this->map(Blocks::PALE_OAK_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::PALE_OAK_PRESSURE_PLATE))); - $this->map(Blocks::PALE_OAK_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::PALE_OAK_STANDING_SIGN))); - $this->map(Blocks::PALE_OAK_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::PALE_OAK_TRAPDOOR))); - $this->map(Blocks::PALE_OAK_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::PALE_OAK_WALL_SIGN))); - $this->mapLog(Blocks::PALE_OAK_LOG(), Ids::PALE_OAK_LOG, Ids::STRIPPED_PALE_OAK_LOG); - $this->mapLog(Blocks::PALE_OAK_WOOD(), Ids::PALE_OAK_WOOD, Ids::STRIPPED_PALE_OAK_WOOD); - $this->mapSimple(Blocks::PALE_OAK_FENCE(), Ids::PALE_OAK_FENCE); - $this->mapSimple(Blocks::PALE_OAK_PLANKS(), Ids::PALE_OAK_PLANKS); - $this->mapSlab(Blocks::PALE_OAK_SLAB(), Ids::PALE_OAK_SLAB, Ids::PALE_OAK_DOUBLE_SLAB); - $this->mapStairs(Blocks::PALE_OAK_STAIRS(), Ids::PALE_OAK_STAIRS); - - $this->map(Blocks::SPRUCE_BUTTON(), fn(WoodenButton $block) => Helper::encodeButton($block, new Writer(Ids::SPRUCE_BUTTON))); - $this->map(Blocks::SPRUCE_DOOR(), fn(WoodenDoor $block) => Helper::encodeDoor($block, new Writer(Ids::SPRUCE_DOOR))); - $this->map(Blocks::SPRUCE_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::SPRUCE_FENCE_GATE))); - $this->map(Blocks::SPRUCE_PRESSURE_PLATE(), fn(WoodenPressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::SPRUCE_PRESSURE_PLATE))); - $this->map(Blocks::SPRUCE_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::SPRUCE_STANDING_SIGN))); - $this->map(Blocks::SPRUCE_TRAPDOOR(), fn(WoodenTrapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::SPRUCE_TRAPDOOR))); - $this->map(Blocks::SPRUCE_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::SPRUCE_WALL_SIGN))); - $this->mapLog(Blocks::SPRUCE_LOG(), Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG); - $this->mapLog(Blocks::SPRUCE_WOOD(), Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD); - $this->mapSimple(Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE); - $this->mapSimple(Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS); - $this->mapSlab(Blocks::SPRUCE_SLAB(), Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB); - $this->mapStairs(Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS); - //wood and slabs still use the old way of storing wood type - - $this->map(Blocks::WARPED_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::WARPED_BUTTON))); - $this->map(Blocks::WARPED_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::WARPED_DOOR))); - $this->map(Blocks::WARPED_FENCE_GATE(), fn(FenceGate $block) => Helper::encodeFenceGate($block, new Writer(Ids::WARPED_FENCE_GATE))); - $this->map(Blocks::WARPED_HYPHAE(), fn(Wood $block) => Helper::encodeLog($block, Ids::WARPED_HYPHAE, Ids::STRIPPED_WARPED_HYPHAE)); - $this->map(Blocks::WARPED_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::WARPED_PRESSURE_PLATE))); - $this->map(Blocks::WARPED_SIGN(), fn(FloorSign $block) => Helper::encodeFloorSign($block, new Writer(Ids::WARPED_STANDING_SIGN))); - $this->map(Blocks::WARPED_STEM(), fn(Wood $block) => Helper::encodeLog($block, Ids::WARPED_STEM, Ids::STRIPPED_WARPED_STEM)); - $this->map(Blocks::WARPED_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::WARPED_TRAPDOOR))); - $this->map(Blocks::WARPED_WALL_SIGN(), fn(WallSign $block) => Helper::encodeWallSign($block, new Writer(Ids::WARPED_WALL_SIGN))); - $this->mapSimple(Blocks::WARPED_FENCE(), Ids::WARPED_FENCE); - $this->mapSimple(Blocks::WARPED_PLANKS(), Ids::WARPED_PLANKS); - $this->mapSlab(Blocks::WARPED_SLAB(), Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB); - $this->mapStairs(Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS); - } - - private function registerLeavesSerializers() : void{ - //flattened IDs - $this->map(Blocks::AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES))); - $this->map(Blocks::CHERRY_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::CHERRY_LEAVES))); - $this->map(Blocks::FLOWERING_AZALEA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::AZALEA_LEAVES_FLOWERED))); - $this->map(Blocks::MANGROVE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::MANGROVE_LEAVES))); - $this->map(Blocks::PALE_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::PALE_OAK_LEAVES))); - - //legacy mess - $this->map(Blocks::ACACIA_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::ACACIA_LEAVES))); - $this->map(Blocks::BIRCH_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::BIRCH_LEAVES))); - $this->map(Blocks::DARK_OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::DARK_OAK_LEAVES))); - $this->map(Blocks::JUNGLE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::JUNGLE_LEAVES))); - $this->map(Blocks::OAK_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::OAK_LEAVES))); - $this->map(Blocks::SPRUCE_LEAVES(), fn(Leaves $block) => Helper::encodeLeaves($block, new Writer(Ids::SPRUCE_LEAVES))); - } - - private function registerSaplingSerializers() : void{ - foreach([ - Ids::ACACIA_SAPLING => Blocks::ACACIA_SAPLING(), - Ids::BIRCH_SAPLING => Blocks::BIRCH_SAPLING(), - Ids::DARK_OAK_SAPLING => Blocks::DARK_OAK_SAPLING(), - Ids::JUNGLE_SAPLING => Blocks::JUNGLE_SAPLING(), - Ids::OAK_SAPLING => Blocks::OAK_SAPLING(), - Ids::SPRUCE_SAPLING => Blocks::SPRUCE_SAPLING(), - ] as $id => $block){ - $this->map($block, fn(Sapling $block) => Helper::encodeSapling($block, new Writer($id))); - } - } - - private function registerMobHeadSerializers() : void{ - $this->map(Blocks::MOB_HEAD(), fn(MobHead $block) => Writer::create(match ($block->getMobHeadType()){ - 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, - })->writeFacingWithoutDown($block->getFacing())); - } - - private function registerCopperSerializers() : void{ - $this->map(Blocks::COPPER(), function(Copper $block) : BlockStateData{ - $oxidation = $block->getOxidation(); - return BlockStateData::current( - $block->isWaxed() ? - Helper::selectCopperId($oxidation, Ids::WAXED_COPPER, Ids::WAXED_EXPOSED_COPPER, Ids::WAXED_WEATHERED_COPPER, Ids::WAXED_OXIDIZED_COPPER) : - Helper::selectCopperId($oxidation, Ids::COPPER_BLOCK, Ids::EXPOSED_COPPER, Ids::WEATHERED_COPPER, Ids::OXIDIZED_COPPER), - [] - ); - }); - $this->map(Blocks::CHISELED_COPPER(), function(Copper $block) : BlockStateData{ - $oxidation = $block->getOxidation(); - return BlockStateData::current( - $block->isWaxed() ? - Helper::selectCopperId($oxidation, - Ids::WAXED_CHISELED_COPPER, - Ids::WAXED_EXPOSED_CHISELED_COPPER, - Ids::WAXED_WEATHERED_CHISELED_COPPER, - Ids::WAXED_OXIDIZED_CHISELED_COPPER - ) : - Helper::selectCopperId($oxidation, - Ids::CHISELED_COPPER, - Ids::EXPOSED_CHISELED_COPPER, - Ids::WEATHERED_CHISELED_COPPER, - Ids::OXIDIZED_CHISELED_COPPER - ), - [] - ); - }); - $this->map(Blocks::COPPER_GRATE(), function(CopperGrate $block) : BlockStateData{ - $oxidation = $block->getOxidation(); - return BlockStateData::current( - $block->isWaxed() ? - Helper::selectCopperId($oxidation, - Ids::WAXED_COPPER_GRATE, - Ids::WAXED_EXPOSED_COPPER_GRATE, - Ids::WAXED_WEATHERED_COPPER_GRATE, - Ids::WAXED_OXIDIZED_COPPER_GRATE - ) : - Helper::selectCopperId($oxidation, - Ids::COPPER_GRATE, - Ids::EXPOSED_COPPER_GRATE, - Ids::WEATHERED_COPPER_GRATE, - Ids::OXIDIZED_COPPER_GRATE - ), - [] - ); - }); - $this->map(Blocks::CUT_COPPER(), function(Copper $block) : BlockStateData{ - $oxidation = $block->getOxidation(); - return BlockStateData::current( - $block->isWaxed() ? - Helper::selectCopperId($oxidation, Ids::WAXED_CUT_COPPER, Ids::WAXED_EXPOSED_CUT_COPPER, Ids::WAXED_WEATHERED_CUT_COPPER, Ids::WAXED_OXIDIZED_CUT_COPPER) : - Helper::selectCopperId($oxidation, Ids::CUT_COPPER, Ids::EXPOSED_CUT_COPPER, Ids::WEATHERED_CUT_COPPER, Ids::OXIDIZED_CUT_COPPER), - [] - ); - }); - $this->map(Blocks::CUT_COPPER_SLAB(), function(CopperSlab $block) : Writer{ - $oxidation = $block->getOxidation(); - return Helper::encodeSlab( - $block, - ($block->isWaxed() ? - Helper::selectCopperId( - $oxidation, - Ids::WAXED_CUT_COPPER_SLAB, - Ids::WAXED_EXPOSED_CUT_COPPER_SLAB, - Ids::WAXED_WEATHERED_CUT_COPPER_SLAB, - Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB - ) : - Helper::selectCopperId( - $oxidation, - Ids::CUT_COPPER_SLAB, - Ids::EXPOSED_CUT_COPPER_SLAB, - Ids::WEATHERED_CUT_COPPER_SLAB, - Ids::OXIDIZED_CUT_COPPER_SLAB - ) - ), - ($block->isWaxed() ? - Helper::selectCopperId( - $oxidation, - Ids::WAXED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB - ) : - Helper::selectCopperId( - $oxidation, - Ids::DOUBLE_CUT_COPPER_SLAB, - Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB, - Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB, - Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB - ) - ) - ); - }); - $this->map(Blocks::CUT_COPPER_STAIRS(), function(CopperStairs $block) : Writer{ - $oxidation = $block->getOxidation(); - return Helper::encodeStairs( - $block, - new Writer($block->isWaxed() ? - Helper::selectCopperId( - $oxidation, - Ids::WAXED_CUT_COPPER_STAIRS, - Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS, - Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS, - Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS - ) : - Helper::selectCopperId( - $oxidation, - Ids::CUT_COPPER_STAIRS, - Ids::EXPOSED_CUT_COPPER_STAIRS, - Ids::WEATHERED_CUT_COPPER_STAIRS, - Ids::OXIDIZED_CUT_COPPER_STAIRS - ) - ) - ); - }); - $this->map(Blocks::COPPER_BULB(), function(CopperBulb $block) : Writer{ - $oxidation = $block->getOxidation(); - return Writer::create($block->isWaxed() ? - Helper::selectCopperId($oxidation, - Ids::WAXED_COPPER_BULB, - Ids::WAXED_EXPOSED_COPPER_BULB, - Ids::WAXED_WEATHERED_COPPER_BULB, - Ids::WAXED_OXIDIZED_COPPER_BULB) : - Helper::selectCopperId($oxidation, - Ids::COPPER_BULB, - Ids::EXPOSED_COPPER_BULB, - Ids::WEATHERED_COPPER_BULB, - Ids::OXIDIZED_COPPER_BULB - )) - ->writeBool(StateNames::LIT, $block->isLit()) - ->writeBool(StateNames::POWERED_BIT, $block->isPowered()); - }); - $this->map(Blocks::COPPER_DOOR(), function(CopperDoor $block) : Writer{ - $oxidation = $block->getOxidation(); - return Helper::encodeDoor( - $block, - new Writer($block->isWaxed() ? - Helper::selectCopperId( - $oxidation, - Ids::WAXED_COPPER_DOOR, - Ids::WAXED_EXPOSED_COPPER_DOOR, - Ids::WAXED_WEATHERED_COPPER_DOOR, - Ids::WAXED_OXIDIZED_COPPER_DOOR - ) : - Helper::selectCopperId( - $oxidation, - Ids::COPPER_DOOR, - Ids::EXPOSED_COPPER_DOOR, - Ids::WEATHERED_COPPER_DOOR, - Ids::OXIDIZED_COPPER_DOOR - ) - ) - ); - }); - $this->map(Blocks::COPPER_TRAPDOOR(), function(CopperTrapdoor $block) : Writer{ - $oxidation = $block->getOxidation(); - return Helper::encodeTrapdoor( - $block, - new Writer($block->isWaxed() ? - Helper::selectCopperId( - $oxidation, - Ids::WAXED_COPPER_TRAPDOOR, - Ids::WAXED_EXPOSED_COPPER_TRAPDOOR, - Ids::WAXED_WEATHERED_COPPER_TRAPDOOR, - Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR - ) : - Helper::selectCopperId( - $oxidation, - Ids::COPPER_TRAPDOOR, - Ids::EXPOSED_COPPER_TRAPDOOR, - Ids::WEATHERED_COPPER_TRAPDOOR, - Ids::OXIDIZED_COPPER_TRAPDOOR - ) - ) - ); - }); - } - - private function registerSimpleSerializers() : void{ - $this->mapSimple(Blocks::AIR(), Ids::AIR); - $this->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK); - $this->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS); - $this->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE); - $this->mapSimple(Blocks::BARRIER(), Ids::BARRIER); - $this->mapSimple(Blocks::BEACON(), Ids::BEACON); - $this->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE); - $this->mapSimple(Blocks::BLUE_ICE(), Ids::BLUE_ICE); - $this->mapSimple(Blocks::BOOKSHELF(), Ids::BOOKSHELF); - $this->mapSimple(Blocks::BRICKS(), Ids::BRICK_BLOCK); - $this->mapSimple(Blocks::BROWN_MUSHROOM(), Ids::BROWN_MUSHROOM); - $this->mapSimple(Blocks::BUDDING_AMETHYST(), Ids::BUDDING_AMETHYST); - $this->mapSimple(Blocks::CALCITE(), Ids::CALCITE); - $this->mapSimple(Blocks::CARTOGRAPHY_TABLE(), Ids::CARTOGRAPHY_TABLE); - $this->mapSimple(Blocks::CHEMICAL_HEAT(), Ids::CHEMICAL_HEAT); - $this->mapSimple(Blocks::CHISELED_DEEPSLATE(), Ids::CHISELED_DEEPSLATE); - $this->mapSimple(Blocks::CHISELED_NETHER_BRICKS(), Ids::CHISELED_NETHER_BRICKS); - $this->mapSimple(Blocks::CHISELED_POLISHED_BLACKSTONE(), Ids::CHISELED_POLISHED_BLACKSTONE); - $this->mapSimple(Blocks::CHISELED_RED_SANDSTONE(), Ids::CHISELED_RED_SANDSTONE); - $this->mapSimple(Blocks::CHISELED_RESIN_BRICKS(), Ids::CHISELED_RESIN_BRICKS); - $this->mapSimple(Blocks::CHISELED_SANDSTONE(), Ids::CHISELED_SANDSTONE); - $this->mapSimple(Blocks::CHISELED_STONE_BRICKS(), Ids::CHISELED_STONE_BRICKS); - $this->mapSimple(Blocks::CHISELED_TUFF(), Ids::CHISELED_TUFF); - $this->mapSimple(Blocks::CHISELED_TUFF_BRICKS(), Ids::CHISELED_TUFF_BRICKS); - $this->mapSimple(Blocks::CHORUS_PLANT(), Ids::CHORUS_PLANT); - $this->mapSimple(Blocks::CLAY(), Ids::CLAY); - $this->mapSimple(Blocks::COAL(), Ids::COAL_BLOCK); - $this->mapSimple(Blocks::COAL_ORE(), Ids::COAL_ORE); - $this->mapSimple(Blocks::COBBLED_DEEPSLATE(), Ids::COBBLED_DEEPSLATE); - $this->mapSimple(Blocks::COBBLESTONE(), Ids::COBBLESTONE); - $this->mapSimple(Blocks::COBWEB(), Ids::WEB); - $this->mapSimple(Blocks::COPPER_ORE(), Ids::COPPER_ORE); - $this->mapSimple(Blocks::CRACKED_DEEPSLATE_BRICKS(), Ids::CRACKED_DEEPSLATE_BRICKS); - $this->mapSimple(Blocks::CRACKED_DEEPSLATE_TILES(), Ids::CRACKED_DEEPSLATE_TILES); - $this->mapSimple(Blocks::CRACKED_NETHER_BRICKS(), Ids::CRACKED_NETHER_BRICKS); - $this->mapSimple(Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS(), Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS); - $this->mapSimple(Blocks::CRACKED_STONE_BRICKS(), Ids::CRACKED_STONE_BRICKS); - $this->mapSimple(Blocks::CRAFTING_TABLE(), Ids::CRAFTING_TABLE); - $this->mapSimple(Blocks::CRIMSON_ROOTS(), Ids::CRIMSON_ROOTS); - $this->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN); - $this->mapSimple(Blocks::DANDELION(), Ids::DANDELION); - $this->mapSimple(Blocks::CUT_RED_SANDSTONE(), Ids::CUT_RED_SANDSTONE); - $this->mapSimple(Blocks::CUT_SANDSTONE(), Ids::CUT_SANDSTONE); - $this->mapSimple(Blocks::DARK_PRISMARINE(), Ids::DARK_PRISMARINE); - $this->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH); - $this->mapSimple(Blocks::DEEPSLATE_BRICKS(), Ids::DEEPSLATE_BRICKS); - $this->mapSimple(Blocks::DEEPSLATE_COAL_ORE(), Ids::DEEPSLATE_COAL_ORE); - $this->mapSimple(Blocks::DEEPSLATE_COPPER_ORE(), Ids::DEEPSLATE_COPPER_ORE); - $this->mapSimple(Blocks::DEEPSLATE_DIAMOND_ORE(), Ids::DEEPSLATE_DIAMOND_ORE); - $this->mapSimple(Blocks::DEEPSLATE_EMERALD_ORE(), Ids::DEEPSLATE_EMERALD_ORE); - $this->mapSimple(Blocks::DEEPSLATE_GOLD_ORE(), Ids::DEEPSLATE_GOLD_ORE); - $this->mapSimple(Blocks::DEEPSLATE_IRON_ORE(), Ids::DEEPSLATE_IRON_ORE); - $this->mapSimple(Blocks::DEEPSLATE_LAPIS_LAZULI_ORE(), Ids::DEEPSLATE_LAPIS_ORE); - $this->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES); - $this->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK); - $this->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE); - $this->mapSimple(Blocks::DIORITE(), Ids::DIORITE); - $this->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG); - $this->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK); - $this->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89); - $this->mapSimple(Blocks::ELEMENT_ALUMINUM(), Ids::ELEMENT_13); - $this->mapSimple(Blocks::ELEMENT_AMERICIUM(), Ids::ELEMENT_95); - $this->mapSimple(Blocks::ELEMENT_ANTIMONY(), Ids::ELEMENT_51); - $this->mapSimple(Blocks::ELEMENT_ARGON(), Ids::ELEMENT_18); - $this->mapSimple(Blocks::ELEMENT_ARSENIC(), Ids::ELEMENT_33); - $this->mapSimple(Blocks::ELEMENT_ASTATINE(), Ids::ELEMENT_85); - $this->mapSimple(Blocks::ELEMENT_BARIUM(), Ids::ELEMENT_56); - $this->mapSimple(Blocks::ELEMENT_BERKELIUM(), Ids::ELEMENT_97); - $this->mapSimple(Blocks::ELEMENT_BERYLLIUM(), Ids::ELEMENT_4); - $this->mapSimple(Blocks::ELEMENT_BISMUTH(), Ids::ELEMENT_83); - $this->mapSimple(Blocks::ELEMENT_BOHRIUM(), Ids::ELEMENT_107); - $this->mapSimple(Blocks::ELEMENT_BORON(), Ids::ELEMENT_5); - $this->mapSimple(Blocks::ELEMENT_BROMINE(), Ids::ELEMENT_35); - $this->mapSimple(Blocks::ELEMENT_CADMIUM(), Ids::ELEMENT_48); - $this->mapSimple(Blocks::ELEMENT_CALCIUM(), Ids::ELEMENT_20); - $this->mapSimple(Blocks::ELEMENT_CALIFORNIUM(), Ids::ELEMENT_98); - $this->mapSimple(Blocks::ELEMENT_CARBON(), Ids::ELEMENT_6); - $this->mapSimple(Blocks::ELEMENT_CERIUM(), Ids::ELEMENT_58); - $this->mapSimple(Blocks::ELEMENT_CESIUM(), Ids::ELEMENT_55); - $this->mapSimple(Blocks::ELEMENT_CHLORINE(), Ids::ELEMENT_17); - $this->mapSimple(Blocks::ELEMENT_CHROMIUM(), Ids::ELEMENT_24); - $this->mapSimple(Blocks::ELEMENT_COBALT(), Ids::ELEMENT_27); - $this->mapSimple(Blocks::ELEMENT_COPERNICIUM(), Ids::ELEMENT_112); - $this->mapSimple(Blocks::ELEMENT_COPPER(), Ids::ELEMENT_29); - $this->mapSimple(Blocks::ELEMENT_CURIUM(), Ids::ELEMENT_96); - $this->mapSimple(Blocks::ELEMENT_DARMSTADTIUM(), Ids::ELEMENT_110); - $this->mapSimple(Blocks::ELEMENT_DUBNIUM(), Ids::ELEMENT_105); - $this->mapSimple(Blocks::ELEMENT_DYSPROSIUM(), Ids::ELEMENT_66); - $this->mapSimple(Blocks::ELEMENT_EINSTEINIUM(), Ids::ELEMENT_99); - $this->mapSimple(Blocks::ELEMENT_ERBIUM(), Ids::ELEMENT_68); - $this->mapSimple(Blocks::ELEMENT_EUROPIUM(), Ids::ELEMENT_63); - $this->mapSimple(Blocks::ELEMENT_FERMIUM(), Ids::ELEMENT_100); - $this->mapSimple(Blocks::ELEMENT_FLEROVIUM(), Ids::ELEMENT_114); - $this->mapSimple(Blocks::ELEMENT_FLUORINE(), Ids::ELEMENT_9); - $this->mapSimple(Blocks::ELEMENT_FRANCIUM(), Ids::ELEMENT_87); - $this->mapSimple(Blocks::ELEMENT_GADOLINIUM(), Ids::ELEMENT_64); - $this->mapSimple(Blocks::ELEMENT_GALLIUM(), Ids::ELEMENT_31); - $this->mapSimple(Blocks::ELEMENT_GERMANIUM(), Ids::ELEMENT_32); - $this->mapSimple(Blocks::ELEMENT_GOLD(), Ids::ELEMENT_79); - $this->mapSimple(Blocks::ELEMENT_HAFNIUM(), Ids::ELEMENT_72); - $this->mapSimple(Blocks::ELEMENT_HASSIUM(), Ids::ELEMENT_108); - $this->mapSimple(Blocks::ELEMENT_HELIUM(), Ids::ELEMENT_2); - $this->mapSimple(Blocks::ELEMENT_HOLMIUM(), Ids::ELEMENT_67); - $this->mapSimple(Blocks::ELEMENT_HYDROGEN(), Ids::ELEMENT_1); - $this->mapSimple(Blocks::ELEMENT_INDIUM(), Ids::ELEMENT_49); - $this->mapSimple(Blocks::ELEMENT_IODINE(), Ids::ELEMENT_53); - $this->mapSimple(Blocks::ELEMENT_IRIDIUM(), Ids::ELEMENT_77); - $this->mapSimple(Blocks::ELEMENT_IRON(), Ids::ELEMENT_26); - $this->mapSimple(Blocks::ELEMENT_KRYPTON(), Ids::ELEMENT_36); - $this->mapSimple(Blocks::ELEMENT_LANTHANUM(), Ids::ELEMENT_57); - $this->mapSimple(Blocks::ELEMENT_LAWRENCIUM(), Ids::ELEMENT_103); - $this->mapSimple(Blocks::ELEMENT_LEAD(), Ids::ELEMENT_82); - $this->mapSimple(Blocks::ELEMENT_LITHIUM(), Ids::ELEMENT_3); - $this->mapSimple(Blocks::ELEMENT_LIVERMORIUM(), Ids::ELEMENT_116); - $this->mapSimple(Blocks::ELEMENT_LUTETIUM(), Ids::ELEMENT_71); - $this->mapSimple(Blocks::ELEMENT_MAGNESIUM(), Ids::ELEMENT_12); - $this->mapSimple(Blocks::ELEMENT_MANGANESE(), Ids::ELEMENT_25); - $this->mapSimple(Blocks::ELEMENT_MEITNERIUM(), Ids::ELEMENT_109); - $this->mapSimple(Blocks::ELEMENT_MENDELEVIUM(), Ids::ELEMENT_101); - $this->mapSimple(Blocks::ELEMENT_MERCURY(), Ids::ELEMENT_80); - $this->mapSimple(Blocks::ELEMENT_MOLYBDENUM(), Ids::ELEMENT_42); - $this->mapSimple(Blocks::ELEMENT_MOSCOVIUM(), Ids::ELEMENT_115); - $this->mapSimple(Blocks::ELEMENT_NEODYMIUM(), Ids::ELEMENT_60); - $this->mapSimple(Blocks::ELEMENT_NEON(), Ids::ELEMENT_10); - $this->mapSimple(Blocks::ELEMENT_NEPTUNIUM(), Ids::ELEMENT_93); - $this->mapSimple(Blocks::ELEMENT_NICKEL(), Ids::ELEMENT_28); - $this->mapSimple(Blocks::ELEMENT_NIHONIUM(), Ids::ELEMENT_113); - $this->mapSimple(Blocks::ELEMENT_NIOBIUM(), Ids::ELEMENT_41); - $this->mapSimple(Blocks::ELEMENT_NITROGEN(), Ids::ELEMENT_7); - $this->mapSimple(Blocks::ELEMENT_NOBELIUM(), Ids::ELEMENT_102); - $this->mapSimple(Blocks::ELEMENT_OGANESSON(), Ids::ELEMENT_118); - $this->mapSimple(Blocks::ELEMENT_OSMIUM(), Ids::ELEMENT_76); - $this->mapSimple(Blocks::ELEMENT_OXYGEN(), Ids::ELEMENT_8); - $this->mapSimple(Blocks::ELEMENT_PALLADIUM(), Ids::ELEMENT_46); - $this->mapSimple(Blocks::ELEMENT_PHOSPHORUS(), Ids::ELEMENT_15); - $this->mapSimple(Blocks::ELEMENT_PLATINUM(), Ids::ELEMENT_78); - $this->mapSimple(Blocks::ELEMENT_PLUTONIUM(), Ids::ELEMENT_94); - $this->mapSimple(Blocks::ELEMENT_POLONIUM(), Ids::ELEMENT_84); - $this->mapSimple(Blocks::ELEMENT_POTASSIUM(), Ids::ELEMENT_19); - $this->mapSimple(Blocks::ELEMENT_PRASEODYMIUM(), Ids::ELEMENT_59); - $this->mapSimple(Blocks::ELEMENT_PROMETHIUM(), Ids::ELEMENT_61); - $this->mapSimple(Blocks::ELEMENT_PROTACTINIUM(), Ids::ELEMENT_91); - $this->mapSimple(Blocks::ELEMENT_RADIUM(), Ids::ELEMENT_88); - $this->mapSimple(Blocks::ELEMENT_RADON(), Ids::ELEMENT_86); - $this->mapSimple(Blocks::ELEMENT_RHENIUM(), Ids::ELEMENT_75); - $this->mapSimple(Blocks::ELEMENT_RHODIUM(), Ids::ELEMENT_45); - $this->mapSimple(Blocks::ELEMENT_ROENTGENIUM(), Ids::ELEMENT_111); - $this->mapSimple(Blocks::ELEMENT_RUBIDIUM(), Ids::ELEMENT_37); - $this->mapSimple(Blocks::ELEMENT_RUTHENIUM(), Ids::ELEMENT_44); - $this->mapSimple(Blocks::ELEMENT_RUTHERFORDIUM(), Ids::ELEMENT_104); - $this->mapSimple(Blocks::ELEMENT_SAMARIUM(), Ids::ELEMENT_62); - $this->mapSimple(Blocks::ELEMENT_SCANDIUM(), Ids::ELEMENT_21); - $this->mapSimple(Blocks::ELEMENT_SEABORGIUM(), Ids::ELEMENT_106); - $this->mapSimple(Blocks::ELEMENT_SELENIUM(), Ids::ELEMENT_34); - $this->mapSimple(Blocks::ELEMENT_SILICON(), Ids::ELEMENT_14); - $this->mapSimple(Blocks::ELEMENT_SILVER(), Ids::ELEMENT_47); - $this->mapSimple(Blocks::ELEMENT_SODIUM(), Ids::ELEMENT_11); - $this->mapSimple(Blocks::ELEMENT_STRONTIUM(), Ids::ELEMENT_38); - $this->mapSimple(Blocks::ELEMENT_SULFUR(), Ids::ELEMENT_16); - $this->mapSimple(Blocks::ELEMENT_TANTALUM(), Ids::ELEMENT_73); - $this->mapSimple(Blocks::ELEMENT_TECHNETIUM(), Ids::ELEMENT_43); - $this->mapSimple(Blocks::ELEMENT_TELLURIUM(), Ids::ELEMENT_52); - $this->mapSimple(Blocks::ELEMENT_TENNESSINE(), Ids::ELEMENT_117); - $this->mapSimple(Blocks::ELEMENT_TERBIUM(), Ids::ELEMENT_65); - $this->mapSimple(Blocks::ELEMENT_THALLIUM(), Ids::ELEMENT_81); - $this->mapSimple(Blocks::ELEMENT_THORIUM(), Ids::ELEMENT_90); - $this->mapSimple(Blocks::ELEMENT_THULIUM(), Ids::ELEMENT_69); - $this->mapSimple(Blocks::ELEMENT_TIN(), Ids::ELEMENT_50); - $this->mapSimple(Blocks::ELEMENT_TITANIUM(), Ids::ELEMENT_22); - $this->mapSimple(Blocks::ELEMENT_TUNGSTEN(), Ids::ELEMENT_74); - $this->mapSimple(Blocks::ELEMENT_URANIUM(), Ids::ELEMENT_92); - $this->mapSimple(Blocks::ELEMENT_VANADIUM(), Ids::ELEMENT_23); - $this->mapSimple(Blocks::ELEMENT_XENON(), Ids::ELEMENT_54); - $this->mapSimple(Blocks::ELEMENT_YTTERBIUM(), Ids::ELEMENT_70); - $this->mapSimple(Blocks::ELEMENT_YTTRIUM(), Ids::ELEMENT_39); - $this->mapSimple(Blocks::ELEMENT_ZERO(), Ids::ELEMENT_0); - $this->mapSimple(Blocks::ELEMENT_ZINC(), Ids::ELEMENT_30); - $this->mapSimple(Blocks::ELEMENT_ZIRCONIUM(), Ids::ELEMENT_40); - $this->mapSimple(Blocks::EMERALD(), Ids::EMERALD_BLOCK); - $this->mapSimple(Blocks::EMERALD_ORE(), Ids::EMERALD_ORE); - $this->mapSimple(Blocks::ENCHANTING_TABLE(), Ids::ENCHANTING_TABLE); - $this->mapSimple(Blocks::END_STONE(), Ids::END_STONE); - $this->mapSimple(Blocks::END_STONE_BRICKS(), Ids::END_BRICKS); - $this->mapSimple(Blocks::FERN(), Ids::FERN); - $this->mapSimple(Blocks::FLETCHING_TABLE(), Ids::FLETCHING_TABLE); - $this->mapSimple(Blocks::GILDED_BLACKSTONE(), Ids::GILDED_BLACKSTONE); - $this->mapSimple(Blocks::GLASS(), Ids::GLASS); - $this->mapSimple(Blocks::GLASS_PANE(), Ids::GLASS_PANE); - $this->mapSimple(Blocks::GLOWING_OBSIDIAN(), Ids::GLOWINGOBSIDIAN); - $this->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE); - $this->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK); - $this->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE); - $this->mapSimple(Blocks::GRANITE(), Ids::GRANITE); - $this->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK); - $this->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH); - $this->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL); - $this->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS); - $this->mapSimple(Blocks::HARDENED_CLAY(), Ids::HARDENED_CLAY); - $this->mapSimple(Blocks::HARDENED_GLASS(), Ids::HARD_GLASS); - $this->mapSimple(Blocks::HARDENED_GLASS_PANE(), Ids::HARD_GLASS_PANE); - $this->mapSimple(Blocks::HONEYCOMB(), Ids::HONEYCOMB_BLOCK); - $this->mapSimple(Blocks::ICE(), Ids::ICE); - $this->mapSimple(Blocks::INFESTED_CHISELED_STONE_BRICK(), Ids::INFESTED_CHISELED_STONE_BRICKS); - $this->mapSimple(Blocks::INFESTED_COBBLESTONE(), Ids::INFESTED_COBBLESTONE); - $this->mapSimple(Blocks::INFESTED_CRACKED_STONE_BRICK(), Ids::INFESTED_CRACKED_STONE_BRICKS); - $this->mapSimple(Blocks::INFESTED_MOSSY_STONE_BRICK(), Ids::INFESTED_MOSSY_STONE_BRICKS); - $this->mapSimple(Blocks::INFESTED_STONE(), Ids::INFESTED_STONE); - $this->mapSimple(Blocks::INFESTED_STONE_BRICK(), Ids::INFESTED_STONE_BRICKS); - $this->mapSimple(Blocks::INFO_UPDATE(), Ids::INFO_UPDATE); - $this->mapSimple(Blocks::INFO_UPDATE2(), Ids::INFO_UPDATE2); - $this->mapSimple(Blocks::INVISIBLE_BEDROCK(), Ids::INVISIBLE_BEDROCK); - $this->mapSimple(Blocks::IRON(), Ids::IRON_BLOCK); - $this->mapSimple(Blocks::IRON_BARS(), Ids::IRON_BARS); - $this->mapSimple(Blocks::IRON_ORE(), Ids::IRON_ORE); - $this->mapSimple(Blocks::JUKEBOX(), Ids::JUKEBOX); - $this->mapSimple(Blocks::LAPIS_LAZULI(), Ids::LAPIS_BLOCK); - $this->mapSimple(Blocks::LAPIS_LAZULI_ORE(), Ids::LAPIS_ORE); - $this->mapSimple(Blocks::LEGACY_STONECUTTER(), Ids::STONECUTTER); - $this->mapSimple(Blocks::LILY_PAD(), Ids::WATERLILY); - $this->mapSimple(Blocks::MAGMA(), Ids::MAGMA); - $this->mapSimple(Blocks::MANGROVE_ROOTS(), Ids::MANGROVE_ROOTS); - $this->mapSimple(Blocks::MELON(), Ids::MELON_BLOCK); - $this->mapSimple(Blocks::MONSTER_SPAWNER(), Ids::MOB_SPAWNER); - $this->mapSimple(Blocks::MOSSY_COBBLESTONE(), Ids::MOSSY_COBBLESTONE); - $this->mapSimple(Blocks::MOSSY_STONE_BRICKS(), Ids::MOSSY_STONE_BRICKS); - $this->mapSimple(Blocks::MUD(), Ids::MUD); - $this->mapSimple(Blocks::MUD_BRICKS(), Ids::MUD_BRICKS); - $this->mapSimple(Blocks::MYCELIUM(), Ids::MYCELIUM); - $this->mapSimple(Blocks::NETHERITE(), Ids::NETHERITE_BLOCK); - $this->mapSimple(Blocks::NETHERRACK(), Ids::NETHERRACK); - $this->mapSimple(Blocks::NETHER_BRICKS(), Ids::NETHER_BRICK); - $this->mapSimple(Blocks::NETHER_BRICK_FENCE(), Ids::NETHER_BRICK_FENCE); - $this->mapSimple(Blocks::NETHER_GOLD_ORE(), Ids::NETHER_GOLD_ORE); - $this->mapSimple(Blocks::NETHER_QUARTZ_ORE(), Ids::QUARTZ_ORE); - $this->mapSimple(Blocks::NETHER_REACTOR_CORE(), Ids::NETHERREACTOR); - $this->mapSimple(Blocks::NETHER_WART_BLOCK(), Ids::NETHER_WART_BLOCK); - $this->mapSimple(Blocks::NOTE_BLOCK(), Ids::NOTEBLOCK); - $this->mapSimple(Blocks::OBSIDIAN(), Ids::OBSIDIAN); - $this->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE); - $this->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD); - $this->mapSimple(Blocks::PODZOL(), Ids::PODZOL); - $this->mapSimple(Blocks::POLISHED_ANDESITE(), Ids::POLISHED_ANDESITE); - $this->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE); - $this->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS); - $this->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE); - $this->mapSimple(Blocks::POLISHED_DIORITE(), Ids::POLISHED_DIORITE); - $this->mapSimple(Blocks::POLISHED_GRANITE(), Ids::POLISHED_GRANITE); - $this->mapSimple(Blocks::POLISHED_TUFF(), Ids::POLISHED_TUFF); - $this->mapSimple(Blocks::PRISMARINE(), Ids::PRISMARINE); - $this->mapSimple(Blocks::PRISMARINE_BRICKS(), Ids::PRISMARINE_BRICKS); - $this->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS); - $this->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK); - $this->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK); - $this->mapSimple(Blocks::RAW_IRON(), Ids::RAW_IRON_BLOCK); - $this->mapSimple(Blocks::REDSTONE(), Ids::REDSTONE_BLOCK); - $this->mapSimple(Blocks::RED_MUSHROOM(), Ids::RED_MUSHROOM); - $this->mapSimple(Blocks::RED_NETHER_BRICKS(), Ids::RED_NETHER_BRICK); - $this->mapSimple(Blocks::RED_SAND(), Ids::RED_SAND); - $this->mapSimple(Blocks::RED_SANDSTONE(), Ids::RED_SANDSTONE); - $this->mapSimple(Blocks::REINFORCED_DEEPSLATE(), Ids::REINFORCED_DEEPSLATE); - $this->mapSimple(Blocks::RESERVED6(), Ids::RESERVED6); - $this->mapSimple(Blocks::RESIN(), Ids::RESIN_BLOCK); - $this->mapSimple(Blocks::RESIN_BRICKS(), Ids::RESIN_BRICKS); - $this->mapSimple(Blocks::SAND(), Ids::SAND); - $this->mapSimple(Blocks::SANDSTONE(), Ids::SANDSTONE); - $this->mapSimple(Blocks::SCULK(), Ids::SCULK); - $this->mapSimple(Blocks::SEA_LANTERN(), Ids::SEA_LANTERN); - $this->mapSimple(Blocks::SHROOMLIGHT(), Ids::SHROOMLIGHT); - $this->mapSimple(Blocks::SHULKER_BOX(), Ids::UNDYED_SHULKER_BOX); - $this->mapSimple(Blocks::SLIME(), Ids::SLIME); - $this->mapSimple(Blocks::SMITHING_TABLE(), Ids::SMITHING_TABLE); - $this->mapSimple(Blocks::SMOOTH_BASALT(), Ids::SMOOTH_BASALT); - $this->mapSimple(Blocks::SMOOTH_RED_SANDSTONE(), Ids::SMOOTH_RED_SANDSTONE); - $this->mapSimple(Blocks::SMOOTH_SANDSTONE(), Ids::SMOOTH_SANDSTONE); - $this->mapSimple(Blocks::SMOOTH_STONE(), Ids::SMOOTH_STONE); - $this->mapSimple(Blocks::SNOW(), Ids::SNOW); - $this->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND); - $this->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL); - $this->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM); - $this->mapSimple(Blocks::STONE(), Ids::STONE); - $this->mapSimple(Blocks::STONE_BRICKS(), Ids::STONE_BRICKS); - $this->mapSimple(Blocks::TALL_GRASS(), Ids::SHORT_GRASS); //no, this is not a typo - tall_grass is now the double block, just to be confusing :( - $this->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS); - $this->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER); - $this->mapSimple(Blocks::TUFF(), Ids::TUFF); - $this->mapSimple(Blocks::TUFF_BRICKS(), Ids::TUFF_BRICKS); - $this->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK); - $this->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS); - $this->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE); - - $this->mapSimple(Blocks::ALLIUM(), Ids::ALLIUM); - $this->mapSimple(Blocks::CORNFLOWER(), Ids::CORNFLOWER); - $this->mapSimple(Blocks::AZURE_BLUET(), Ids::AZURE_BLUET); - $this->mapSimple(Blocks::LILY_OF_THE_VALLEY(), Ids::LILY_OF_THE_VALLEY); - $this->mapSimple(Blocks::BLUE_ORCHID(), Ids::BLUE_ORCHID); - $this->mapSimple(Blocks::OXEYE_DAISY(), Ids::OXEYE_DAISY); - $this->mapSimple(Blocks::POPPY(), Ids::POPPY); - $this->mapSimple(Blocks::ORANGE_TULIP(), Ids::ORANGE_TULIP); - $this->mapSimple(Blocks::PINK_TULIP(), Ids::PINK_TULIP); - $this->mapSimple(Blocks::RED_TULIP(), Ids::RED_TULIP); - $this->mapSimple(Blocks::WHITE_TULIP(), Ids::WHITE_TULIP); - } - - private function registerSerializers() : void{ - $this->map(Blocks::ACTIVATOR_RAIL(), function(ActivatorRail $block) : Writer{ - return Writer::create(Ids::ACTIVATOR_RAIL) - ->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered()) - ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape()); - }); - $this->map(Blocks::ALL_SIDED_MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM) - ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM)); - $this->map(Blocks::AMETHYST_CLUSTER(), fn(AmethystCluster $block) => Writer::create( - match($stage = $block->getStage()){ - AmethystCluster::STAGE_SMALL_BUD => Ids::SMALL_AMETHYST_BUD, - AmethystCluster::STAGE_MEDIUM_BUD => Ids::MEDIUM_AMETHYST_BUD, - AmethystCluster::STAGE_LARGE_BUD => Ids::LARGE_AMETHYST_BUD, - AmethystCluster::STAGE_CLUSTER => Ids::AMETHYST_CLUSTER, - default => throw new BlockStateSerializeException("Invalid Amethyst Cluster stage $stage"), - }) - ->writeBlockFace($block->getFacing()) - ); - $this->mapSlab(Blocks::ANDESITE_SLAB(), Ids::ANDESITE_SLAB, Ids::ANDESITE_DOUBLE_SLAB); - $this->map(Blocks::ANDESITE_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::ANDESITE_STAIRS))); - $this->map(Blocks::ANDESITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::ANDESITE_WALL))); - $this->map(Blocks::ANVIL(), fn(Anvil $block) : Writer => Writer::create( - match($damage = $block->getDamage()){ - 0 => Ids::ANVIL, - 1 => Ids::CHIPPED_ANVIL, - 2 => Ids::DAMAGED_ANVIL, - default => throw new BlockStateSerializeException("Invalid Anvil damage {$damage}"), - }) - ->writeCardinalHorizontalFacing($block->getFacing()) - ); - $this->map(Blocks::BAMBOO(), function(Bamboo $block) : Writer{ - return Writer::create(Ids::BAMBOO) - ->writeBool(StateNames::AGE_BIT, $block->isReady()) - ->writeString(StateNames::BAMBOO_LEAF_SIZE, match($block->getLeafSize()){ - 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, - default => throw new BlockStateSerializeException("Invalid Bamboo leaf thickness " . $block->getLeafSize()), - }) - ->writeString(StateNames::BAMBOO_STALK_THICKNESS, $block->isThick() ? StringValues::BAMBOO_STALK_THICKNESS_THICK : StringValues::BAMBOO_STALK_THICKNESS_THIN); - }); - $this->map(Blocks::BAMBOO_SAPLING(), function(BambooSapling $block) : Writer{ - return Writer::create(Ids::BAMBOO_SAPLING) - ->writeBool(StateNames::AGE_BIT, $block->isReady()); - }); - $this->map(Blocks::BANNER(), function(FloorBanner $block) : Writer{ - return Writer::create(Ids::STANDING_BANNER) - ->writeInt(StateNames::GROUND_SIGN_DIRECTION, $block->getRotation()); - }); - $this->map(Blocks::BARREL(), function(Barrel $block) : Writer{ - return Writer::create(Ids::BARREL) - ->writeBool(StateNames::OPEN_BIT, $block->isOpen()) - ->writeFacingDirection($block->getFacing()); - }); - $this->map(Blocks::BASALT(), function(SimplePillar $block) : Writer{ - return Writer::create(Ids::BASALT) - ->writePillarAxis($block->getAxis()); - }); - $this->map(Blocks::BED(), function(Bed $block) : Writer{ - return Writer::create(Ids::BED) - ->writeBool(StateNames::HEAD_PIECE_BIT, $block->isHeadPart()) - ->writeBool(StateNames::OCCUPIED_BIT, $block->isOccupied()) - ->writeLegacyHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::BEDROCK(), function(Block $block) : Writer{ - return Writer::create(Ids::BEDROCK) - ->writeBool(StateNames::INFINIBURN_BIT, $block->burnsForever()); - }); - $this->map(Blocks::BEETROOTS(), fn(Beetroot $block) => Helper::encodeCrops($block, new Writer(Ids::BEETROOT))); - $this->map(Blocks::BELL(), function(Bell $block) : Writer{ - return Writer::create(Ids::BELL) - ->writeBellAttachmentType($block->getAttachmentType()) - ->writeBool(StateNames::TOGGLE_BIT, false) //we don't care about this; it's just to keep MCPE happy - ->writeLegacyHorizontalFacing($block->getFacing()); - - }); - $this->map(Blocks::BIG_DRIPLEAF_HEAD(), function(BigDripleafHead $block) : Writer{ - return Writer::create(Ids::BIG_DRIPLEAF) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeString(StateNames::BIG_DRIPLEAF_TILT, match($block->getLeafState()){ - 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, - }) - ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, true); - }); - $this->map(Blocks::BIG_DRIPLEAF_STEM(), function(BigDripleafStem $block) : Writer{ - return Writer::create(Ids::BIG_DRIPLEAF) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeString(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE) - ->writeBool(StateNames::BIG_DRIPLEAF_HEAD, false); - }); - $this->mapSlab(Blocks::BLACKSTONE_SLAB(), Ids::BLACKSTONE_SLAB, Ids::BLACKSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::BLACKSTONE_STAIRS(), Ids::BLACKSTONE_STAIRS); - $this->map(Blocks::BLACKSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::BLACKSTONE_WALL))); - $this->map(Blocks::BLAST_FURNACE(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::BLAST_FURNACE, Ids::LIT_BLAST_FURNACE)); - $this->map(Blocks::BLUE_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_BLUE))); - $this->map(Blocks::BONE_BLOCK(), function(BoneBlock $block) : Writer{ - return Writer::create(Ids::BONE_BLOCK) - ->writeInt(StateNames::DEPRECATED, 0) - ->writePillarAxis($block->getAxis()); - }); - $this->map(Blocks::BREWING_STAND(), function(BrewingStand $block) : Writer{ - return Writer::create(Ids::BREWING_STAND) - ->writeBool(StateNames::BREWING_STAND_SLOT_A_BIT, $block->hasSlot(BrewingStandSlot::EAST)) - ->writeBool(StateNames::BREWING_STAND_SLOT_B_BIT, $block->hasSlot(BrewingStandSlot::SOUTHWEST)) - ->writeBool(StateNames::BREWING_STAND_SLOT_C_BIT, $block->hasSlot(BrewingStandSlot::NORTHWEST)); - }); - $this->mapSlab(Blocks::BRICK_SLAB(), Ids::BRICK_SLAB, Ids::BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::BRICK_STAIRS(), Ids::BRICK_STAIRS); - $this->map(Blocks::BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::BRICK_WALL))); - $this->map(Blocks::BROWN_MUSHROOM_BLOCK(), fn(BrownMushroomBlock $block) => Helper::encodeMushroomBlock($block, new Writer(Ids::BROWN_MUSHROOM_BLOCK))); - $this->map(Blocks::CACTUS(), function(Cactus $block) : Writer{ - return Writer::create(Ids::CACTUS) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->map(Blocks::CAKE(), function(Cake $block) : Writer{ - return Writer::create(Ids::CAKE) - ->writeInt(StateNames::BITE_COUNTER, $block->getBites()); - }); - $this->map(Blocks::CAMPFIRE(), function(Campfire $block) : Writer{ - return Writer::create(Ids::CAMPFIRE) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeBool(StateNames::EXTINGUISHED, !$block->isLit()); - }); - $this->map(Blocks::CARROTS(), fn(Carrot $block) => Helper::encodeCrops($block, new Writer(Ids::CARROTS))); - $this->map(Blocks::CARVED_PUMPKIN(), function(CarvedPumpkin $block) : Writer{ - return Writer::create(Ids::CARVED_PUMPKIN) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::CAVE_VINES(), function(CaveVines $block) : Writer{ - //I have no idea why this only has 3 IDs - there are 4 in Java and 4 visually distinct states in Bedrock - return Writer::create($block->hasBerries() ? - ($block->isHead() ? - Ids::CAVE_VINES_HEAD_WITH_BERRIES : - Ids::CAVE_VINES_BODY_WITH_BERRIES - ) : - Ids::CAVE_VINES - ) - ->writeInt(StateNames::GROWING_PLANT_AGE, $block->getAge()); - }); - $this->map(Blocks::CHAIN(), function(Chain $block) : Writer{ - return Writer::create(Ids::CHAIN) - ->writePillarAxis($block->getAxis()); - }); - $this->map(Blocks::CHEST(), function(Chest $block) : Writer{ - return Writer::create(Ids::CHEST) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::CHISELED_BOOKSHELF(), function(ChiseledBookshelf $block) : Writer{ - $flags = 0; - foreach($block->getSlots() as $slot){ - $flags |= 1 << $slot->value; - } - return Writer::create(Ids::CHISELED_BOOKSHELF) - ->writeLegacyHorizontalFacing($block->getFacing()) - ->writeInt(StateNames::BOOKS_STORED, $flags); - }); - $this->map(Blocks::CHISELED_QUARTZ(), fn(SimplePillar $block) => Helper::encodeQuartz($block->getAxis(), Writer::create(Ids::CHISELED_QUARTZ_BLOCK))); - $this->map(Blocks::CHORUS_FLOWER(), function(ChorusFlower $block) : Writer{ - return Writer::create(Ids::CHORUS_FLOWER) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->mapSlab(Blocks::COBBLED_DEEPSLATE_SLAB(), Ids::COBBLED_DEEPSLATE_SLAB, Ids::COBBLED_DEEPSLATE_DOUBLE_SLAB); - $this->mapStairs(Blocks::COBBLED_DEEPSLATE_STAIRS(), Ids::COBBLED_DEEPSLATE_STAIRS); - $this->map(Blocks::COBBLED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::COBBLED_DEEPSLATE_WALL))); - $this->mapSlab(Blocks::COBBLESTONE_SLAB(), Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS); - $this->map(Blocks::COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::COBBLESTONE_WALL))); - $this->map(Blocks::COCOA_POD(), function(CocoaBlock $block) : Writer{ - return Writer::create(Ids::COCOA) - ->writeInt(StateNames::AGE, $block->getAge()) - ->writeLegacyHorizontalFacing(Facing::opposite($block->getFacing())); - }); - $this->map(Blocks::COMPOUND_CREATOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::COMPOUND_CREATOR))); - $this->mapSlab(Blocks::CUT_RED_SANDSTONE_SLAB(), Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB); - $this->mapSlab(Blocks::CUT_SANDSTONE_SLAB(), Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB); - $this->mapSlab(Blocks::DARK_PRISMARINE_SLAB(), Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB); - $this->mapStairs(Blocks::DARK_PRISMARINE_STAIRS(), Ids::DARK_PRISMARINE_STAIRS); - $this->map(Blocks::DAYLIGHT_SENSOR(), function(DaylightSensor $block) : Writer{ - return Writer::create($block->isInverted() ? Ids::DAYLIGHT_DETECTOR_INVERTED : Ids::DAYLIGHT_DETECTOR) - ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength()); - }); - $this->map(Blocks::DEEPSLATE(), function(SimplePillar $block) : Writer{ - return Writer::create(Ids::DEEPSLATE) - ->writePillarAxis($block->getAxis()); - }); - $this->mapSlab(Blocks::DEEPSLATE_BRICK_SLAB(), Ids::DEEPSLATE_BRICK_SLAB, Ids::DEEPSLATE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::DEEPSLATE_BRICK_STAIRS(), Ids::DEEPSLATE_BRICK_STAIRS); - $this->map(Blocks::DEEPSLATE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::DEEPSLATE_BRICK_WALL))); - $this->map(Blocks::DEEPSLATE_REDSTONE_ORE(), fn(RedstoneOre $block) => new Writer($block->isLit() ? Ids::LIT_DEEPSLATE_REDSTONE_ORE : Ids::DEEPSLATE_REDSTONE_ORE)); - $this->mapSlab(Blocks::DEEPSLATE_TILE_SLAB(), Ids::DEEPSLATE_TILE_SLAB, Ids::DEEPSLATE_TILE_DOUBLE_SLAB); - $this->mapStairs(Blocks::DEEPSLATE_TILE_STAIRS(), Ids::DEEPSLATE_TILE_STAIRS); - $this->map(Blocks::DEEPSLATE_TILE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::DEEPSLATE_TILE_WALL))); - $this->map(Blocks::DETECTOR_RAIL(), function(DetectorRail $block) : Writer{ - return Writer::create(Ids::DETECTOR_RAIL) - ->writeBool(StateNames::RAIL_DATA_BIT, $block->isActivated()) - ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape()); - }); - $this->mapSlab(Blocks::DIORITE_SLAB(), Ids::DIORITE_SLAB, Ids::DIORITE_DOUBLE_SLAB); - $this->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS); - $this->map(Blocks::DIORITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::DIORITE_WALL))); - $this->map(Blocks::DIRT(), fn(Dirt $block) => BlockStateData::current(match($block->getDirtType()){ - DirtType::NORMAL => Ids::DIRT, - DirtType::COARSE => Ids::COARSE_DIRT, - DirtType::ROOTED => Ids::DIRT_WITH_ROOTS, - }, [])); - $this->map(Blocks::DOUBLE_TALLGRASS(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::TALL_GRASS))); - $this->map(Blocks::ELEMENT_CONSTRUCTOR(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::ELEMENT_CONSTRUCTOR))); - $this->map(Blocks::ENDER_CHEST(), function(EnderChest $block) : Writer{ - return Writer::create(Ids::ENDER_CHEST) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::END_PORTAL_FRAME(), function(EndPortalFrame $block) : Writer{ - return Writer::create(Ids::END_PORTAL_FRAME) - ->writeBool(StateNames::END_PORTAL_EYE_BIT, $block->hasEye()) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::END_ROD(), function(EndRod $block) : Writer{ - return Writer::create(Ids::END_ROD) - ->writeEndRodFacingDirection($block->getFacing()); - }); - $this->mapSlab(Blocks::END_STONE_BRICK_SLAB(), Ids::END_STONE_BRICK_SLAB, Ids::END_STONE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::END_STONE_BRICK_STAIRS(), Ids::END_BRICK_STAIRS); - $this->map(Blocks::END_STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::END_STONE_BRICK_WALL))); - $this->mapSlab(Blocks::FAKE_WOODEN_SLAB(), Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB); - $this->map(Blocks::FARMLAND(), function(Farmland $block) : Writer{ - return Writer::create(Ids::FARMLAND) - ->writeInt(StateNames::MOISTURIZED_AMOUNT, $block->getWetness()); - }); - $this->map(Blocks::FIRE(), function(Fire $block) : Writer{ - return Writer::create(Ids::FIRE) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->map(Blocks::FLOWER_POT(), Writer::create(Ids::FLOWER_POT) - ->writeBool(StateNames::UPDATE_BIT, false) //to keep MCPE happy - ); - $this->map(Blocks::FROGLIGHT(), function(Froglight $block){ - return Writer::create(match($block->getFroglightType()){ - FroglightType::OCHRE => Ids::OCHRE_FROGLIGHT, - FroglightType::PEARLESCENT => Ids::PEARLESCENT_FROGLIGHT, - FroglightType::VERDANT => Ids::VERDANT_FROGLIGHT, - }) - ->writePillarAxis($block->getAxis()); - }); - $this->map(Blocks::FROSTED_ICE(), function(FrostedIce $block) : Writer{ - return Writer::create(Ids::FROSTED_ICE) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->map(Blocks::FURNACE(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::FURNACE, Ids::LIT_FURNACE)); - $this->map(Blocks::GLOW_LICHEN(), function(GlowLichen $block) : Writer{ - return Writer::create(Ids::GLOW_LICHEN) - ->writeFacingFlags($block->getFaces()); - }); - $this->map(Blocks::GLOWING_ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::GLOW_FRAME)); - $this->mapSlab(Blocks::GRANITE_SLAB(), Ids::GRANITE_SLAB, Ids::GRANITE_DOUBLE_SLAB); - $this->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS); - $this->map(Blocks::GRANITE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::GRANITE_WALL))); - $this->map(Blocks::GREEN_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_GREEN))); - $this->map(Blocks::HAY_BALE(), function(HayBale $block) : Writer{ - return Writer::create(Ids::HAY_BLOCK) - ->writeInt(StateNames::DEPRECATED, 0) - ->writePillarAxis($block->getAxis()); - }); - $this->map(Blocks::HOPPER(), function(Hopper $block) : Writer{ - return Writer::create(Ids::HOPPER) - ->writeBool(StateNames::TOGGLE_BIT, $block->isPowered()) - ->writeFacingWithoutUp($block->getFacing()); - }); - $this->map(Blocks::IRON_DOOR(), fn(Door $block) => Helper::encodeDoor($block, new Writer(Ids::IRON_DOOR))); - $this->map(Blocks::IRON_TRAPDOOR(), fn(Trapdoor $block) => Helper::encodeTrapdoor($block, new Writer(Ids::IRON_TRAPDOOR))); - $this->map(Blocks::ITEM_FRAME(), fn(ItemFrame $block) => Helper::encodeItemFrame($block, Ids::FRAME)); - $this->map(Blocks::LAB_TABLE(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::LAB_TABLE))); - $this->map(Blocks::LADDER(), function(Ladder $block) : Writer{ - return Writer::create(Ids::LADDER) - ->writeHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::LANTERN(), function(Lantern $block) : Writer{ - return Writer::create(Ids::LANTERN) - ->writeBool(StateNames::HANGING, $block->isHanging()); - }); - $this->map(Blocks::LARGE_FERN(), fn(DoubleTallGrass $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LARGE_FERN))); - $this->map(Blocks::LAVA(), fn(Lava $block) => Helper::encodeLiquid($block, Ids::LAVA, Ids::FLOWING_LAVA)); - $this->map(Blocks::LECTERN(), function(Lectern $block) : Writer{ - return Writer::create(Ids::LECTERN) - ->writeBool(StateNames::POWERED_BIT, $block->isProducingSignal()) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::LEVER(), function(Lever $block) : Writer{ - return Writer::create(Ids::LEVER) - ->writeBool(StateNames::OPEN_BIT, $block->isActivated()) - ->writeString(StateNames::LEVER_DIRECTION, match($block->getFacing()){ - 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->map(Blocks::LIGHT(), fn(Light $block) => BlockStateData::current(match($block->getLightLevel()){ - 0 => Ids::LIGHT_BLOCK_0, - 1 => Ids::LIGHT_BLOCK_1, - 2 => Ids::LIGHT_BLOCK_2, - 3 => Ids::LIGHT_BLOCK_3, - 4 => Ids::LIGHT_BLOCK_4, - 5 => Ids::LIGHT_BLOCK_5, - 6 => Ids::LIGHT_BLOCK_6, - 7 => Ids::LIGHT_BLOCK_7, - 8 => Ids::LIGHT_BLOCK_8, - 9 => Ids::LIGHT_BLOCK_9, - 10 => Ids::LIGHT_BLOCK_10, - 11 => Ids::LIGHT_BLOCK_11, - 12 => Ids::LIGHT_BLOCK_12, - 13 => Ids::LIGHT_BLOCK_13, - 14 => Ids::LIGHT_BLOCK_14, - 15 => Ids::LIGHT_BLOCK_15, - default => throw new BlockStateSerializeException("Invalid light level " . $block->getLightLevel()), - }, [])); - $this->map(Blocks::LIGHTNING_ROD(), function(LightningRod $block) : Writer{ - return Writer::create(Ids::LIGHTNING_ROD) - ->writeFacingDirection($block->getFacing()); - }); - $this->map(Blocks::LILAC(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::LILAC))); - $this->map(Blocks::LIT_PUMPKIN(), function(LitPumpkin $block) : Writer{ - return Writer::create(Ids::LIT_PUMPKIN) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::LOOM(), function(Loom $block) : Writer{ - return Writer::create(Ids::LOOM) - ->writeLegacyHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::MATERIAL_REDUCER(), fn(ChemistryTable $block) => Helper::encodeChemistryTable($block, Writer::create(Ids::MATERIAL_REDUCER))); - $this->map(Blocks::MELON_STEM(), fn(MelonStem $block) => Helper::encodeStem($block, new Writer(Ids::MELON_STEM))); - $this->mapSlab(Blocks::MOSSY_COBBLESTONE_SLAB(), Ids::MOSSY_COBBLESTONE_SLAB, Ids::MOSSY_COBBLESTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::MOSSY_COBBLESTONE_STAIRS(), Ids::MOSSY_COBBLESTONE_STAIRS); - $this->map(Blocks::MOSSY_COBBLESTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::MOSSY_COBBLESTONE_WALL))); - $this->mapSlab(Blocks::MOSSY_STONE_BRICK_SLAB(), Ids::MOSSY_STONE_BRICK_SLAB, Ids::MOSSY_STONE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::MOSSY_STONE_BRICK_STAIRS(), Ids::MOSSY_STONE_BRICK_STAIRS); - $this->map(Blocks::MOSSY_STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::MOSSY_STONE_BRICK_WALL))); - $this->mapSlab(Blocks::MUD_BRICK_SLAB(), Ids::MUD_BRICK_SLAB, Ids::MUD_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::MUD_BRICK_STAIRS(), Ids::MUD_BRICK_STAIRS); - $this->map(Blocks::MUD_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::MUD_BRICK_WALL))); - $this->map(Blocks::MUDDY_MANGROVE_ROOTS(), fn(SimplePillar $block) => Writer::create(Ids::MUDDY_MANGROVE_ROOTS) - ->writePillarAxis($block->getAxis())); - $this->map(Blocks::MUSHROOM_STEM(), Writer::create(Ids::MUSHROOM_STEM) - ->writeInt(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM)); - $this->mapSlab(Blocks::NETHER_BRICK_SLAB(), Ids::NETHER_BRICK_SLAB, Ids::NETHER_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS); - $this->map(Blocks::NETHER_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::NETHER_BRICK_WALL))); - $this->map(Blocks::NETHER_PORTAL(), function(NetherPortal $block) : Writer{ - return Writer::create(Ids::PORTAL) - ->writeString(StateNames::PORTAL_AXIS, match($block->getAxis()){ - Axis::X => StringValues::PORTAL_AXIS_X, - Axis::Z => StringValues::PORTAL_AXIS_Z, - default => throw new BlockStateSerializeException("Invalid Nether Portal axis " . $block->getAxis()), - }); - }); - $this->map(Blocks::NETHER_WART(), function(NetherWartPlant $block) : Writer{ - return Writer::create(Ids::NETHER_WART) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->map(Blocks::PEONY(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::PEONY))); - $this->map(Blocks::PINK_PETALS(), function(PinkPetals $block) : Writer{ - return Writer::create(Ids::PINK_PETALS) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeInt(StateNames::GROWTH, $block->getCount() - 1); - }); - $this->map(Blocks::PITCHER_PLANT(), function(DoublePlant $block) : Writer{ - return Writer::create(Ids::PITCHER_PLANT) - ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop()); - }); - $this->map(Blocks::PITCHER_CROP(), function(PitcherCrop $block) : Writer{ - return Writer::create(Ids::PITCHER_CROP) - ->writeInt(StateNames::GROWTH, $block->getAge()) - ->writeBool(StateNames::UPPER_BLOCK_BIT, false); - }); - $this->map(Blocks::DOUBLE_PITCHER_CROP(), function(DoublePitcherCrop $block) : Writer{ - return Writer::create(Ids::PITCHER_CROP) - ->writeInt(StateNames::GROWTH, $block->getAge() + 1 + PitcherCrop::MAX_AGE) - ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop()); - }); - $this->mapSlab(Blocks::POLISHED_ANDESITE_SLAB(), Ids::POLISHED_ANDESITE_SLAB, Ids::POLISHED_ANDESITE_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS); - $this->map(Blocks::POLISHED_BASALT(), function(SimplePillar $block) : Writer{ - return Writer::create(Ids::POLISHED_BASALT) - ->writePillarAxis($block->getAxis()); - }); - $this->mapSlab(Blocks::POLISHED_BLACKSTONE_BRICK_SLAB(), Ids::POLISHED_BLACKSTONE_BRICK_SLAB, Ids::POLISHED_BLACKSTONE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS(), Ids::POLISHED_BLACKSTONE_BRICK_STAIRS); - $this->map(Blocks::POLISHED_BLACKSTONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_BLACKSTONE_BRICK_WALL))); - $this->map(Blocks::POLISHED_BLACKSTONE_BUTTON(), fn(Button $block) => Helper::encodeButton($block, new Writer(Ids::POLISHED_BLACKSTONE_BUTTON))); - $this->map(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), fn(SimplePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE))); - $this->mapSlab(Blocks::POLISHED_BLACKSTONE_SLAB(), Ids::POLISHED_BLACKSTONE_SLAB, Ids::POLISHED_BLACKSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_BLACKSTONE_STAIRS(), Ids::POLISHED_BLACKSTONE_STAIRS); - $this->map(Blocks::POLISHED_BLACKSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_BLACKSTONE_WALL))); - $this->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS); - $this->map(Blocks::POLISHED_DEEPSLATE_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_DEEPSLATE_WALL))); - $this->mapSlab(Blocks::POLISHED_DIORITE_SLAB(), Ids::POLISHED_DIORITE_SLAB, Ids::POLISHED_DIORITE_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS); - $this->mapSlab(Blocks::POLISHED_GRANITE_SLAB(), Ids::POLISHED_GRANITE_SLAB, Ids::POLISHED_GRANITE_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS); - $this->mapSlab(Blocks::POLISHED_TUFF_SLAB(), Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB); - $this->mapStairs(Blocks::POLISHED_TUFF_STAIRS(), Ids::POLISHED_TUFF_STAIRS); - $this->map(Blocks::POLISHED_TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::POLISHED_TUFF_WALL))); - $this->map(Blocks::POTATOES(), fn(Potato $block) => Helper::encodeCrops($block, new Writer(Ids::POTATOES))); - $this->map(Blocks::POWERED_RAIL(), function(PoweredRail $block) : Writer{ - return Writer::create(Ids::GOLDEN_RAIL) - ->writeBool(StateNames::RAIL_DATA_BIT, $block->isPowered()) - ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape()); - }); - $this->mapSlab(Blocks::PRISMARINE_BRICKS_SLAB(), Ids::PRISMARINE_BRICK_SLAB, Ids::PRISMARINE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::PRISMARINE_BRICKS_STAIRS(), Ids::PRISMARINE_BRICKS_STAIRS); - $this->mapSlab(Blocks::PRISMARINE_SLAB(), Ids::PRISMARINE_SLAB, Ids::PRISMARINE_DOUBLE_SLAB); - $this->mapStairs(Blocks::PRISMARINE_STAIRS(), Ids::PRISMARINE_STAIRS); - $this->map(Blocks::PRISMARINE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::PRISMARINE_WALL))); - $this->map(Blocks::PUMPKIN(), Writer::create(Ids::PUMPKIN) - ->writeCardinalHorizontalFacing(Facing::SOUTH) //no longer used - ); - $this->map(Blocks::PUMPKIN_STEM(), fn(PumpkinStem $block) => Helper::encodeStem($block, new Writer(Ids::PUMPKIN_STEM))); - $this->map(Blocks::PURPUR(), Writer::create(Ids::PURPUR_BLOCK)->writePillarAxis(Axis::Y)); - $this->map(Blocks::PURPLE_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_PURPLE))); - $this->map(Blocks::PURPUR_PILLAR(), function(SimplePillar $block) : Writer{ - return Writer::create(Ids::PURPUR_PILLAR) - ->writePillarAxis($block->getAxis()); - }); - $this->mapSlab(Blocks::PURPUR_SLAB(), Ids::PURPUR_SLAB, Ids::PURPUR_DOUBLE_SLAB); - $this->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS); - $this->map(Blocks::QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::QUARTZ_BLOCK))); - $this->map(Blocks::QUARTZ_PILLAR(), fn(SimplePillar $block) => Helper::encodeQuartz($block->getAxis(), Writer::create(Ids::QUARTZ_PILLAR))); - $this->mapSlab(Blocks::QUARTZ_SLAB(), Ids::QUARTZ_SLAB, Ids::QUARTZ_DOUBLE_SLAB); - $this->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS); - $this->map(Blocks::RAIL(), function(Rail $block) : Writer{ - return Writer::create(Ids::RAIL) - ->writeInt(StateNames::RAIL_DIRECTION, $block->getShape()); - }); - $this->map(Blocks::REDSTONE_COMPARATOR(), function(RedstoneComparator $block) : Writer{ - return Writer::create($block->isPowered() ? Ids::POWERED_COMPARATOR : Ids::UNPOWERED_COMPARATOR) - ->writeBool(StateNames::OUTPUT_LIT_BIT, $block->isPowered()) - ->writeBool(StateNames::OUTPUT_SUBTRACT_BIT, $block->isSubtractMode()) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::REDSTONE_LAMP(), fn(RedstoneLamp $block) => new Writer($block->isPowered() ? Ids::LIT_REDSTONE_LAMP : Ids::REDSTONE_LAMP)); - $this->map(Blocks::REDSTONE_ORE(), fn(RedstoneOre $block) => new Writer($block->isLit() ? Ids::LIT_REDSTONE_ORE : Ids::REDSTONE_ORE)); - $this->map(Blocks::REDSTONE_REPEATER(), function(RedstoneRepeater $block) : Writer{ - return Writer::create($block->isPowered() ? Ids::POWERED_REPEATER : Ids::UNPOWERED_REPEATER) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeInt(StateNames::REPEATER_DELAY, $block->getDelay() - 1); - }); - $this->map(Blocks::REDSTONE_TORCH(), function(RedstoneTorch $block) : Writer{ - return Writer::create($block->isLit() ? Ids::REDSTONE_TORCH : Ids::UNLIT_REDSTONE_TORCH) - ->writeTorchFacing($block->getFacing()); - }); - $this->map(Blocks::REDSTONE_WIRE(), function(RedstoneWire $block) : Writer{ - return Writer::create(Ids::REDSTONE_WIRE) - ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength()); - }); - $this->map(Blocks::RED_MUSHROOM_BLOCK(), fn(RedMushroomBlock $block) => Helper::encodeMushroomBlock($block, new Writer(Ids::RED_MUSHROOM_BLOCK))); - $this->mapSlab(Blocks::RED_NETHER_BRICK_SLAB(), Ids::RED_NETHER_BRICK_SLAB, Ids::RED_NETHER_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::RED_NETHER_BRICK_STAIRS(), Ids::RED_NETHER_BRICK_STAIRS); - $this->map(Blocks::RED_NETHER_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RED_NETHER_BRICK_WALL))); - $this->mapSlab(Blocks::RED_SANDSTONE_SLAB(), Ids::RED_SANDSTONE_SLAB, Ids::RED_SANDSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::RED_SANDSTONE_STAIRS(), Ids::RED_SANDSTONE_STAIRS); - $this->map(Blocks::RED_SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RED_SANDSTONE_WALL))); - $this->map(Blocks::RED_TORCH(), fn(Torch $block) => Helper::encodeTorch($block, Writer::create(Ids::COLORED_TORCH_RED))); - $this->mapSlab(Blocks::RESIN_BRICK_SLAB(), Ids::RESIN_BRICK_SLAB, Ids::RESIN_BRICK_DOUBLE_SLAB); - $this->map(Blocks::RESIN_BRICK_STAIRS(), fn(Stair $block) => Helper::encodeStairs($block, new Writer(Ids::RESIN_BRICK_STAIRS))); - $this->map(Blocks::RESIN_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::RESIN_BRICK_WALL))); - $this->map(Blocks::RESIN_CLUMP(), function(ResinClump $block) : Writer{ - return Writer::create(Ids::RESIN_CLUMP) - ->writeFacingFlags($block->getFaces()); - }); - $this->map(Blocks::RESPAWN_ANCHOR(), function(RespawnAnchor $block) : Writer{ - return Writer::create(Ids::RESPAWN_ANCHOR) - ->writeInt(StateNames::RESPAWN_ANCHOR_CHARGE, $block->getCharges()); - }); - $this->map(Blocks::ROSE_BUSH(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::ROSE_BUSH))); - $this->mapSlab(Blocks::SANDSTONE_SLAB(), Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS); - $this->map(Blocks::SANDSTONE_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::SANDSTONE_WALL))); - $this->map(Blocks::SEA_PICKLE(), function(SeaPickle $block) : Writer{ - return Writer::create(Ids::SEA_PICKLE) - ->writeBool(StateNames::DEAD_BIT, !$block->isUnderwater()) - ->writeInt(StateNames::CLUSTER_COUNT, $block->getCount() - 1); - }); - $this->map(Blocks::SMALL_DRIPLEAF(), function(SmallDripleaf $block) : Writer{ - return Writer::create(Ids::SMALL_DRIPLEAF_BLOCK) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeBool(StateNames::UPPER_BLOCK_BIT, $block->isTop()); - }); - $this->map(Blocks::SMOKER(), fn(Furnace $block) => Helper::encodeFurnace($block, Ids::SMOKER, Ids::LIT_SMOKER)); - $this->map(Blocks::SMOOTH_QUARTZ(), Helper::encodeQuartz(Axis::Y, Writer::create(Ids::SMOOTH_QUARTZ))); - $this->mapSlab(Blocks::SMOOTH_QUARTZ_SLAB(), Ids::SMOOTH_QUARTZ_SLAB, Ids::SMOOTH_QUARTZ_DOUBLE_SLAB); - $this->mapStairs(Blocks::SMOOTH_QUARTZ_STAIRS(), Ids::SMOOTH_QUARTZ_STAIRS); - $this->mapSlab(Blocks::SMOOTH_RED_SANDSTONE_SLAB(), Ids::SMOOTH_RED_SANDSTONE_SLAB, Ids::SMOOTH_RED_SANDSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::SMOOTH_RED_SANDSTONE_STAIRS(), Ids::SMOOTH_RED_SANDSTONE_STAIRS); - $this->mapSlab(Blocks::SMOOTH_SANDSTONE_SLAB(), Ids::SMOOTH_SANDSTONE_SLAB, Ids::SMOOTH_SANDSTONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::SMOOTH_SANDSTONE_STAIRS(), Ids::SMOOTH_SANDSTONE_STAIRS); - $this->mapSlab(Blocks::SMOOTH_STONE_SLAB(), Ids::SMOOTH_STONE_SLAB, Ids::SMOOTH_STONE_DOUBLE_SLAB); - $this->map(Blocks::SNOW_LAYER(), function(SnowLayer $block) : Writer{ - return Writer::create(Ids::SNOW_LAYER) - ->writeBool(StateNames::COVERED_BIT, false) - ->writeInt(StateNames::HEIGHT, $block->getLayers() - 1); - }); - $this->map(Blocks::SOUL_CAMPFIRE(), function(SoulCampfire $block) : Writer{ - return Writer::create(Ids::SOUL_CAMPFIRE) - ->writeCardinalHorizontalFacing($block->getFacing()) - ->writeBool(StateNames::EXTINGUISHED, !$block->isLit()); - }); - $this->map(Blocks::SOUL_FIRE(), Writer::create(Ids::SOUL_FIRE) - ->writeInt(StateNames::AGE, 0) //useless for soul fire, we don't track it - ); - $this->map(Blocks::SOUL_LANTERN(), function(Lantern $block) : Writer{ - return Writer::create(Ids::SOUL_LANTERN) - ->writeBool(StateNames::HANGING, $block->isHanging()); - }); - $this->map(Blocks::SOUL_TORCH(), function(Torch $block) : Writer{ - return Writer::create(Ids::SOUL_TORCH) - ->writeTorchFacing($block->getFacing()); - }); - $this->map(Blocks::SPONGE(), fn(Sponge $block) => Writer::create($block->isWet() ? Ids::WET_SPONGE : Ids::SPONGE)); - $this->map(Blocks::STONECUTTER(), fn(Stonecutter $block) => Writer::create(Ids::STONECUTTER_BLOCK) - ->writeCardinalHorizontalFacing($block->getFacing())); - $this->mapSlab(Blocks::STONE_BRICK_SLAB(), Ids::STONE_BRICK_SLAB, Ids::STONE_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS); - $this->map(Blocks::STONE_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, Writer::create(Ids::STONE_BRICK_WALL))); - $this->map(Blocks::STONE_BUTTON(), fn(StoneButton $block) => Helper::encodeButton($block, new Writer(Ids::STONE_BUTTON))); - $this->map(Blocks::STONE_PRESSURE_PLATE(), fn(StonePressurePlate $block) => Helper::encodeSimplePressurePlate($block, new Writer(Ids::STONE_PRESSURE_PLATE))); - $this->mapSlab(Blocks::STONE_SLAB(), Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB); - $this->mapStairs(Blocks::STONE_STAIRS(), Ids::NORMAL_STONE_STAIRS); - $this->map(Blocks::SUGARCANE(), function(Sugarcane $block) : Writer{ - return Writer::create(Ids::REEDS) - ->writeInt(StateNames::AGE, $block->getAge()); - }); - $this->map(Blocks::SUNFLOWER(), fn(DoublePlant $block) => Helper::encodeDoublePlant($block, Writer::create(Ids::SUNFLOWER))); - $this->map(Blocks::SWEET_BERRY_BUSH(), function(SweetBerryBush $block) : Writer{ - return Writer::create(Ids::SWEET_BERRY_BUSH) - ->writeInt(StateNames::GROWTH, $block->getAge()); - }); - $this->map(Blocks::TNT(), fn(TNT $block) => Writer::create($block->worksUnderwater() ? Ids::UNDERWATER_TNT : Ids::TNT) - ->writeBool(StateNames::EXPLODE_BIT, $block->isUnstable()) - ); - $this->map(Blocks::TORCH(), function(Torch $block) : Writer{ - return Writer::create(Ids::TORCH) - ->writeTorchFacing($block->getFacing()); - }); - $this->map(Blocks::TORCHFLOWER_CROP(), function(TorchflowerCrop $block){ - return Writer::create(Ids::TORCHFLOWER_CROP) - ->writeInt(StateNames::GROWTH, $block->isReady() ? 1 : 0); - }); - $this->map(Blocks::TRAPPED_CHEST(), function(TrappedChest $block) : Writer{ - return Writer::create(Ids::TRAPPED_CHEST) - ->writeCardinalHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::TRIPWIRE(), function(Tripwire $block) : Writer{ - return Writer::create(Ids::TRIP_WIRE) - ->writeBool(StateNames::ATTACHED_BIT, $block->isConnected()) - ->writeBool(StateNames::DISARMED_BIT, $block->isDisarmed()) - ->writeBool(StateNames::POWERED_BIT, $block->isTriggered()) - ->writeBool(StateNames::SUSPENDED_BIT, $block->isSuspended()); - }); - $this->map(Blocks::TRIPWIRE_HOOK(), function(TripwireHook $block) : Writer{ - return Writer::create(Ids::TRIPWIRE_HOOK) - ->writeBool(StateNames::ATTACHED_BIT, $block->isConnected()) - ->writeBool(StateNames::POWERED_BIT, $block->isPowered()) - ->writeLegacyHorizontalFacing($block->getFacing()); - }); - $this->mapSlab(Blocks::TUFF_BRICK_SLAB(), Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB); - $this->mapStairs(Blocks::TUFF_BRICK_STAIRS(), Ids::TUFF_BRICK_STAIRS); - $this->map(Blocks::TUFF_BRICK_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_BRICK_WALL))); - $this->mapSlab(Blocks::TUFF_SLAB(), Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB); - $this->mapStairs(Blocks::TUFF_STAIRS(), Ids::TUFF_STAIRS); - $this->map(Blocks::TUFF_WALL(), fn(Wall $block) => Helper::encodeWall($block, new Writer(Ids::TUFF_WALL))); - $this->map(Blocks::TWISTING_VINES(), function(NetherVines $block) : Writer{ - return Writer::create(Ids::TWISTING_VINES) - ->writeInt(StateNames::TWISTING_VINES_AGE, $block->getAge()); - }); - $this->map(Blocks::UNDERWATER_TORCH(), function(UnderwaterTorch $block) : Writer{ - return Writer::create(Ids::UNDERWATER_TORCH) - ->writeTorchFacing($block->getFacing()); - }); - $this->map(Blocks::VINES(), function(Vine $block) : Writer{ - return Writer::create(Ids::VINE) - ->writeInt(StateNames::VINE_DIRECTION_BITS, ($block->hasFace(Facing::NORTH) ? BlockLegacyMetadata::VINE_FLAG_NORTH : 0) | ($block->hasFace(Facing::SOUTH) ? BlockLegacyMetadata::VINE_FLAG_SOUTH : 0) | ($block->hasFace(Facing::WEST) ? BlockLegacyMetadata::VINE_FLAG_WEST : 0) | ($block->hasFace(Facing::EAST) ? BlockLegacyMetadata::VINE_FLAG_EAST : 0)); - }); - $this->map(Blocks::WALL_BANNER(), function(WallBanner $block) : Writer{ - return Writer::create(Ids::WALL_BANNER) - ->writeHorizontalFacing($block->getFacing()); - }); - $this->map(Blocks::WATER(), fn(Water $block) => Helper::encodeLiquid($block, Ids::WATER, Ids::FLOWING_WATER)); - $this->map(Blocks::WEEPING_VINES(), function(NetherVines $block) : Writer{ - return Writer::create(Ids::WEEPING_VINES) - ->writeInt(StateNames::WEEPING_VINES_AGE, $block->getAge()); - }); - $this->map(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), function(WeightedPressurePlate $block) : Writer{ - return Writer::create(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE) - ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength()); - }); - $this->map(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), function(WeightedPressurePlate $block) : Writer{ - return Writer::create(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE) - ->writeInt(StateNames::REDSTONE_SIGNAL, $block->getOutputSignalStrength()); - }); - $this->map(Blocks::WHEAT(), fn(Wheat $block) => Helper::encodeCrops($block, new Writer(Ids::WHEAT))); - } } diff --git a/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php b/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php new file mode 100644 index 000000000..02491bae6 --- /dev/null +++ b/src/data/bedrock/block/convert/BlockSerializerDeserializerRegistrar.php @@ -0,0 +1,237 @@ +> $components + * + * @return string[][] + * @phpstan-return list> + */ + 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> $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> $idComponents + * @phpstan-param list $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 $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 $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; + }); + } +} diff --git a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php index 3cf55429e..1d48ec76f 100644 --- a/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php +++ b/src/data/bedrock/block/convert/BlockStateDeserializerHelper.php @@ -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)); diff --git a/src/data/bedrock/block/convert/BlockStateReader.php b/src/data/bedrock/block/convert/BlockStateReader.php index e3a02885f..4d09d2f85 100644 --- a/src/data/bedrock/block/convert/BlockStateReader.php +++ b/src/data/bedrock/block/convert/BlockStateReader.php @@ -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 $mapping - * @phpstan-return int + * @deprecated + * @phpstan-param IntFromRawStateMap $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 $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 */ @@ -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 $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 */ diff --git a/src/data/bedrock/block/convert/BlockStateSerializerHelper.php b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php index a25044153..da3dbb387 100644 --- a/src/data/bedrock/block/convert/BlockStateSerializerHelper.php +++ b/src/data/bedrock/block/convert/BlockStateSerializerHelper.php @@ -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()); diff --git a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php index 1e9a4041f..ca5c12412 100644 --- a/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php +++ b/src/data/bedrock/block/convert/BlockStateToObjectDeserializer.php @@ -23,50 +23,18 @@ declare(strict_types=1); namespace pocketmine\data\bedrock\block\convert; -use pocketmine\block\AmethystCluster; -use pocketmine\block\Anvil; -use pocketmine\block\Bamboo; use pocketmine\block\Block; -use pocketmine\block\CakeWithDyedCandle; -use pocketmine\block\CaveVines; -use pocketmine\block\ChorusFlower; -use pocketmine\block\DoublePitcherCrop; -use pocketmine\block\Opaque; -use pocketmine\block\PinkPetals; -use pocketmine\block\PitcherCrop; use pocketmine\block\RuntimeBlockStateRegistry; use pocketmine\block\Slab; use pocketmine\block\Stair; -use pocketmine\block\SweetBerryBush; -use pocketmine\block\utils\BrewingStandSlot; -use pocketmine\block\utils\ChiseledBookshelfSlot; -use pocketmine\block\utils\Colored; -use pocketmine\block\utils\CopperMaterial; -use pocketmine\block\utils\CopperOxidation; -use pocketmine\block\utils\CoralType; -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\VanillaBlocks as Blocks; use pocketmine\block\Wood; -use pocketmine\data\bedrock\block\BlockLegacyMetadata; use pocketmine\data\bedrock\block\BlockStateData; use pocketmine\data\bedrock\block\BlockStateDeserializeException; use pocketmine\data\bedrock\block\BlockStateDeserializer; -use pocketmine\data\bedrock\block\BlockStateNames as StateNames; -use pocketmine\data\bedrock\block\BlockStateStringValues as StringValues; -use pocketmine\data\bedrock\block\BlockTypeNames as Ids; use pocketmine\data\bedrock\block\convert\BlockStateDeserializerHelper as Helper; use pocketmine\data\bedrock\block\convert\BlockStateReader as Reader; -use pocketmine\math\Axis; -use pocketmine\math\Facing; -use pocketmine\utils\Utils; use function array_key_exists; use function count; -use function min; final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ @@ -82,21 +50,6 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ */ private array $simpleCache = []; - public function __construct(){ - $this->registerCandleDeserializers(); - $this->registerFlatColorBlockDeserializers(); - $this->registerFlatCoralDeserializers(); - $this->registerCauldronDeserializers(); - $this->registerFlatWoodBlockDeserializers(); - $this->registerLeavesDeserializers(); - $this->registerSaplingDeserializers(); - $this->registerLightDeserializers(); - $this->registerMobHeadDeserializers(); - $this->registerCopperDeserializers(); - $this->registerSimpleDeserializers(); - $this->registerDeserializers(); - } - public function deserialize(BlockStateData $stateData) : int{ if(count($stateData->getStates()) === 0){ //if a block has zero properties, we can keep a map of string ID -> internal blockstate ID @@ -133,12 +86,16 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ return $this->deserializeFuncs[$id] ?? null; } - /** @phpstan-param \Closure() : Block $getBlock */ + /** + * @deprecated + * @phpstan-param \Closure() : Block $getBlock + */ public function mapSimple(string $id, \Closure $getBlock) : void{ $this->map($id, $getBlock); } /** + * @deprecated * @phpstan-param \Closure(Reader) : Slab $getBlock */ public function mapSlab(string $singleId, string $doubleId, \Closure $getBlock) : void{ @@ -147,1552 +104,22 @@ final class BlockStateToObjectDeserializer implements BlockStateDeserializer{ } /** + * @deprecated * @phpstan-param \Closure() : Stair $getBlock */ public function mapStairs(string $id, \Closure $getBlock) : void{ $this->map($id, fn(Reader $in) : Stair => Helper::decodeStairs($getBlock(), $in)); } - /** @phpstan-param \Closure() : Wood $getBlock */ + /** + * @deprecated + * @phpstan-param \Closure() : Wood $getBlock + */ public function mapLog(string $unstrippedId, string $strippedId, \Closure $getBlock) : void{ $this->map($unstrippedId, fn(Reader $in) => Helper::decodeLog($getBlock(), false, $in)); $this->map($strippedId, fn(Reader $in) => Helper::decodeLog($getBlock(), true, $in)); } - /** - * @phpstan-template TBlock of Block - * @phpstan-template TEnum of \UnitEnum - * - * @phpstan-param StringEnumMap $mapProperty - * @phpstan-param \Closure(TEnum) : TBlock $getBlock - * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra - */ - public function mapFlattenedEnum( - StringEnumMap $mapProperty, - string $prefix, - string $suffix, - \Closure $getBlock, - ?\Closure $extra = null - ) : void{ - foreach(Utils::stringifyKeys($mapProperty->getValueToEnum()) as $infix => $enumCase){ - $id = $prefix . $infix . $suffix; - if($extra === null){ - $this->map($id, fn() => $getBlock($enumCase)); - }else{ - $this->map($id, function(Reader $in) use ($enumCase, $getBlock, $extra) : Block{ - $block = $getBlock($enumCase); - $extra($block, $in); - return $block; - }); - } - } - } - - /** - * @phpstan-template TBlock of Block&Colored - * @phpstan-param \Closure() : TBlock $getBlock - * @phpstan-param ?\Closure(TBlock, Reader) : TBlock $extra - */ - public function mapColored(string $prefix, string $suffix, \Closure $getBlock, ?\Closure $extra = null) : void{ - $this->mapFlattenedEnum( - ValueMappings::getInstance()->getEnumMap(DyeColor::class), - $prefix, - $suffix, - fn(DyeColor $color) => $getBlock()->setColor($color), - $extra - ); - } - - private function registerCandleDeserializers() : void{ - $this->map(Ids::CANDLE, fn(Reader $in) => Helper::decodeCandle(Blocks::CANDLE(), $in)); - $this->mapColored( - "minecraft:", - "_candle", - fn() => Blocks::DYED_CANDLE(), - Helper::decodeCandle(...) - ); - - $this->map(Ids::CANDLE_CAKE, fn(Reader $in) => Blocks::CAKE_WITH_CANDLE()->setLit($in->readBool(StateNames::LIT))); - - $this->mapColored( - "minecraft:", - "_candle_cake", - fn() => Blocks::CAKE_WITH_DYED_CANDLE(), - fn(CakeWithDyedCandle $block, Reader $in) => $block->setLit($in->readBool(StateNames::LIT)) - ); - } - - private function registerFlatColorBlockDeserializers() : void{ - $this->mapColored("minecraft:hard_", "_stained_glass", fn() => Blocks::STAINED_HARDENED_GLASS()); - $this->mapColored("minecraft:hard_", "_stained_glass_pane", fn() => Blocks::STAINED_HARDENED_GLASS_PANE()); - - $this->mapColored("minecraft:", "_carpet", fn() => Blocks::CARPET()); - $this->mapColored("minecraft:", "_concrete", fn() => Blocks::CONCRETE()); - $this->mapColored("minecraft:", "_concrete_powder", fn() => Blocks::CONCRETE_POWDER()); - $this->mapColored("minecraft:", "_shulker_box", fn() => Blocks::DYED_SHULKER_BOX()); - $this->mapColored("minecraft:", "_stained_glass", fn() => Blocks::STAINED_GLASS()); - $this->mapColored("minecraft:", "_stained_glass_pane", fn() => Blocks::STAINED_GLASS_PANE()); - $this->mapColored("minecraft:", "_terracotta", fn() => Blocks::STAINED_CLAY()); - $this->mapColored("minecraft:", "_wool", fn() => Blocks::WOOL()); - - foreach([ - Ids::BLACK_GLAZED_TERRACOTTA => DyeColor::BLACK, - Ids::BLUE_GLAZED_TERRACOTTA => DyeColor::BLUE, - Ids::BROWN_GLAZED_TERRACOTTA => DyeColor::BROWN, - Ids::CYAN_GLAZED_TERRACOTTA => DyeColor::CYAN, - Ids::GRAY_GLAZED_TERRACOTTA => DyeColor::GRAY, - Ids::GREEN_GLAZED_TERRACOTTA => DyeColor::GREEN, - Ids::LIGHT_BLUE_GLAZED_TERRACOTTA => DyeColor::LIGHT_BLUE, - Ids::SILVER_GLAZED_TERRACOTTA => DyeColor::LIGHT_GRAY, //minecraft sadness - Ids::LIME_GLAZED_TERRACOTTA => DyeColor::LIME, - Ids::MAGENTA_GLAZED_TERRACOTTA => DyeColor::MAGENTA, - Ids::ORANGE_GLAZED_TERRACOTTA => DyeColor::ORANGE, - Ids::PINK_GLAZED_TERRACOTTA => DyeColor::PINK, - Ids::PURPLE_GLAZED_TERRACOTTA => DyeColor::PURPLE, - Ids::RED_GLAZED_TERRACOTTA => DyeColor::RED, - Ids::WHITE_GLAZED_TERRACOTTA => DyeColor::WHITE, - Ids::YELLOW_GLAZED_TERRACOTTA => DyeColor::YELLOW, - ] as $id => $color){ - $this->map($id, fn(Reader $in) => Blocks::GLAZED_TERRACOTTA() - ->setColor($color) - ->setFacing($in->readHorizontalFacing()) - ); - } - } - - private function registerFlatCoralDeserializers() : void{ - foreach([ - Ids::BRAIN_CORAL => CoralType::BRAIN, - Ids::BUBBLE_CORAL => CoralType::BUBBLE, - Ids::FIRE_CORAL => CoralType::FIRE, - Ids::HORN_CORAL => CoralType::HORN, - Ids::TUBE_CORAL => CoralType::TUBE, - ] as $id => $coralType){ - $this->mapSimple($id, fn() => Blocks::CORAL()->setCoralType($coralType)->setDead(false)); - } - foreach([ - Ids::DEAD_BRAIN_CORAL => CoralType::BRAIN, - Ids::DEAD_BUBBLE_CORAL => CoralType::BUBBLE, - Ids::DEAD_FIRE_CORAL => CoralType::FIRE, - Ids::DEAD_HORN_CORAL => CoralType::HORN, - Ids::DEAD_TUBE_CORAL => CoralType::TUBE, - ] as $id => $coralType){ - $this->mapSimple($id, fn() => Blocks::CORAL()->setCoralType($coralType)->setDead(true)); - } - - foreach([ - [CoralType::BRAIN, Ids::BRAIN_CORAL_FAN, Ids::DEAD_BRAIN_CORAL_FAN], - [CoralType::BUBBLE, Ids::BUBBLE_CORAL_FAN, Ids::DEAD_BUBBLE_CORAL_FAN], - [CoralType::FIRE, Ids::FIRE_CORAL_FAN, Ids::DEAD_FIRE_CORAL_FAN], - [CoralType::HORN, Ids::HORN_CORAL_FAN, Ids::DEAD_HORN_CORAL_FAN], - [CoralType::TUBE, Ids::TUBE_CORAL_FAN, Ids::DEAD_TUBE_CORAL_FAN], - ] as [$coralType, $aliveId, $deadId]){ - $this->map($aliveId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(false), $in)); - $this->map($deadId, fn(Reader $in) => Helper::decodeFloorCoralFan(Blocks::CORAL_FAN()->setCoralType($coralType)->setDead(true), $in)); - } - - foreach([ - [CoralType::BRAIN, Ids::BRAIN_CORAL_BLOCK, Ids::DEAD_BRAIN_CORAL_BLOCK], - [CoralType::BUBBLE, Ids::BUBBLE_CORAL_BLOCK, Ids::DEAD_BUBBLE_CORAL_BLOCK], - [CoralType::FIRE, Ids::FIRE_CORAL_BLOCK, Ids::DEAD_FIRE_CORAL_BLOCK], - [CoralType::HORN, Ids::HORN_CORAL_BLOCK, Ids::DEAD_HORN_CORAL_BLOCK], - [CoralType::TUBE, Ids::TUBE_CORAL_BLOCK, Ids::DEAD_TUBE_CORAL_BLOCK], - ] as [$coralType, $aliveId, $deadId]){ - $this->map($aliveId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(false)); - $this->map($deadId, fn(Reader $in) => Blocks::CORAL_BLOCK()->setCoralType($coralType)->setDead(true)); - } - - foreach([ - [CoralType::BRAIN, Ids::BRAIN_CORAL_WALL_FAN, Ids::DEAD_BRAIN_CORAL_WALL_FAN], - [CoralType::BUBBLE, Ids::BUBBLE_CORAL_WALL_FAN, Ids::DEAD_BUBBLE_CORAL_WALL_FAN], - [CoralType::FIRE, Ids::FIRE_CORAL_WALL_FAN, Ids::DEAD_FIRE_CORAL_WALL_FAN], - [CoralType::HORN, Ids::HORN_CORAL_WALL_FAN, Ids::DEAD_HORN_CORAL_WALL_FAN], - [CoralType::TUBE, Ids::TUBE_CORAL_WALL_FAN, Ids::DEAD_TUBE_CORAL_WALL_FAN], - ] as [$coralType, $aliveId, $deadId]){ - $this->map($aliveId, fn(Reader $in) => Blocks::WALL_CORAL_FAN()->setFacing($in->readCoralFacing())->setCoralType($coralType)->setDead(false)); - $this->map($deadId, fn(Reader $in) => Blocks::WALL_CORAL_FAN()->setFacing($in->readCoralFacing())->setCoralType($coralType)->setDead(true)); - } - } - - private function registerCauldronDeserializers() : void{ - $deserializer = function(Reader $in) : Block{ - $level = $in->readBoundedInt(StateNames::FILL_LEVEL, 0, 6); - if($level === 0){ - $in->ignored(StateNames::CAULDRON_LIQUID); - return Blocks::CAULDRON(); - } - - return (match($liquid = $in->readString(StateNames::CAULDRON_LIQUID)){ - StringValues::CAULDRON_LIQUID_WATER => Blocks::WATER_CAULDRON(), - StringValues::CAULDRON_LIQUID_LAVA => Blocks::LAVA_CAULDRON(), - StringValues::CAULDRON_LIQUID_POWDER_SNOW => throw new UnsupportedBlockStateException("Powder snow is not supported yet"), - default => throw $in->badValueException(StateNames::CAULDRON_LIQUID, $liquid) - })->setFillLevel($level); - }; - $this->map(Ids::CAULDRON, $deserializer); - } - - private function registerFlatWoodBlockDeserializers() : void{ - $this->map(Ids::ACACIA_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::ACACIA_BUTTON(), $in)); - $this->map(Ids::ACACIA_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::ACACIA_DOOR(), $in)); - $this->map(Ids::ACACIA_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::ACACIA_FENCE_GATE(), $in)); - $this->map(Ids::ACACIA_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::ACACIA_PRESSURE_PLATE(), $in)); - $this->map(Ids::ACACIA_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::ACACIA_SIGN(), $in)); - $this->map(Ids::ACACIA_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::ACACIA_TRAPDOOR(), $in)); - $this->map(Ids::ACACIA_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::ACACIA_WALL_SIGN(), $in)); - $this->mapLog(Ids::ACACIA_LOG, Ids::STRIPPED_ACACIA_LOG, fn() => Blocks::ACACIA_LOG()); - $this->mapLog(Ids::ACACIA_WOOD, Ids::STRIPPED_ACACIA_WOOD, fn() => Blocks::ACACIA_WOOD()); - $this->mapSimple(Ids::ACACIA_FENCE, fn() => Blocks::ACACIA_FENCE()); - $this->mapSimple(Ids::ACACIA_PLANKS, fn() => Blocks::ACACIA_PLANKS()); - $this->mapSlab(Ids::ACACIA_SLAB, Ids::ACACIA_DOUBLE_SLAB, fn() => Blocks::ACACIA_SLAB()); - $this->mapStairs(Ids::ACACIA_STAIRS, fn() => Blocks::ACACIA_STAIRS()); - - $this->map(Ids::BIRCH_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::BIRCH_BUTTON(), $in)); - $this->map(Ids::BIRCH_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::BIRCH_DOOR(), $in)); - $this->map(Ids::BIRCH_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::BIRCH_FENCE_GATE(), $in)); - $this->map(Ids::BIRCH_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::BIRCH_PRESSURE_PLATE(), $in)); - $this->map(Ids::BIRCH_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::BIRCH_SIGN(), $in)); - $this->map(Ids::BIRCH_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::BIRCH_TRAPDOOR(), $in)); - $this->map(Ids::BIRCH_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::BIRCH_WALL_SIGN(), $in)); - $this->mapLog(Ids::BIRCH_LOG, Ids::STRIPPED_BIRCH_LOG, fn() => Blocks::BIRCH_LOG()); - $this->mapLog(Ids::BIRCH_WOOD, Ids::STRIPPED_BIRCH_WOOD, fn() => Blocks::BIRCH_WOOD()); - $this->mapSimple(Ids::BIRCH_FENCE, fn() => Blocks::BIRCH_FENCE()); - $this->mapSimple(Ids::BIRCH_PLANKS, fn() => Blocks::BIRCH_PLANKS()); - $this->mapSlab(Ids::BIRCH_SLAB, Ids::BIRCH_DOUBLE_SLAB, fn() => Blocks::BIRCH_SLAB()); - $this->mapStairs(Ids::BIRCH_STAIRS, fn() => Blocks::BIRCH_STAIRS()); - - $this->map(Ids::CHERRY_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CHERRY_BUTTON(), $in)); - $this->map(Ids::CHERRY_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CHERRY_DOOR(), $in)); - $this->map(Ids::CHERRY_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::CHERRY_FENCE_GATE(), $in)); - $this->map(Ids::CHERRY_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::CHERRY_PRESSURE_PLATE(), $in)); - $this->map(Ids::CHERRY_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::CHERRY_SIGN(), $in)); - $this->map(Ids::CHERRY_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::CHERRY_TRAPDOOR(), $in)); - $this->map(Ids::CHERRY_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::CHERRY_WALL_SIGN(), $in)); - $this->mapLog(Ids::CHERRY_LOG, Ids::STRIPPED_CHERRY_LOG, fn() => Blocks::CHERRY_LOG()); - $this->mapSimple(Ids::CHERRY_FENCE, fn() => Blocks::CHERRY_FENCE()); - $this->mapSimple(Ids::CHERRY_PLANKS, fn() => Blocks::CHERRY_PLANKS()); - $this->mapSlab(Ids::CHERRY_SLAB, Ids::CHERRY_DOUBLE_SLAB, fn() => Blocks::CHERRY_SLAB()); - $this->mapStairs(Ids::CHERRY_STAIRS, fn() => Blocks::CHERRY_STAIRS()); - $this->map(Ids::CHERRY_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::CHERRY_WOOD(), false, $in)); - $this->map(Ids::STRIPPED_CHERRY_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::CHERRY_WOOD(), true, $in)); - - $this->map(Ids::CRIMSON_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::CRIMSON_BUTTON(), $in)); - $this->map(Ids::CRIMSON_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::CRIMSON_DOOR(), $in)); - $this->map(Ids::CRIMSON_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::CRIMSON_FENCE_GATE(), $in)); - $this->map(Ids::CRIMSON_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::CRIMSON_PRESSURE_PLATE(), $in)); - $this->map(Ids::CRIMSON_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::CRIMSON_SIGN(), $in)); - $this->map(Ids::CRIMSON_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::CRIMSON_TRAPDOOR(), $in)); - $this->map(Ids::CRIMSON_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::CRIMSON_WALL_SIGN(), $in)); - $this->mapLog(Ids::CRIMSON_HYPHAE, Ids::STRIPPED_CRIMSON_HYPHAE, fn() => Blocks::CRIMSON_HYPHAE()); - $this->mapLog(Ids::CRIMSON_STEM, Ids::STRIPPED_CRIMSON_STEM, fn() => Blocks::CRIMSON_STEM()); - $this->mapSimple(Ids::CRIMSON_FENCE, fn() => Blocks::CRIMSON_FENCE()); - $this->mapSimple(Ids::CRIMSON_PLANKS, fn() => Blocks::CRIMSON_PLANKS()); - $this->mapSlab(Ids::CRIMSON_SLAB, Ids::CRIMSON_DOUBLE_SLAB, fn() => Blocks::CRIMSON_SLAB()); - $this->mapStairs(Ids::CRIMSON_STAIRS, fn() => Blocks::CRIMSON_STAIRS()); - - $this->map(Ids::DARKOAK_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::DARK_OAK_SIGN(), $in)); - $this->map(Ids::DARKOAK_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::DARK_OAK_WALL_SIGN(), $in)); - $this->map(Ids::DARK_OAK_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::DARK_OAK_BUTTON(), $in)); - $this->map(Ids::DARK_OAK_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::DARK_OAK_DOOR(), $in)); - $this->map(Ids::DARK_OAK_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::DARK_OAK_FENCE_GATE(), $in)); - $this->map(Ids::DARK_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::DARK_OAK_PRESSURE_PLATE(), $in)); - $this->map(Ids::DARK_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::DARK_OAK_TRAPDOOR(), $in)); - $this->mapLog(Ids::DARK_OAK_LOG, Ids::STRIPPED_DARK_OAK_LOG, fn() => Blocks::DARK_OAK_LOG()); - $this->mapLog(Ids::DARK_OAK_WOOD, Ids::STRIPPED_DARK_OAK_WOOD, fn() => Blocks::DARK_OAK_WOOD()); - $this->mapSimple(Ids::DARK_OAK_FENCE, fn() => Blocks::DARK_OAK_FENCE()); - $this->mapSimple(Ids::DARK_OAK_PLANKS, fn() => Blocks::DARK_OAK_PLANKS()); - $this->mapSlab(Ids::DARK_OAK_SLAB, Ids::DARK_OAK_DOUBLE_SLAB, fn() => Blocks::DARK_OAK_SLAB()); - $this->mapStairs(Ids::DARK_OAK_STAIRS, fn() => Blocks::DARK_OAK_STAIRS()); - - $this->map(Ids::JUNGLE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::JUNGLE_BUTTON(), $in)); - $this->map(Ids::JUNGLE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::JUNGLE_DOOR(), $in)); - $this->map(Ids::JUNGLE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::JUNGLE_FENCE_GATE(), $in)); - $this->map(Ids::JUNGLE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::JUNGLE_PRESSURE_PLATE(), $in)); - $this->map(Ids::JUNGLE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::JUNGLE_SIGN(), $in)); - $this->map(Ids::JUNGLE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::JUNGLE_TRAPDOOR(), $in)); - $this->map(Ids::JUNGLE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::JUNGLE_WALL_SIGN(), $in)); - $this->mapLog(Ids::JUNGLE_LOG, Ids::STRIPPED_JUNGLE_LOG, fn() => Blocks::JUNGLE_LOG()); - $this->mapLog(Ids::JUNGLE_WOOD, Ids::STRIPPED_JUNGLE_WOOD, fn() => Blocks::JUNGLE_WOOD()); - $this->mapSimple(Ids::JUNGLE_FENCE, fn() => Blocks::JUNGLE_FENCE()); - $this->mapSimple(Ids::JUNGLE_PLANKS, fn() => Blocks::JUNGLE_PLANKS()); - $this->mapSlab(Ids::JUNGLE_SLAB, Ids::JUNGLE_DOUBLE_SLAB, fn() => Blocks::JUNGLE_SLAB()); - $this->mapStairs(Ids::JUNGLE_STAIRS, fn() => Blocks::JUNGLE_STAIRS()); - - $this->map(Ids::MANGROVE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::MANGROVE_BUTTON(), $in)); - $this->map(Ids::MANGROVE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::MANGROVE_DOOR(), $in)); - $this->map(Ids::MANGROVE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::MANGROVE_FENCE_GATE(), $in)); - $this->map(Ids::MANGROVE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::MANGROVE_PRESSURE_PLATE(), $in)); - $this->map(Ids::MANGROVE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::MANGROVE_SIGN(), $in)); - $this->map(Ids::MANGROVE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::MANGROVE_TRAPDOOR(), $in)); - $this->map(Ids::MANGROVE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::MANGROVE_WALL_SIGN(), $in)); - $this->mapLog(Ids::MANGROVE_LOG, Ids::STRIPPED_MANGROVE_LOG, fn() => Blocks::MANGROVE_LOG()); - $this->mapSimple(Ids::MANGROVE_FENCE, fn() => Blocks::MANGROVE_FENCE()); - $this->mapSimple(Ids::MANGROVE_PLANKS, fn() => Blocks::MANGROVE_PLANKS()); - $this->mapSlab(Ids::MANGROVE_SLAB, Ids::MANGROVE_DOUBLE_SLAB, fn() => Blocks::MANGROVE_SLAB()); - $this->mapStairs(Ids::MANGROVE_STAIRS, fn() => Blocks::MANGROVE_STAIRS()); - $this->map(Ids::MANGROVE_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_WOOD(), false, $in)); - $this->map(Ids::STRIPPED_MANGROVE_WOOD, fn(Reader $in) => Helper::decodeLog(Blocks::MANGROVE_WOOD(), true, $in)); - - //oak - due to age, many of these don't specify "oak", making for confusing reading - $this->map(Ids::WOODEN_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::OAK_BUTTON(), $in)); - $this->map(Ids::WOODEN_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::OAK_DOOR(), $in)); - $this->map(Ids::FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::OAK_FENCE_GATE(), $in)); - $this->map(Ids::WOODEN_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::OAK_PRESSURE_PLATE(), $in)); - $this->map(Ids::STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::OAK_SIGN(), $in)); - $this->map(Ids::TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::OAK_TRAPDOOR(), $in)); - $this->map(Ids::WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::OAK_WALL_SIGN(), $in)); - $this->mapLog(Ids::OAK_LOG, Ids::STRIPPED_OAK_LOG, fn() => Blocks::OAK_LOG()); - $this->mapLog(Ids::OAK_WOOD, Ids::STRIPPED_OAK_WOOD, fn() => Blocks::OAK_WOOD()); - $this->mapSimple(Ids::OAK_FENCE, fn() => Blocks::OAK_FENCE()); - $this->mapSimple(Ids::OAK_PLANKS, fn() => Blocks::OAK_PLANKS()); - $this->mapSlab(Ids::OAK_SLAB, Ids::OAK_DOUBLE_SLAB, fn() => Blocks::OAK_SLAB()); - $this->mapStairs(Ids::OAK_STAIRS, fn() => Blocks::OAK_STAIRS()); - - $this->map(Ids::PALE_OAK_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::PALE_OAK_BUTTON(), $in)); - $this->map(Ids::PALE_OAK_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::PALE_OAK_DOOR(), $in)); - $this->map(Ids::PALE_OAK_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::PALE_OAK_FENCE_GATE(), $in)); - $this->map(Ids::PALE_OAK_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::PALE_OAK_PRESSURE_PLATE(), $in)); - $this->map(Ids::PALE_OAK_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::PALE_OAK_SIGN(), $in)); - $this->map(Ids::PALE_OAK_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::PALE_OAK_TRAPDOOR(), $in)); - $this->map(Ids::PALE_OAK_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::PALE_OAK_WALL_SIGN(), $in)); - $this->mapLog(Ids::PALE_OAK_LOG, Ids::STRIPPED_PALE_OAK_LOG, fn() => Blocks::PALE_OAK_LOG()); - $this->mapLog(Ids::PALE_OAK_WOOD, Ids::STRIPPED_PALE_OAK_WOOD, fn() => Blocks::PALE_OAK_WOOD()); - $this->mapSimple(Ids::PALE_OAK_FENCE, fn() => Blocks::PALE_OAK_FENCE()); - $this->mapSimple(Ids::PALE_OAK_PLANKS, fn() => Blocks::PALE_OAK_PLANKS()); - $this->mapSlab(Ids::PALE_OAK_SLAB, Ids::PALE_OAK_DOUBLE_SLAB, fn() => Blocks::PALE_OAK_SLAB()); - $this->mapStairs(Ids::PALE_OAK_STAIRS, fn() => Blocks::PALE_OAK_STAIRS()); - - $this->map(Ids::SPRUCE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::SPRUCE_BUTTON(), $in)); - $this->map(Ids::SPRUCE_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::SPRUCE_DOOR(), $in)); - $this->map(Ids::SPRUCE_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::SPRUCE_FENCE_GATE(), $in)); - $this->map(Ids::SPRUCE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::SPRUCE_PRESSURE_PLATE(), $in)); - $this->map(Ids::SPRUCE_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::SPRUCE_SIGN(), $in)); - $this->map(Ids::SPRUCE_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::SPRUCE_TRAPDOOR(), $in)); - $this->map(Ids::SPRUCE_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::SPRUCE_WALL_SIGN(), $in)); - $this->mapLog(Ids::SPRUCE_LOG, Ids::STRIPPED_SPRUCE_LOG, fn() => Blocks::SPRUCE_LOG()); - $this->mapLog(Ids::SPRUCE_WOOD, Ids::STRIPPED_SPRUCE_WOOD, fn() => Blocks::SPRUCE_WOOD()); - $this->mapSimple(Ids::SPRUCE_FENCE, fn() => Blocks::SPRUCE_FENCE()); - $this->mapSimple(Ids::SPRUCE_PLANKS, fn() => Blocks::SPRUCE_PLANKS()); - $this->mapSlab(Ids::SPRUCE_SLAB, Ids::SPRUCE_DOUBLE_SLAB, fn() => Blocks::SPRUCE_SLAB()); - $this->mapStairs(Ids::SPRUCE_STAIRS, fn() => Blocks::SPRUCE_STAIRS()); - - $this->map(Ids::WARPED_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::WARPED_BUTTON(), $in)); - $this->map(Ids::WARPED_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::WARPED_DOOR(), $in)); - $this->map(Ids::WARPED_FENCE_GATE, fn(Reader $in) => Helper::decodeFenceGate(Blocks::WARPED_FENCE_GATE(), $in)); - $this->map(Ids::WARPED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::WARPED_PRESSURE_PLATE(), $in)); - $this->map(Ids::WARPED_STANDING_SIGN, fn(Reader $in) => Helper::decodeFloorSign(Blocks::WARPED_SIGN(), $in)); - $this->map(Ids::WARPED_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::WARPED_TRAPDOOR(), $in)); - $this->map(Ids::WARPED_WALL_SIGN, fn(Reader $in) => Helper::decodeWallSign(Blocks::WARPED_WALL_SIGN(), $in)); - $this->mapLog(Ids::WARPED_HYPHAE, Ids::STRIPPED_WARPED_HYPHAE, fn() => Blocks::WARPED_HYPHAE()); - $this->mapLog(Ids::WARPED_STEM, Ids::STRIPPED_WARPED_STEM, fn() => Blocks::WARPED_STEM()); - $this->mapSimple(Ids::WARPED_FENCE, fn() => Blocks::WARPED_FENCE()); - $this->mapSimple(Ids::WARPED_PLANKS, fn() => Blocks::WARPED_PLANKS()); - $this->mapSlab(Ids::WARPED_SLAB, Ids::WARPED_DOUBLE_SLAB, fn() => Blocks::WARPED_SLAB()); - $this->mapStairs(Ids::WARPED_STAIRS, fn() => Blocks::WARPED_STAIRS()); - } - - private function registerLeavesDeserializers() : void{ - $this->map(Ids::ACACIA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::ACACIA_LEAVES(), $in)); - $this->map(Ids::AZALEA_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::AZALEA_LEAVES(), $in)); - $this->map(Ids::AZALEA_LEAVES_FLOWERED, fn(Reader $in) => Helper::decodeLeaves(Blocks::FLOWERING_AZALEA_LEAVES(), $in)); - $this->map(Ids::BIRCH_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::BIRCH_LEAVES(), $in)); - $this->map(Ids::CHERRY_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::CHERRY_LEAVES(), $in)); - $this->map(Ids::DARK_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::DARK_OAK_LEAVES(), $in)); - $this->map(Ids::JUNGLE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::JUNGLE_LEAVES(), $in)); - $this->map(Ids::MANGROVE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::MANGROVE_LEAVES(), $in)); - $this->map(Ids::OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::OAK_LEAVES(), $in)); - $this->map(Ids::PALE_OAK_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::PALE_OAK_LEAVES(), $in)); - $this->map(Ids::SPRUCE_LEAVES, fn(Reader $in) => Helper::decodeLeaves(Blocks::SPRUCE_LEAVES(), $in)); - } - - private function registerSaplingDeserializers() : void{ - foreach([ - Ids::ACACIA_SAPLING => fn() => Blocks::ACACIA_SAPLING(), - Ids::BIRCH_SAPLING => fn() => Blocks::BIRCH_SAPLING(), - Ids::DARK_OAK_SAPLING => fn() => Blocks::DARK_OAK_SAPLING(), - Ids::JUNGLE_SAPLING => fn() => Blocks::JUNGLE_SAPLING(), - Ids::OAK_SAPLING => fn() => Blocks::OAK_SAPLING(), - Ids::SPRUCE_SAPLING => fn() => Blocks::SPRUCE_SAPLING(), - ] as $id => $getBlock){ - $this->map($id, fn(Reader $in) => Helper::decodeSapling($getBlock(), $in)); - } - } - - private function registerLightDeserializers() : void{ - foreach([ - Ids::LIGHT_BLOCK_0 => 0, - Ids::LIGHT_BLOCK_1 => 1, - Ids::LIGHT_BLOCK_2 => 2, - Ids::LIGHT_BLOCK_3 => 3, - Ids::LIGHT_BLOCK_4 => 4, - Ids::LIGHT_BLOCK_5 => 5, - Ids::LIGHT_BLOCK_6 => 6, - Ids::LIGHT_BLOCK_7 => 7, - Ids::LIGHT_BLOCK_8 => 8, - Ids::LIGHT_BLOCK_9 => 9, - Ids::LIGHT_BLOCK_10 => 10, - Ids::LIGHT_BLOCK_11 => 11, - Ids::LIGHT_BLOCK_12 => 12, - Ids::LIGHT_BLOCK_13 => 13, - Ids::LIGHT_BLOCK_14 => 14, - Ids::LIGHT_BLOCK_15 => 15, - ] as $id => $level){ - $this->mapSimple($id, fn() => Blocks::LIGHT()->setLightLevel($level)); - } - } - - private function registerMobHeadDeserializers() : void{ - foreach([ - Ids::CREEPER_HEAD => MobHeadType::CREEPER, - Ids::DRAGON_HEAD => MobHeadType::DRAGON, - Ids::PIGLIN_HEAD => MobHeadType::PIGLIN, - Ids::PLAYER_HEAD => MobHeadType::PLAYER, - Ids::SKELETON_SKULL => MobHeadType::SKELETON, - Ids::WITHER_SKELETON_SKULL => MobHeadType::WITHER_SKELETON, - Ids::ZOMBIE_HEAD => MobHeadType::ZOMBIE - ] as $id => $mobHeadType){ - $this->map($id, fn(Reader $in) => Blocks::MOB_HEAD()->setMobHeadType($mobHeadType)->setFacing($in->readFacingWithoutDown())); - } - } - - /** - * @phpstan-param \Closure(Reader) : (CopperMaterial&Block) $deserializer - */ - private function mapCopper( - string $normalId, - string $waxedNormalId, - string $exposedId, - string $waxedExposedId, - string $weatheredId, - string $waxedWeatheredId, - string $oxidizedId, - string $waxedOxidizedId, - \Closure $deserializer - ) : void{ - foreach(Utils::stringifyKeys([ - $normalId => [CopperOxidation::NONE, false], - $waxedNormalId => [CopperOxidation::NONE, true], - $exposedId => [CopperOxidation::EXPOSED, false], - $waxedExposedId => [CopperOxidation::EXPOSED, true], - $weatheredId => [CopperOxidation::WEATHERED, false], - $waxedWeatheredId => [CopperOxidation::WEATHERED, true], - $oxidizedId => [CopperOxidation::OXIDIZED, false], - $waxedOxidizedId => [CopperOxidation::OXIDIZED, true], - ]) as $id => [$oxidation, $waxed]){ - $this->map($id, fn(Reader $in) => $deserializer($in)->setOxidation($oxidation)->setWaxed($waxed)); - } - } - - private function registerCopperDeserializers() : void{ - $this->mapCopper( - Ids::CUT_COPPER_SLAB, - Ids::WAXED_CUT_COPPER_SLAB, - Ids::EXPOSED_CUT_COPPER_SLAB, - Ids::WAXED_EXPOSED_CUT_COPPER_SLAB, - Ids::WEATHERED_CUT_COPPER_SLAB, - Ids::WAXED_WEATHERED_CUT_COPPER_SLAB, - Ids::OXIDIZED_CUT_COPPER_SLAB, - Ids::WAXED_OXIDIZED_CUT_COPPER_SLAB, - fn(Reader $in) => Helper::decodeSingleSlab(Blocks::CUT_COPPER_SLAB(), $in) - ); - $this->mapCopper( - Ids::DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_DOUBLE_CUT_COPPER_SLAB, - Ids::EXPOSED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_EXPOSED_DOUBLE_CUT_COPPER_SLAB, - Ids::WEATHERED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_WEATHERED_DOUBLE_CUT_COPPER_SLAB, - Ids::OXIDIZED_DOUBLE_CUT_COPPER_SLAB, - Ids::WAXED_OXIDIZED_DOUBLE_CUT_COPPER_SLAB, - fn(Reader $in) => Helper::decodeDoubleSlab(Blocks::CUT_COPPER_SLAB(), $in) - ); - - $this->mapCopper( - Ids::COPPER_BULB, - Ids::WAXED_COPPER_BULB, - Ids::EXPOSED_COPPER_BULB, - Ids::WAXED_EXPOSED_COPPER_BULB, - Ids::WEATHERED_COPPER_BULB, - Ids::WAXED_WEATHERED_COPPER_BULB, - Ids::OXIDIZED_COPPER_BULB, - Ids::WAXED_OXIDIZED_COPPER_BULB, - fn(Reader $in) => Blocks::COPPER_BULB() - ->setLit($in->readBool(StateNames::LIT)) - ->setPowered($in->readBool(StateNames::POWERED_BIT)) - ); - $this->mapCopper( - Ids::COPPER_DOOR, - Ids::WAXED_COPPER_DOOR, - Ids::EXPOSED_COPPER_DOOR, - Ids::WAXED_EXPOSED_COPPER_DOOR, - Ids::WEATHERED_COPPER_DOOR, - Ids::WAXED_WEATHERED_COPPER_DOOR, - Ids::OXIDIZED_COPPER_DOOR, - Ids::WAXED_OXIDIZED_COPPER_DOOR, - fn(Reader $in) => Helper::decodeDoor(Blocks::COPPER_DOOR(), $in) - ); - $this->mapCopper( - Ids::COPPER_TRAPDOOR, - Ids::WAXED_COPPER_TRAPDOOR, - Ids::EXPOSED_COPPER_TRAPDOOR, - Ids::WAXED_EXPOSED_COPPER_TRAPDOOR, - Ids::WEATHERED_COPPER_TRAPDOOR, - Ids::WAXED_WEATHERED_COPPER_TRAPDOOR, - Ids::OXIDIZED_COPPER_TRAPDOOR, - Ids::WAXED_OXIDIZED_COPPER_TRAPDOOR, - fn(Reader $in) => Helper::decodeTrapdoor(Blocks::COPPER_TRAPDOOR(), $in) - ); - $this->mapCopper( - Ids::COPPER_BLOCK, - Ids::WAXED_COPPER, - Ids::EXPOSED_COPPER, - Ids::WAXED_EXPOSED_COPPER, - Ids::WEATHERED_COPPER, - Ids::WAXED_WEATHERED_COPPER, - Ids::OXIDIZED_COPPER, - Ids::WAXED_OXIDIZED_COPPER, - fn(Reader $in) => Blocks::COPPER() - ); - $this->mapCopper( - Ids::CHISELED_COPPER, - Ids::WAXED_CHISELED_COPPER, - Ids::EXPOSED_CHISELED_COPPER, - Ids::WAXED_EXPOSED_CHISELED_COPPER, - Ids::WEATHERED_CHISELED_COPPER, - Ids::WAXED_WEATHERED_CHISELED_COPPER, - Ids::OXIDIZED_CHISELED_COPPER, - Ids::WAXED_OXIDIZED_CHISELED_COPPER, - fn(Reader $in) => Blocks::CHISELED_COPPER() - ); - $this->mapCopper( - Ids::COPPER_GRATE, - Ids::WAXED_COPPER_GRATE, - Ids::EXPOSED_COPPER_GRATE, - Ids::WAXED_EXPOSED_COPPER_GRATE, - Ids::WEATHERED_COPPER_GRATE, - Ids::WAXED_WEATHERED_COPPER_GRATE, - Ids::OXIDIZED_COPPER_GRATE, - Ids::WAXED_OXIDIZED_COPPER_GRATE, - fn(Reader $in) => Blocks::COPPER_GRATE() - ); - $this->mapCopper( - Ids::CUT_COPPER, - Ids::WAXED_CUT_COPPER, - Ids::EXPOSED_CUT_COPPER, - Ids::WAXED_EXPOSED_CUT_COPPER, - Ids::WEATHERED_CUT_COPPER, - Ids::WAXED_WEATHERED_CUT_COPPER, - Ids::OXIDIZED_CUT_COPPER, - Ids::WAXED_OXIDIZED_CUT_COPPER, - fn(Reader $in) => Blocks::CUT_COPPER() - ); - $this->mapCopper( - Ids::CUT_COPPER_STAIRS, - Ids::WAXED_CUT_COPPER_STAIRS, - Ids::EXPOSED_CUT_COPPER_STAIRS, - Ids::WAXED_EXPOSED_CUT_COPPER_STAIRS, - Ids::WEATHERED_CUT_COPPER_STAIRS, - Ids::WAXED_WEATHERED_CUT_COPPER_STAIRS, - Ids::OXIDIZED_CUT_COPPER_STAIRS, - Ids::WAXED_OXIDIZED_CUT_COPPER_STAIRS, - fn(Reader $in) => Helper::decodeStairs(Blocks::CUT_COPPER_STAIRS(), $in) - ); - } - - private function registerSimpleDeserializers() : void{ - $this->mapSimple(Ids::AIR, fn() => Blocks::AIR()); - $this->mapSimple(Ids::AMETHYST_BLOCK, fn() => Blocks::AMETHYST()); - $this->mapSimple(Ids::ANCIENT_DEBRIS, fn() => Blocks::ANCIENT_DEBRIS()); - $this->mapSimple(Ids::ANDESITE, fn() => Blocks::ANDESITE()); - $this->mapSimple(Ids::BARRIER, fn() => Blocks::BARRIER()); - $this->mapSimple(Ids::BEACON, fn() => Blocks::BEACON()); - $this->mapSimple(Ids::BLACKSTONE, fn() => Blocks::BLACKSTONE()); - $this->mapSimple(Ids::BLUE_ICE, fn() => Blocks::BLUE_ICE()); - $this->mapSimple(Ids::BOOKSHELF, fn() => Blocks::BOOKSHELF()); - $this->mapSimple(Ids::BRICK_BLOCK, fn() => Blocks::BRICKS()); - $this->mapSimple(Ids::BROWN_MUSHROOM, fn() => Blocks::BROWN_MUSHROOM()); - $this->mapSimple(Ids::BUDDING_AMETHYST, fn() => Blocks::BUDDING_AMETHYST()); - $this->mapSimple(Ids::CALCITE, fn() => Blocks::CALCITE()); - $this->mapSimple(Ids::CARTOGRAPHY_TABLE, fn() => Blocks::CARTOGRAPHY_TABLE()); - $this->mapSimple(Ids::CHEMICAL_HEAT, fn() => Blocks::CHEMICAL_HEAT()); - $this->mapSimple(Ids::CHISELED_DEEPSLATE, fn() => Blocks::CHISELED_DEEPSLATE()); - $this->mapSimple(Ids::CHISELED_NETHER_BRICKS, fn() => Blocks::CHISELED_NETHER_BRICKS()); - $this->mapSimple(Ids::CHISELED_POLISHED_BLACKSTONE, fn() => Blocks::CHISELED_POLISHED_BLACKSTONE()); - $this->mapSimple(Ids::CHISELED_RED_SANDSTONE, fn() => Blocks::CHISELED_RED_SANDSTONE()); - $this->mapSimple(Ids::CHISELED_RESIN_BRICKS, fn() => Blocks::CHISELED_RESIN_BRICKS()); - $this->mapSimple(Ids::CHISELED_SANDSTONE, fn() => Blocks::CHISELED_SANDSTONE()); - $this->mapSimple(Ids::CHISELED_STONE_BRICKS, fn() => Blocks::CHISELED_STONE_BRICKS()); - $this->mapSimple(Ids::CHISELED_TUFF, fn() => Blocks::CHISELED_TUFF()); - $this->mapSimple(Ids::CHISELED_TUFF_BRICKS, fn() => Blocks::CHISELED_TUFF_BRICKS()); - $this->mapSimple(Ids::CHORUS_PLANT, fn() => Blocks::CHORUS_PLANT()); - $this->mapSimple(Ids::CLAY, fn() => Blocks::CLAY()); - $this->mapSimple(Ids::COAL_BLOCK, fn() => Blocks::COAL()); - $this->mapSimple(Ids::COAL_ORE, fn() => Blocks::COAL_ORE()); - $this->mapSimple(Ids::COBBLED_DEEPSLATE, fn() => Blocks::COBBLED_DEEPSLATE()); - $this->mapSimple(Ids::COBBLESTONE, fn() => Blocks::COBBLESTONE()); - $this->mapSimple(Ids::COPPER_ORE, fn() => Blocks::COPPER_ORE()); - $this->mapSimple(Ids::CRACKED_DEEPSLATE_BRICKS, fn() => Blocks::CRACKED_DEEPSLATE_BRICKS()); - $this->mapSimple(Ids::CRACKED_DEEPSLATE_TILES, fn() => Blocks::CRACKED_DEEPSLATE_TILES()); - $this->mapSimple(Ids::CRACKED_NETHER_BRICKS, fn() => Blocks::CRACKED_NETHER_BRICKS()); - $this->mapSimple(Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS()); - $this->mapSimple(Ids::CRACKED_STONE_BRICKS, fn() => Blocks::CRACKED_STONE_BRICKS()); - $this->mapSimple(Ids::CRAFTING_TABLE, fn() => Blocks::CRAFTING_TABLE()); - $this->mapSimple(Ids::CRIMSON_ROOTS, fn() => Blocks::CRIMSON_ROOTS()); - $this->mapSimple(Ids::CRYING_OBSIDIAN, fn() => Blocks::CRYING_OBSIDIAN()); - $this->mapSimple(Ids::CUT_RED_SANDSTONE, fn() => Blocks::CUT_RED_SANDSTONE()); - $this->mapSimple(Ids::CUT_SANDSTONE, fn() => Blocks::CUT_SANDSTONE()); - $this->mapSimple(Ids::DARK_PRISMARINE, fn() => Blocks::DARK_PRISMARINE()); - $this->mapSimple(Ids::DEADBUSH, fn() => Blocks::DEAD_BUSH()); - $this->mapSimple(Ids::DEEPSLATE_BRICKS, fn() => Blocks::DEEPSLATE_BRICKS()); - $this->mapSimple(Ids::DEEPSLATE_COAL_ORE, fn() => Blocks::DEEPSLATE_COAL_ORE()); - $this->mapSimple(Ids::DEEPSLATE_COPPER_ORE, fn() => Blocks::DEEPSLATE_COPPER_ORE()); - $this->mapSimple(Ids::DEEPSLATE_DIAMOND_ORE, fn() => Blocks::DEEPSLATE_DIAMOND_ORE()); - $this->mapSimple(Ids::DEEPSLATE_EMERALD_ORE, fn() => Blocks::DEEPSLATE_EMERALD_ORE()); - $this->mapSimple(Ids::DEEPSLATE_GOLD_ORE, fn() => Blocks::DEEPSLATE_GOLD_ORE()); - $this->mapSimple(Ids::DEEPSLATE_IRON_ORE, fn() => Blocks::DEEPSLATE_IRON_ORE()); - $this->mapSimple(Ids::DEEPSLATE_LAPIS_ORE, fn() => Blocks::DEEPSLATE_LAPIS_LAZULI_ORE()); - $this->mapSimple(Ids::DEEPSLATE_TILES, fn() => Blocks::DEEPSLATE_TILES()); - $this->mapSimple(Ids::DIAMOND_BLOCK, fn() => Blocks::DIAMOND()); - $this->mapSimple(Ids::DIAMOND_ORE, fn() => Blocks::DIAMOND_ORE()); - $this->mapSimple(Ids::DIORITE, fn() => Blocks::DIORITE()); - $this->mapSimple(Ids::DRAGON_EGG, fn() => Blocks::DRAGON_EGG()); - $this->mapSimple(Ids::DRIED_KELP_BLOCK, fn() => Blocks::DRIED_KELP()); - $this->mapSimple(Ids::ELEMENT_0, fn() => Blocks::ELEMENT_ZERO()); - $this->mapSimple(Ids::ELEMENT_1, fn() => Blocks::ELEMENT_HYDROGEN()); - $this->mapSimple(Ids::ELEMENT_10, fn() => Blocks::ELEMENT_NEON()); - $this->mapSimple(Ids::ELEMENT_100, fn() => Blocks::ELEMENT_FERMIUM()); - $this->mapSimple(Ids::ELEMENT_101, fn() => Blocks::ELEMENT_MENDELEVIUM()); - $this->mapSimple(Ids::ELEMENT_102, fn() => Blocks::ELEMENT_NOBELIUM()); - $this->mapSimple(Ids::ELEMENT_103, fn() => Blocks::ELEMENT_LAWRENCIUM()); - $this->mapSimple(Ids::ELEMENT_104, fn() => Blocks::ELEMENT_RUTHERFORDIUM()); - $this->mapSimple(Ids::ELEMENT_105, fn() => Blocks::ELEMENT_DUBNIUM()); - $this->mapSimple(Ids::ELEMENT_106, fn() => Blocks::ELEMENT_SEABORGIUM()); - $this->mapSimple(Ids::ELEMENT_107, fn() => Blocks::ELEMENT_BOHRIUM()); - $this->mapSimple(Ids::ELEMENT_108, fn() => Blocks::ELEMENT_HASSIUM()); - $this->mapSimple(Ids::ELEMENT_109, fn() => Blocks::ELEMENT_MEITNERIUM()); - $this->mapSimple(Ids::ELEMENT_11, fn() => Blocks::ELEMENT_SODIUM()); - $this->mapSimple(Ids::ELEMENT_110, fn() => Blocks::ELEMENT_DARMSTADTIUM()); - $this->mapSimple(Ids::ELEMENT_111, fn() => Blocks::ELEMENT_ROENTGENIUM()); - $this->mapSimple(Ids::ELEMENT_112, fn() => Blocks::ELEMENT_COPERNICIUM()); - $this->mapSimple(Ids::ELEMENT_113, fn() => Blocks::ELEMENT_NIHONIUM()); - $this->mapSimple(Ids::ELEMENT_114, fn() => Blocks::ELEMENT_FLEROVIUM()); - $this->mapSimple(Ids::ELEMENT_115, fn() => Blocks::ELEMENT_MOSCOVIUM()); - $this->mapSimple(Ids::ELEMENT_116, fn() => Blocks::ELEMENT_LIVERMORIUM()); - $this->mapSimple(Ids::ELEMENT_117, fn() => Blocks::ELEMENT_TENNESSINE()); - $this->mapSimple(Ids::ELEMENT_118, fn() => Blocks::ELEMENT_OGANESSON()); - $this->mapSimple(Ids::ELEMENT_12, fn() => Blocks::ELEMENT_MAGNESIUM()); - $this->mapSimple(Ids::ELEMENT_13, fn() => Blocks::ELEMENT_ALUMINUM()); - $this->mapSimple(Ids::ELEMENT_14, fn() => Blocks::ELEMENT_SILICON()); - $this->mapSimple(Ids::ELEMENT_15, fn() => Blocks::ELEMENT_PHOSPHORUS()); - $this->mapSimple(Ids::ELEMENT_16, fn() => Blocks::ELEMENT_SULFUR()); - $this->mapSimple(Ids::ELEMENT_17, fn() => Blocks::ELEMENT_CHLORINE()); - $this->mapSimple(Ids::ELEMENT_18, fn() => Blocks::ELEMENT_ARGON()); - $this->mapSimple(Ids::ELEMENT_19, fn() => Blocks::ELEMENT_POTASSIUM()); - $this->mapSimple(Ids::ELEMENT_2, fn() => Blocks::ELEMENT_HELIUM()); - $this->mapSimple(Ids::ELEMENT_20, fn() => Blocks::ELEMENT_CALCIUM()); - $this->mapSimple(Ids::ELEMENT_21, fn() => Blocks::ELEMENT_SCANDIUM()); - $this->mapSimple(Ids::ELEMENT_22, fn() => Blocks::ELEMENT_TITANIUM()); - $this->mapSimple(Ids::ELEMENT_23, fn() => Blocks::ELEMENT_VANADIUM()); - $this->mapSimple(Ids::ELEMENT_24, fn() => Blocks::ELEMENT_CHROMIUM()); - $this->mapSimple(Ids::ELEMENT_25, fn() => Blocks::ELEMENT_MANGANESE()); - $this->mapSimple(Ids::ELEMENT_26, fn() => Blocks::ELEMENT_IRON()); - $this->mapSimple(Ids::ELEMENT_27, fn() => Blocks::ELEMENT_COBALT()); - $this->mapSimple(Ids::ELEMENT_28, fn() => Blocks::ELEMENT_NICKEL()); - $this->mapSimple(Ids::ELEMENT_29, fn() => Blocks::ELEMENT_COPPER()); - $this->mapSimple(Ids::ELEMENT_3, fn() => Blocks::ELEMENT_LITHIUM()); - $this->mapSimple(Ids::ELEMENT_30, fn() => Blocks::ELEMENT_ZINC()); - $this->mapSimple(Ids::ELEMENT_31, fn() => Blocks::ELEMENT_GALLIUM()); - $this->mapSimple(Ids::ELEMENT_32, fn() => Blocks::ELEMENT_GERMANIUM()); - $this->mapSimple(Ids::ELEMENT_33, fn() => Blocks::ELEMENT_ARSENIC()); - $this->mapSimple(Ids::ELEMENT_34, fn() => Blocks::ELEMENT_SELENIUM()); - $this->mapSimple(Ids::ELEMENT_35, fn() => Blocks::ELEMENT_BROMINE()); - $this->mapSimple(Ids::ELEMENT_36, fn() => Blocks::ELEMENT_KRYPTON()); - $this->mapSimple(Ids::ELEMENT_37, fn() => Blocks::ELEMENT_RUBIDIUM()); - $this->mapSimple(Ids::ELEMENT_38, fn() => Blocks::ELEMENT_STRONTIUM()); - $this->mapSimple(Ids::ELEMENT_39, fn() => Blocks::ELEMENT_YTTRIUM()); - $this->mapSimple(Ids::ELEMENT_4, fn() => Blocks::ELEMENT_BERYLLIUM()); - $this->mapSimple(Ids::ELEMENT_40, fn() => Blocks::ELEMENT_ZIRCONIUM()); - $this->mapSimple(Ids::ELEMENT_41, fn() => Blocks::ELEMENT_NIOBIUM()); - $this->mapSimple(Ids::ELEMENT_42, fn() => Blocks::ELEMENT_MOLYBDENUM()); - $this->mapSimple(Ids::ELEMENT_43, fn() => Blocks::ELEMENT_TECHNETIUM()); - $this->mapSimple(Ids::ELEMENT_44, fn() => Blocks::ELEMENT_RUTHENIUM()); - $this->mapSimple(Ids::ELEMENT_45, fn() => Blocks::ELEMENT_RHODIUM()); - $this->mapSimple(Ids::ELEMENT_46, fn() => Blocks::ELEMENT_PALLADIUM()); - $this->mapSimple(Ids::ELEMENT_47, fn() => Blocks::ELEMENT_SILVER()); - $this->mapSimple(Ids::ELEMENT_48, fn() => Blocks::ELEMENT_CADMIUM()); - $this->mapSimple(Ids::ELEMENT_49, fn() => Blocks::ELEMENT_INDIUM()); - $this->mapSimple(Ids::ELEMENT_5, fn() => Blocks::ELEMENT_BORON()); - $this->mapSimple(Ids::ELEMENT_50, fn() => Blocks::ELEMENT_TIN()); - $this->mapSimple(Ids::ELEMENT_51, fn() => Blocks::ELEMENT_ANTIMONY()); - $this->mapSimple(Ids::ELEMENT_52, fn() => Blocks::ELEMENT_TELLURIUM()); - $this->mapSimple(Ids::ELEMENT_53, fn() => Blocks::ELEMENT_IODINE()); - $this->mapSimple(Ids::ELEMENT_54, fn() => Blocks::ELEMENT_XENON()); - $this->mapSimple(Ids::ELEMENT_55, fn() => Blocks::ELEMENT_CESIUM()); - $this->mapSimple(Ids::ELEMENT_56, fn() => Blocks::ELEMENT_BARIUM()); - $this->mapSimple(Ids::ELEMENT_57, fn() => Blocks::ELEMENT_LANTHANUM()); - $this->mapSimple(Ids::ELEMENT_58, fn() => Blocks::ELEMENT_CERIUM()); - $this->mapSimple(Ids::ELEMENT_59, fn() => Blocks::ELEMENT_PRASEODYMIUM()); - $this->mapSimple(Ids::ELEMENT_6, fn() => Blocks::ELEMENT_CARBON()); - $this->mapSimple(Ids::ELEMENT_60, fn() => Blocks::ELEMENT_NEODYMIUM()); - $this->mapSimple(Ids::ELEMENT_61, fn() => Blocks::ELEMENT_PROMETHIUM()); - $this->mapSimple(Ids::ELEMENT_62, fn() => Blocks::ELEMENT_SAMARIUM()); - $this->mapSimple(Ids::ELEMENT_63, fn() => Blocks::ELEMENT_EUROPIUM()); - $this->mapSimple(Ids::ELEMENT_64, fn() => Blocks::ELEMENT_GADOLINIUM()); - $this->mapSimple(Ids::ELEMENT_65, fn() => Blocks::ELEMENT_TERBIUM()); - $this->mapSimple(Ids::ELEMENT_66, fn() => Blocks::ELEMENT_DYSPROSIUM()); - $this->mapSimple(Ids::ELEMENT_67, fn() => Blocks::ELEMENT_HOLMIUM()); - $this->mapSimple(Ids::ELEMENT_68, fn() => Blocks::ELEMENT_ERBIUM()); - $this->mapSimple(Ids::ELEMENT_69, fn() => Blocks::ELEMENT_THULIUM()); - $this->mapSimple(Ids::ELEMENT_7, fn() => Blocks::ELEMENT_NITROGEN()); - $this->mapSimple(Ids::ELEMENT_70, fn() => Blocks::ELEMENT_YTTERBIUM()); - $this->mapSimple(Ids::ELEMENT_71, fn() => Blocks::ELEMENT_LUTETIUM()); - $this->mapSimple(Ids::ELEMENT_72, fn() => Blocks::ELEMENT_HAFNIUM()); - $this->mapSimple(Ids::ELEMENT_73, fn() => Blocks::ELEMENT_TANTALUM()); - $this->mapSimple(Ids::ELEMENT_74, fn() => Blocks::ELEMENT_TUNGSTEN()); - $this->mapSimple(Ids::ELEMENT_75, fn() => Blocks::ELEMENT_RHENIUM()); - $this->mapSimple(Ids::ELEMENT_76, fn() => Blocks::ELEMENT_OSMIUM()); - $this->mapSimple(Ids::ELEMENT_77, fn() => Blocks::ELEMENT_IRIDIUM()); - $this->mapSimple(Ids::ELEMENT_78, fn() => Blocks::ELEMENT_PLATINUM()); - $this->mapSimple(Ids::ELEMENT_79, fn() => Blocks::ELEMENT_GOLD()); - $this->mapSimple(Ids::ELEMENT_8, fn() => Blocks::ELEMENT_OXYGEN()); - $this->mapSimple(Ids::ELEMENT_80, fn() => Blocks::ELEMENT_MERCURY()); - $this->mapSimple(Ids::ELEMENT_81, fn() => Blocks::ELEMENT_THALLIUM()); - $this->mapSimple(Ids::ELEMENT_82, fn() => Blocks::ELEMENT_LEAD()); - $this->mapSimple(Ids::ELEMENT_83, fn() => Blocks::ELEMENT_BISMUTH()); - $this->mapSimple(Ids::ELEMENT_84, fn() => Blocks::ELEMENT_POLONIUM()); - $this->mapSimple(Ids::ELEMENT_85, fn() => Blocks::ELEMENT_ASTATINE()); - $this->mapSimple(Ids::ELEMENT_86, fn() => Blocks::ELEMENT_RADON()); - $this->mapSimple(Ids::ELEMENT_87, fn() => Blocks::ELEMENT_FRANCIUM()); - $this->mapSimple(Ids::ELEMENT_88, fn() => Blocks::ELEMENT_RADIUM()); - $this->mapSimple(Ids::ELEMENT_89, fn() => Blocks::ELEMENT_ACTINIUM()); - $this->mapSimple(Ids::ELEMENT_9, fn() => Blocks::ELEMENT_FLUORINE()); - $this->mapSimple(Ids::ELEMENT_90, fn() => Blocks::ELEMENT_THORIUM()); - $this->mapSimple(Ids::ELEMENT_91, fn() => Blocks::ELEMENT_PROTACTINIUM()); - $this->mapSimple(Ids::ELEMENT_92, fn() => Blocks::ELEMENT_URANIUM()); - $this->mapSimple(Ids::ELEMENT_93, fn() => Blocks::ELEMENT_NEPTUNIUM()); - $this->mapSimple(Ids::ELEMENT_94, fn() => Blocks::ELEMENT_PLUTONIUM()); - $this->mapSimple(Ids::ELEMENT_95, fn() => Blocks::ELEMENT_AMERICIUM()); - $this->mapSimple(Ids::ELEMENT_96, fn() => Blocks::ELEMENT_CURIUM()); - $this->mapSimple(Ids::ELEMENT_97, fn() => Blocks::ELEMENT_BERKELIUM()); - $this->mapSimple(Ids::ELEMENT_98, fn() => Blocks::ELEMENT_CALIFORNIUM()); - $this->mapSimple(Ids::ELEMENT_99, fn() => Blocks::ELEMENT_EINSTEINIUM()); - $this->mapSimple(Ids::EMERALD_BLOCK, fn() => Blocks::EMERALD()); - $this->mapSimple(Ids::EMERALD_ORE, fn() => Blocks::EMERALD_ORE()); - $this->mapSimple(Ids::ENCHANTING_TABLE, fn() => Blocks::ENCHANTING_TABLE()); - $this->mapSimple(Ids::END_BRICKS, fn() => Blocks::END_STONE_BRICKS()); - $this->mapSimple(Ids::END_STONE, fn() => Blocks::END_STONE()); - $this->mapSimple(Ids::FERN, fn() => Blocks::FERN()); - $this->mapSimple(Ids::FLETCHING_TABLE, fn() => Blocks::FLETCHING_TABLE()); - $this->mapSimple(Ids::GILDED_BLACKSTONE, fn() => Blocks::GILDED_BLACKSTONE()); - $this->mapSimple(Ids::GLASS, fn() => Blocks::GLASS()); - $this->mapSimple(Ids::GLASS_PANE, fn() => Blocks::GLASS_PANE()); - $this->mapSimple(Ids::GLOWINGOBSIDIAN, fn() => Blocks::GLOWING_OBSIDIAN()); - $this->mapSimple(Ids::GLOWSTONE, fn() => Blocks::GLOWSTONE()); - $this->mapSimple(Ids::GOLD_BLOCK, fn() => Blocks::GOLD()); - $this->mapSimple(Ids::GOLD_ORE, fn() => Blocks::GOLD_ORE()); - $this->mapSimple(Ids::GRANITE, fn() => Blocks::GRANITE()); - $this->mapSimple(Ids::GRASS_BLOCK, fn() => Blocks::GRASS()); - $this->mapSimple(Ids::GRASS_PATH, fn() => Blocks::GRASS_PATH()); - $this->mapSimple(Ids::GRAVEL, fn() => Blocks::GRAVEL()); - $this->mapSimple(Ids::HANGING_ROOTS, fn() => Blocks::HANGING_ROOTS()); - $this->mapSimple(Ids::HARD_GLASS, fn() => Blocks::HARDENED_GLASS()); - $this->mapSimple(Ids::HARD_GLASS_PANE, fn() => Blocks::HARDENED_GLASS_PANE()); - $this->mapSimple(Ids::HARDENED_CLAY, fn() => Blocks::HARDENED_CLAY()); - $this->mapSimple(Ids::HONEYCOMB_BLOCK, fn() => Blocks::HONEYCOMB()); - $this->mapSimple(Ids::ICE, fn() => Blocks::ICE()); - $this->mapSimple(Ids::INFESTED_CHISELED_STONE_BRICKS, fn() => Blocks::INFESTED_CHISELED_STONE_BRICK()); - $this->mapSimple(Ids::INFESTED_COBBLESTONE, fn() => Blocks::INFESTED_COBBLESTONE()); - $this->mapSimple(Ids::INFESTED_CRACKED_STONE_BRICKS, fn() => Blocks::INFESTED_CRACKED_STONE_BRICK()); - $this->mapSimple(Ids::INFESTED_MOSSY_STONE_BRICKS, fn() => Blocks::INFESTED_MOSSY_STONE_BRICK()); - $this->mapSimple(Ids::INFESTED_STONE, fn() => Blocks::INFESTED_STONE()); - $this->mapSimple(Ids::INFESTED_STONE_BRICKS, fn() => Blocks::INFESTED_STONE_BRICK()); - $this->mapSimple(Ids::INFO_UPDATE, fn() => Blocks::INFO_UPDATE()); - $this->mapSimple(Ids::INFO_UPDATE2, fn() => Blocks::INFO_UPDATE2()); - $this->mapSimple(Ids::INVISIBLE_BEDROCK, fn() => Blocks::INVISIBLE_BEDROCK()); - $this->mapSimple(Ids::IRON_BARS, fn() => Blocks::IRON_BARS()); - $this->mapSimple(Ids::IRON_BLOCK, fn() => Blocks::IRON()); - $this->mapSimple(Ids::IRON_ORE, fn() => Blocks::IRON_ORE()); - $this->mapSimple(Ids::JUKEBOX, fn() => Blocks::JUKEBOX()); - $this->mapSimple(Ids::LAPIS_BLOCK, fn() => Blocks::LAPIS_LAZULI()); - $this->mapSimple(Ids::LAPIS_ORE, fn() => Blocks::LAPIS_LAZULI_ORE()); - $this->mapSimple(Ids::MAGMA, fn() => Blocks::MAGMA()); - $this->mapSimple(Ids::MANGROVE_ROOTS, fn() => Blocks::MANGROVE_ROOTS()); - $this->mapSimple(Ids::MELON_BLOCK, fn() => Blocks::MELON()); - $this->mapSimple(Ids::MOB_SPAWNER, fn() => Blocks::MONSTER_SPAWNER()); - $this->mapSimple(Ids::MOSSY_COBBLESTONE, fn() => Blocks::MOSSY_COBBLESTONE()); - $this->mapSimple(Ids::MOSSY_STONE_BRICKS, fn() => Blocks::MOSSY_STONE_BRICKS()); - $this->mapSimple(Ids::MUD, fn() => Blocks::MUD()); - $this->mapSimple(Ids::MUD_BRICKS, fn() => Blocks::MUD_BRICKS()); - $this->mapSimple(Ids::MYCELIUM, fn() => Blocks::MYCELIUM()); - $this->mapSimple(Ids::NETHER_BRICK, fn() => Blocks::NETHER_BRICKS()); - $this->mapSimple(Ids::NETHER_BRICK_FENCE, fn() => Blocks::NETHER_BRICK_FENCE()); - $this->mapSimple(Ids::NETHER_GOLD_ORE, fn() => Blocks::NETHER_GOLD_ORE()); - $this->mapSimple(Ids::NETHER_WART_BLOCK, fn() => Blocks::NETHER_WART_BLOCK()); - $this->mapSimple(Ids::NETHERITE_BLOCK, fn() => Blocks::NETHERITE()); - $this->mapSimple(Ids::NETHERRACK, fn() => Blocks::NETHERRACK()); - $this->mapSimple(Ids::NETHERREACTOR, fn() => Blocks::NETHER_REACTOR_CORE()); - $this->mapSimple(Ids::NOTEBLOCK, fn() => Blocks::NOTE_BLOCK()); - $this->mapSimple(Ids::OBSIDIAN, fn() => Blocks::OBSIDIAN()); - $this->mapSimple(Ids::PACKED_ICE, fn() => Blocks::PACKED_ICE()); - $this->mapSimple(Ids::PACKED_MUD, fn() => Blocks::PACKED_MUD()); - $this->mapSimple(Ids::PODZOL, fn() => Blocks::PODZOL()); - $this->mapSimple(Ids::POLISHED_ANDESITE, fn() => Blocks::POLISHED_ANDESITE()); - $this->mapSimple(Ids::POLISHED_BLACKSTONE, fn() => Blocks::POLISHED_BLACKSTONE()); - $this->mapSimple(Ids::POLISHED_BLACKSTONE_BRICKS, fn() => Blocks::POLISHED_BLACKSTONE_BRICKS()); - $this->mapSimple(Ids::POLISHED_DEEPSLATE, fn() => Blocks::POLISHED_DEEPSLATE()); - $this->mapSimple(Ids::POLISHED_DIORITE, fn() => Blocks::POLISHED_DIORITE()); - $this->mapSimple(Ids::POLISHED_GRANITE, fn() => Blocks::POLISHED_GRANITE()); - $this->mapSimple(Ids::POLISHED_TUFF, fn() => Blocks::POLISHED_TUFF()); - $this->mapSimple(Ids::PRISMARINE, fn() => Blocks::PRISMARINE()); - $this->mapSimple(Ids::PRISMARINE_BRICKS, fn() => Blocks::PRISMARINE_BRICKS()); - $this->mapSimple(Ids::QUARTZ_BRICKS, fn() => Blocks::QUARTZ_BRICKS()); - $this->mapSimple(Ids::QUARTZ_ORE, fn() => Blocks::NETHER_QUARTZ_ORE()); - $this->mapSimple(Ids::RAW_COPPER_BLOCK, fn() => Blocks::RAW_COPPER()); - $this->mapSimple(Ids::RAW_GOLD_BLOCK, fn() => Blocks::RAW_GOLD()); - $this->mapSimple(Ids::RAW_IRON_BLOCK, fn() => Blocks::RAW_IRON()); - $this->mapSimple(Ids::RED_MUSHROOM, fn() => Blocks::RED_MUSHROOM()); - $this->mapSimple(Ids::RED_NETHER_BRICK, fn() => Blocks::RED_NETHER_BRICKS()); - $this->mapSimple(Ids::RED_SAND, fn() => Blocks::RED_SAND()); - $this->mapSimple(Ids::RED_SANDSTONE, fn() => Blocks::RED_SANDSTONE()); - $this->mapSimple(Ids::REDSTONE_BLOCK, fn() => Blocks::REDSTONE()); - $this->mapSimple(Ids::REINFORCED_DEEPSLATE, fn() => Blocks::REINFORCED_DEEPSLATE()); - $this->mapSimple(Ids::RESERVED6, fn() => Blocks::RESERVED6()); - $this->mapSimple(Ids::RESIN_BLOCK, fn() => Blocks::RESIN()); - $this->mapSimple(Ids::RESIN_BRICKS, fn() => Blocks::RESIN_BRICKS()); - $this->mapSimple(Ids::SAND, fn() => Blocks::SAND()); - $this->mapSimple(Ids::SANDSTONE, fn() => Blocks::SANDSTONE()); - $this->mapSimple(Ids::SCULK, fn() => Blocks::SCULK()); - $this->mapSimple(Ids::SEA_LANTERN, fn() => Blocks::SEA_LANTERN()); - $this->mapSimple(Ids::SHORT_GRASS, fn() => Blocks::TALL_GRASS()); //no, this is not a typo - tall_grass is now the double block, just to be confusing :( - $this->mapSimple(Ids::SHROOMLIGHT, fn() => Blocks::SHROOMLIGHT()); - $this->mapSimple(Ids::SLIME, fn() => Blocks::SLIME()); - $this->mapSimple(Ids::SMITHING_TABLE, fn() => Blocks::SMITHING_TABLE()); - $this->mapSimple(Ids::SMOOTH_BASALT, fn() => Blocks::SMOOTH_BASALT()); - $this->mapSimple(Ids::SMOOTH_RED_SANDSTONE, fn() => Blocks::SMOOTH_RED_SANDSTONE()); - $this->mapSimple(Ids::SMOOTH_SANDSTONE, fn() => Blocks::SMOOTH_SANDSTONE()); - $this->mapSimple(Ids::SMOOTH_STONE, fn() => Blocks::SMOOTH_STONE()); - $this->mapSimple(Ids::SNOW, fn() => Blocks::SNOW()); - $this->mapSimple(Ids::SOUL_SAND, fn() => Blocks::SOUL_SAND()); - $this->mapSimple(Ids::SOUL_SOIL, fn() => Blocks::SOUL_SOIL()); - $this->mapSimple(Ids::SPORE_BLOSSOM, fn() => Blocks::SPORE_BLOSSOM()); - $this->mapSimple(Ids::SPONGE, fn() => Blocks::SPONGE()); - $this->mapSimple(Ids::STONE, fn() => Blocks::STONE()); - $this->mapSimple(Ids::STONECUTTER, fn() => Blocks::LEGACY_STONECUTTER()); - $this->mapSimple(Ids::STONE_BRICKS, fn() => Blocks::STONE_BRICKS()); - $this->mapSimple(Ids::TINTED_GLASS, fn() => Blocks::TINTED_GLASS()); - $this->mapSimple(Ids::TORCHFLOWER, fn() => Blocks::TORCHFLOWER()); - $this->mapSimple(Ids::TUFF, fn() => Blocks::TUFF()); - $this->mapSimple(Ids::TUFF_BRICKS, fn() => Blocks::TUFF_BRICKS()); - $this->mapSimple(Ids::UNDYED_SHULKER_BOX, fn() => Blocks::SHULKER_BOX()); - $this->mapSimple(Ids::WARPED_WART_BLOCK, fn() => Blocks::WARPED_WART_BLOCK()); - $this->mapSimple(Ids::WARPED_ROOTS, fn() => Blocks::WARPED_ROOTS()); - $this->mapSimple(Ids::WATERLILY, fn() => Blocks::LILY_PAD()); - $this->mapSimple(Ids::WEB, fn() => Blocks::COBWEB()); - $this->mapSimple(Ids::WET_SPONGE, fn() => Blocks::SPONGE()->setWet(true)); - $this->mapSimple(Ids::WITHER_ROSE, fn() => Blocks::WITHER_ROSE()); - $this->mapSimple(Ids::DANDELION, fn() => Blocks::DANDELION()); - - $this->mapSimple(Ids::ALLIUM, fn() => Blocks::ALLIUM()); - $this->mapSimple(Ids::CORNFLOWER, fn() => Blocks::CORNFLOWER()); - $this->mapSimple(Ids::AZURE_BLUET, fn() => Blocks::AZURE_BLUET()); - $this->mapSimple(Ids::LILY_OF_THE_VALLEY, fn() => Blocks::LILY_OF_THE_VALLEY()); - $this->mapSimple(Ids::BLUE_ORCHID, fn() => Blocks::BLUE_ORCHID()); - $this->mapSimple(Ids::OXEYE_DAISY, fn() => Blocks::OXEYE_DAISY()); - $this->mapSimple(Ids::POPPY, fn() => Blocks::POPPY()); - $this->mapSimple(Ids::ORANGE_TULIP, fn() => Blocks::ORANGE_TULIP()); - $this->mapSimple(Ids::PINK_TULIP, fn() => Blocks::PINK_TULIP()); - $this->mapSimple(Ids::RED_TULIP, fn() => Blocks::RED_TULIP()); - $this->mapSimple(Ids::WHITE_TULIP, fn() => Blocks::WHITE_TULIP()); - } - - private function registerDeserializers() : void{ - $this->map(Ids::ACTIVATOR_RAIL, function(Reader $in) : Block{ - return Blocks::ACTIVATOR_RAIL() - ->setPowered($in->readBool(StateNames::RAIL_DATA_BIT)) - ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5)); - }); - $this->map(Ids::AMETHYST_CLUSTER, function(Reader $in) : Block{ - return Blocks::AMETHYST_CLUSTER() - ->setStage(AmethystCluster::STAGE_CLUSTER) - ->setFacing($in->readBlockFace()); - }); - $this->mapSlab(Ids::ANDESITE_SLAB, Ids::ANDESITE_DOUBLE_SLAB, fn() => Blocks::ANDESITE_SLAB()); - $this->mapStairs(Ids::ANDESITE_STAIRS, fn() => Blocks::ANDESITE_STAIRS()); - $this->map(Ids::ANDESITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::ANDESITE_WALL(), $in)); - $this->map(Ids::ANVIL, function(Reader $in) : Block{ - return Blocks::ANVIL() - ->setDamage(Anvil::UNDAMAGED) - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::CHIPPED_ANVIL, function(Reader $in) : Block{ - return Blocks::ANVIL() - ->setDamage(Anvil::SLIGHTLY_DAMAGED) - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::DAMAGED_ANVIL, function(Reader $in) : Block{ - return Blocks::ANVIL() - ->setDamage(Anvil::VERY_DAMAGED) - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::BAMBOO, function(Reader $in) : Block{ - return Blocks::BAMBOO() - ->setLeafSize(match($value = $in->readString(StateNames::BAMBOO_LEAF_SIZE)){ - StringValues::BAMBOO_LEAF_SIZE_NO_LEAVES => Bamboo::NO_LEAVES, - StringValues::BAMBOO_LEAF_SIZE_SMALL_LEAVES => Bamboo::SMALL_LEAVES, - StringValues::BAMBOO_LEAF_SIZE_LARGE_LEAVES => Bamboo::LARGE_LEAVES, - default => throw $in->badValueException(StateNames::BAMBOO_LEAF_SIZE, $value), - }) - ->setReady($in->readBool(StateNames::AGE_BIT)) - ->setThick(match($value = $in->readString(StateNames::BAMBOO_STALK_THICKNESS)){ - StringValues::BAMBOO_STALK_THICKNESS_THIN => false, - StringValues::BAMBOO_STALK_THICKNESS_THICK => true, - default => throw $in->badValueException(StateNames::BAMBOO_STALK_THICKNESS, $value), - }); - }); - $this->map(Ids::BAMBOO_SAPLING, function(Reader $in) : Block{ - return Blocks::BAMBOO_SAPLING()->setReady($in->readBool(StateNames::AGE_BIT)); - }); - $this->map(Ids::BARREL, function(Reader $in) : Block{ - return Blocks::BARREL() - ->setFacing($in->readFacingDirection()) - ->setOpen($in->readBool(StateNames::OPEN_BIT)); - }); - $this->map(Ids::BASALT, function(Reader $in){ - return Blocks::BASALT() - ->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::BED, function(Reader $in) : Block{ - return Blocks::BED() - ->setFacing($in->readLegacyHorizontalFacing()) - ->setHead($in->readBool(StateNames::HEAD_PIECE_BIT)) - ->setOccupied($in->readBool(StateNames::OCCUPIED_BIT)); - }); - $this->map(Ids::BEDROCK, function(Reader $in) : Block{ - return Blocks::BEDROCK() - ->setBurnsForever($in->readBool(StateNames::INFINIBURN_BIT)); - }); - $this->map(Ids::BEETROOT, fn(Reader $in) => Helper::decodeCrops(Blocks::BEETROOTS(), $in)); - $this->map(Ids::BELL, function(Reader $in) : Block{ - $in->ignored(StateNames::TOGGLE_BIT); //only useful at runtime - return Blocks::BELL() - ->setFacing($in->readLegacyHorizontalFacing()) - ->setAttachmentType($in->readBellAttachmentType()); - }); - $this->map(Ids::BIG_DRIPLEAF, function(Reader $in) : Block{ - if($in->readBool(StateNames::BIG_DRIPLEAF_HEAD)){ - return Blocks::BIG_DRIPLEAF_HEAD() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLeafState(match($type = $in->readString(StateNames::BIG_DRIPLEAF_TILT)){ - StringValues::BIG_DRIPLEAF_TILT_NONE => DripleafState::STABLE, - StringValues::BIG_DRIPLEAF_TILT_UNSTABLE => DripleafState::UNSTABLE, - StringValues::BIG_DRIPLEAF_TILT_PARTIAL_TILT => DripleafState::PARTIAL_TILT, - StringValues::BIG_DRIPLEAF_TILT_FULL_TILT => DripleafState::FULL_TILT, - default => throw $in->badValueException(StateNames::BIG_DRIPLEAF_TILT, $type), - }); - }else{ - $in->ignored(StateNames::BIG_DRIPLEAF_TILT); - return Blocks::BIG_DRIPLEAF_STEM()->setFacing($in->readCardinalHorizontalFacing()); - } - }); - $this->mapSlab(Ids::BLACKSTONE_SLAB, Ids::BLACKSTONE_DOUBLE_SLAB, fn() => Blocks::BLACKSTONE_SLAB()); - $this->mapStairs(Ids::BLACKSTONE_STAIRS, fn() => Blocks::BLACKSTONE_STAIRS()); - $this->map(Ids::BLACKSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::BLACKSTONE_WALL(), $in)); - $this->map(Ids::BLAST_FURNACE, function(Reader $in) : Block{ - return Blocks::BLAST_FURNACE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(false); - }); - $this->map(Ids::BONE_BLOCK, function(Reader $in) : Block{ - $in->ignored(StateNames::DEPRECATED); - return Blocks::BONE_BLOCK()->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::BREWING_STAND, function(Reader $in) : Block{ - return Blocks::BREWING_STAND() - ->setSlot(BrewingStandSlot::EAST, $in->readBool(StateNames::BREWING_STAND_SLOT_A_BIT)) - ->setSlot(BrewingStandSlot::SOUTHWEST, $in->readBool(StateNames::BREWING_STAND_SLOT_B_BIT)) - ->setSlot(BrewingStandSlot::NORTHWEST, $in->readBool(StateNames::BREWING_STAND_SLOT_C_BIT)); - }); - $this->mapSlab(Ids::BRICK_SLAB, Ids::BRICK_DOUBLE_SLAB, fn() => Blocks::BRICK_SLAB()); - $this->mapStairs(Ids::BRICK_STAIRS, fn() => Blocks::BRICK_STAIRS()); - $this->map(Ids::BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::BRICK_WALL(), $in)); - $this->map(Ids::MUSHROOM_STEM, fn(Reader $in) => match($in->readBoundedInt(StateNames::HUGE_MUSHROOM_BITS, 0, 15)){ - BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM => Blocks::ALL_SIDED_MUSHROOM_STEM(), - BlockLegacyMetadata::MUSHROOM_BLOCK_STEM => Blocks::MUSHROOM_STEM(), - default => throw new BlockStateDeserializeException("This state does not exist"), - }); - $this->map(Ids::BROWN_MUSHROOM_BLOCK, fn(Reader $in) => Helper::decodeMushroomBlock(Blocks::BROWN_MUSHROOM_BLOCK(), $in)); - $this->map(Ids::CACTUS, function(Reader $in) : Block{ - return Blocks::CACTUS() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15)); - }); - $this->map(Ids::CAKE, function(Reader $in) : Block{ - return Blocks::CAKE() - ->setBites($in->readBoundedInt(StateNames::BITE_COUNTER, 0, 6)); - }); - $this->map(Ids::CAMPFIRE, function(Reader $in) : Block{ - return Blocks::CAMPFIRE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(!$in->readBool(StateNames::EXTINGUISHED)); - }); - $this->map(Ids::CARROTS, fn(Reader $in) => Helper::decodeCrops(Blocks::CARROTS(), $in)); - $this->map(Ids::CARVED_PUMPKIN, function(Reader $in) : Block{ - return Blocks::CARVED_PUMPKIN() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::CAVE_VINES, function(Reader $in) : CaveVines{ - return Blocks::CAVE_VINES() - ->setBerries(false) - ->setHead(false) - ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25)); - }); - $this->map(Ids::CAVE_VINES_BODY_WITH_BERRIES, function(Reader $in) : CaveVines{ - return Blocks::CAVE_VINES() - ->setBerries(true) - ->setHead(false) - ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25)); - }); - $this->map(Ids::CAVE_VINES_HEAD_WITH_BERRIES, function(Reader $in) : CaveVines{ - return Blocks::CAVE_VINES() - ->setBerries(true) - ->setHead(true) - ->setAge($in->readBoundedInt(StateNames::GROWING_PLANT_AGE, 0, 25)); - }); - $this->map(Ids::CHAIN, function(Reader $in) : Block{ - return Blocks::CHAIN() - ->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::CHISELED_BOOKSHELF, function(Reader $in) : Block{ - $block = Blocks::CHISELED_BOOKSHELF() - ->setFacing($in->readLegacyHorizontalFacing()); - - //we don't use API constant for bounds here as the data bounds might be different to what we support internally - $flags = $in->readBoundedInt(StateNames::BOOKS_STORED, 0, (1 << 6) - 1); - foreach(ChiseledBookshelfSlot::cases() as $slot){ - $block->setSlot($slot, ($flags & (1 << $slot->value)) !== 0); - } - - return $block; - }); - $this->map(Ids::CHISELED_QUARTZ_BLOCK, function(Reader $in) : Block{ - return Blocks::CHISELED_QUARTZ() - ->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::CHEST, function(Reader $in) : Block{ - return Blocks::CHEST() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::CHORUS_FLOWER, function(Reader $in) : Block{ - return Blocks::CHORUS_FLOWER() - ->setAge($in->readBoundedInt(StateNames::AGE, ChorusFlower::MIN_AGE, ChorusFlower::MAX_AGE)); - }); - $this->map(Ids::COARSE_DIRT, fn() => Blocks::DIRT()->setDirtType(DirtType::COARSE)); - $this->mapSlab(Ids::COBBLED_DEEPSLATE_SLAB, Ids::COBBLED_DEEPSLATE_DOUBLE_SLAB, fn() => Blocks::COBBLED_DEEPSLATE_SLAB()); - $this->mapStairs(Ids::COBBLED_DEEPSLATE_STAIRS, fn() => Blocks::COBBLED_DEEPSLATE_STAIRS()); - $this->map(Ids::COBBLED_DEEPSLATE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::COBBLED_DEEPSLATE_WALL(), $in)); - $this->mapSlab(Ids::COBBLESTONE_SLAB, Ids::COBBLESTONE_DOUBLE_SLAB, fn() => Blocks::COBBLESTONE_SLAB()); - $this->map(Ids::COBBLESTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::COBBLESTONE_WALL(), $in)); - $this->map(Ids::COCOA, function(Reader $in) : Block{ - return Blocks::COCOA_POD() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 2)) - ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing())); - }); - $this->map(Ids::COLORED_TORCH_BLUE, fn(Reader $in) => Blocks::BLUE_TORCH()->setFacing($in->readTorchFacing())); - $this->map(Ids::COLORED_TORCH_GREEN, fn(Reader $in) => Blocks::GREEN_TORCH()->setFacing($in->readTorchFacing())); - $this->map(Ids::COLORED_TORCH_PURPLE, fn(Reader $in) => Blocks::PURPLE_TORCH()->setFacing($in->readTorchFacing())); - $this->map(Ids::COLORED_TORCH_RED, fn(Reader $in) => Blocks::RED_TORCH()->setFacing($in->readTorchFacing())); - $this->map(Ids::COMPOUND_CREATOR, fn(Reader $in) => Blocks::COMPOUND_CREATOR() - ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing())) - ); - $this->mapSlab(Ids::CUT_RED_SANDSTONE_SLAB, Ids::CUT_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_RED_SANDSTONE_SLAB()); - $this->mapSlab(Ids::CUT_SANDSTONE_SLAB, Ids::CUT_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::CUT_SANDSTONE_SLAB()); - $this->mapSlab(Ids::DARK_PRISMARINE_SLAB, Ids::DARK_PRISMARINE_DOUBLE_SLAB, fn() => Blocks::DARK_PRISMARINE_SLAB()); - $this->mapStairs(Ids::DARK_PRISMARINE_STAIRS, fn() => Blocks::DARK_PRISMARINE_STAIRS()); - $this->map(Ids::DAYLIGHT_DETECTOR, fn(Reader $in) => Helper::decodeDaylightSensor(Blocks::DAYLIGHT_SENSOR(), $in) - ->setInverted(false)); - $this->map(Ids::DAYLIGHT_DETECTOR_INVERTED, fn(Reader $in) => Helper::decodeDaylightSensor(Blocks::DAYLIGHT_SENSOR(), $in) - ->setInverted(true)); - $this->map(Ids::DEEPSLATE, function(Reader $in) : Block{ - return Blocks::DEEPSLATE() - ->setAxis($in->readPillarAxis()); - }); - $this->mapSlab(Ids::DEEPSLATE_BRICK_SLAB, Ids::DEEPSLATE_BRICK_DOUBLE_SLAB, fn() => Blocks::DEEPSLATE_BRICK_SLAB()); - $this->mapStairs(Ids::DEEPSLATE_BRICK_STAIRS, fn() => Blocks::DEEPSLATE_BRICK_STAIRS()); - $this->map(Ids::DEEPSLATE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DEEPSLATE_BRICK_WALL(), $in)); - $this->map(Ids::DEEPSLATE_REDSTONE_ORE, fn() => Blocks::DEEPSLATE_REDSTONE_ORE()->setLit(false)); - $this->mapSlab(Ids::DEEPSLATE_TILE_SLAB, Ids::DEEPSLATE_TILE_DOUBLE_SLAB, fn() => Blocks::DEEPSLATE_TILE_SLAB()); - $this->mapStairs(Ids::DEEPSLATE_TILE_STAIRS, fn() => Blocks::DEEPSLATE_TILE_STAIRS()); - $this->map(Ids::DEEPSLATE_TILE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DEEPSLATE_TILE_WALL(), $in)); - $this->map(Ids::DETECTOR_RAIL, function(Reader $in) : Block{ - return Blocks::DETECTOR_RAIL() - ->setActivated($in->readBool(StateNames::RAIL_DATA_BIT)) - ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5)); - }); - $this->mapSlab(Ids::DIORITE_SLAB, Ids::DIORITE_DOUBLE_SLAB, fn() => Blocks::DIORITE_SLAB()); - $this->mapStairs(Ids::DIORITE_STAIRS, fn() => Blocks::DIORITE_STAIRS()); - $this->map(Ids::DIORITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::DIORITE_WALL(), $in)); - $this->map(Ids::DIRT, fn() => Blocks::DIRT()->setDirtType(DirtType::NORMAL)); - $this->map(Ids::DIRT_WITH_ROOTS, fn() => Blocks::DIRT()->setDirtType(DirtType::ROOTED)); - $this->map(Ids::LARGE_FERN, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LARGE_FERN(), $in)); - $this->map(Ids::TALL_GRASS, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::DOUBLE_TALLGRASS(), $in)); - $this->map(Ids::PEONY, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::PEONY(), $in)); - $this->map(Ids::ROSE_BUSH, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::ROSE_BUSH(), $in)); - $this->map(Ids::SUNFLOWER, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::SUNFLOWER(), $in)); - $this->map(Ids::LILAC, fn(Reader $in) => Helper::decodeDoublePlant(Blocks::LILAC(), $in)); - $this->map(Ids::ELEMENT_CONSTRUCTOR, fn(Reader $in) => Blocks::ELEMENT_CONSTRUCTOR() - ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing())) - ); - $this->mapStairs(Ids::END_BRICK_STAIRS, fn() => Blocks::END_STONE_BRICK_STAIRS()); - $this->map(Ids::END_STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::END_STONE_BRICK_WALL(), $in)); - $this->map(Ids::END_PORTAL_FRAME, function(Reader $in) : Block{ - return Blocks::END_PORTAL_FRAME() - ->setEye($in->readBool(StateNames::END_PORTAL_EYE_BIT)) - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::END_ROD, function(Reader $in) : Block{ - return Blocks::END_ROD() - ->setFacing($in->readEndRodFacingDirection()); - }); - $this->mapSlab(Ids::END_STONE_BRICK_SLAB, Ids::END_STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::END_STONE_BRICK_SLAB()); - $this->map(Ids::ENDER_CHEST, function(Reader $in) : Block{ - return Blocks::ENDER_CHEST() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::FARMLAND, function(Reader $in) : Block{ - return Blocks::FARMLAND() - ->setWetness($in->readBoundedInt(StateNames::MOISTURIZED_AMOUNT, 0, 7)); - }); - $this->map(Ids::FIRE, function(Reader $in) : Block{ - return Blocks::FIRE() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15)); - }); - $this->map(Ids::FLOWER_POT, function(Reader $in) : Block{ - $in->ignored(StateNames::UPDATE_BIT); - return Blocks::FLOWER_POT(); - }); - $this->map(Ids::FLOWING_LAVA, fn(Reader $in) => Helper::decodeFlowingLiquid(Blocks::LAVA(), $in)); - $this->map(Ids::FLOWING_WATER, fn(Reader $in) => Helper::decodeFlowingLiquid(Blocks::WATER(), $in)); - $this->map(Ids::FRAME, fn(Reader $in) => Helper::decodeItemFrame(Blocks::ITEM_FRAME(), $in)); - $this->map(Ids::FROSTED_ICE, function(Reader $in) : Block{ - return Blocks::FROSTED_ICE() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 3)); - }); - $this->map(Ids::FURNACE, function(Reader $in) : Block{ - return Blocks::FURNACE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(false); - }); - $this->map(Ids::GLOW_LICHEN, fn(Reader $in) => Blocks::GLOW_LICHEN()->setFaces($in->readFacingFlags())); - $this->map(Ids::GLOW_FRAME, fn(Reader $in) => Helper::decodeItemFrame(Blocks::GLOWING_ITEM_FRAME(), $in)); - $this->map(Ids::GOLDEN_RAIL, function(Reader $in) : Block{ - return Blocks::POWERED_RAIL() - ->setPowered($in->readBool(StateNames::RAIL_DATA_BIT)) - ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 5)); - }); - $this->mapSlab(Ids::GRANITE_SLAB, Ids::GRANITE_DOUBLE_SLAB, fn() => Blocks::GRANITE_SLAB()); - $this->mapStairs(Ids::GRANITE_STAIRS, fn() => Blocks::GRANITE_STAIRS()); - $this->map(Ids::GRANITE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::GRANITE_WALL(), $in)); - $this->map(Ids::HAY_BLOCK, function(Reader $in) : Block{ - $in->ignored(StateNames::DEPRECATED); - return Blocks::HAY_BALE()->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::HEAVY_WEIGHTED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeWeightedPressurePlate(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), $in)); - $this->map(Ids::HOPPER, function(Reader $in) : Block{ - return Blocks::HOPPER() - ->setFacing($in->readFacingWithoutUp()) - ->setPowered($in->readBool(StateNames::TOGGLE_BIT)); - }); - $this->map(Ids::IRON_DOOR, fn(Reader $in) => Helper::decodeDoor(Blocks::IRON_DOOR(), $in)); - $this->map(Ids::IRON_TRAPDOOR, fn(Reader $in) => Helper::decodeTrapdoor(Blocks::IRON_TRAPDOOR(), $in)); - $this->map(Ids::LAB_TABLE, fn(Reader $in) => Blocks::LAB_TABLE() - ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing())) - ); - $this->map(Ids::LADDER, function(Reader $in) : Block{ - return Blocks::LADDER() - ->setFacing($in->readHorizontalFacing()); - }); - $this->map(Ids::LANTERN, function(Reader $in) : Block{ - return Blocks::LANTERN() - ->setHanging($in->readBool(StateNames::HANGING)); - }); - $this->map(Ids::LARGE_AMETHYST_BUD, function(Reader $in) : Block{ - return Blocks::AMETHYST_CLUSTER() - ->setStage(AmethystCluster::STAGE_LARGE_BUD) - ->setFacing($in->readBlockFace()); - }); - $this->map(Ids::LAVA, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::LAVA(), $in)); - $this->map(Ids::LECTERN, function(Reader $in) : Block{ - return Blocks::LECTERN() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setProducingSignal($in->readBool(StateNames::POWERED_BIT)); - }); - $this->map(Ids::LEVER, function(Reader $in) : Block{ - return Blocks::LEVER() - ->setActivated($in->readBool(StateNames::OPEN_BIT)) - ->setFacing(match($value = $in->readString(StateNames::LEVER_DIRECTION)){ - StringValues::LEVER_DIRECTION_DOWN_NORTH_SOUTH => LeverFacing::DOWN_AXIS_Z, - StringValues::LEVER_DIRECTION_DOWN_EAST_WEST => LeverFacing::DOWN_AXIS_X, - StringValues::LEVER_DIRECTION_UP_NORTH_SOUTH => LeverFacing::UP_AXIS_Z, - StringValues::LEVER_DIRECTION_UP_EAST_WEST => LeverFacing::UP_AXIS_X, - StringValues::LEVER_DIRECTION_NORTH => LeverFacing::NORTH, - StringValues::LEVER_DIRECTION_SOUTH => LeverFacing::SOUTH, - StringValues::LEVER_DIRECTION_WEST => LeverFacing::WEST, - StringValues::LEVER_DIRECTION_EAST => LeverFacing::EAST, - default => throw $in->badValueException(StateNames::LEVER_DIRECTION, $value), - }); - }); - $this->map(Ids::LIGHTNING_ROD, function(Reader $in) : Block{ - return Blocks::LIGHTNING_ROD() - ->setFacing($in->readFacingDirection()); - }); - $this->map(Ids::LIGHT_WEIGHTED_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeWeightedPressurePlate(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), $in)); - $this->map(Ids::LIT_BLAST_FURNACE, function(Reader $in) : Block{ - return Blocks::BLAST_FURNACE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(true); - }); - $this->map(Ids::LIT_DEEPSLATE_REDSTONE_ORE, fn() => Blocks::DEEPSLATE_REDSTONE_ORE()->setLit(true)); - $this->map(Ids::LIT_FURNACE, function(Reader $in) : Block{ - return Blocks::FURNACE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(true); - }); - $this->map(Ids::LIT_PUMPKIN, function(Reader $in) : Block{ - return Blocks::LIT_PUMPKIN() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::LIT_REDSTONE_LAMP, function() : Block{ - return Blocks::REDSTONE_LAMP() - ->setPowered(true); - }); - $this->map(Ids::LIT_REDSTONE_ORE, function() : Block{ - return Blocks::REDSTONE_ORE() - ->setLit(true); - }); - $this->map(Ids::LIT_SMOKER, function(Reader $in) : Block{ - return Blocks::SMOKER() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(true); - }); - $this->map(Ids::LOOM, function(Reader $in) : Block{ - return Blocks::LOOM() - ->setFacing($in->readLegacyHorizontalFacing()); - }); - $this->map(Ids::MATERIAL_REDUCER, fn(Reader $in) => Blocks::MATERIAL_REDUCER() - ->setFacing(Facing::opposite($in->readLegacyHorizontalFacing())) - ); - $this->map(Ids::MEDIUM_AMETHYST_BUD, function(Reader $in) : Block{ - return Blocks::AMETHYST_CLUSTER() - ->setStage(AmethystCluster::STAGE_MEDIUM_BUD) - ->setFacing($in->readBlockFace()); - }); - $this->map(Ids::MELON_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::MELON_STEM(), $in)); - $this->mapSlab(Ids::MOSSY_COBBLESTONE_SLAB, Ids::MOSSY_COBBLESTONE_DOUBLE_SLAB, fn() => Blocks::MOSSY_COBBLESTONE_SLAB()); - $this->mapStairs(Ids::MOSSY_COBBLESTONE_STAIRS, fn() => Blocks::MOSSY_COBBLESTONE_STAIRS()); - $this->map(Ids::MOSSY_COBBLESTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MOSSY_COBBLESTONE_WALL(), $in)); - $this->mapSlab(Ids::MOSSY_STONE_BRICK_SLAB, Ids::MOSSY_STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::MOSSY_STONE_BRICK_SLAB()); - $this->mapStairs(Ids::MOSSY_STONE_BRICK_STAIRS, fn() => Blocks::MOSSY_STONE_BRICK_STAIRS()); - $this->map(Ids::MOSSY_STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MOSSY_STONE_BRICK_WALL(), $in)); - $this->mapSlab(Ids::MUD_BRICK_SLAB, Ids::MUD_BRICK_DOUBLE_SLAB, fn() => Blocks::MUD_BRICK_SLAB()); - $this->mapStairs(Ids::MUD_BRICK_STAIRS, fn() => Blocks::MUD_BRICK_STAIRS()); - $this->map(Ids::MUD_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::MUD_BRICK_WALL(), $in)); - $this->map(Ids::MUDDY_MANGROVE_ROOTS, function(Reader $in) : Block{ - return Blocks::MUDDY_MANGROVE_ROOTS() - ->setAxis($in->readPillarAxis()); - }); - $this->mapSlab(Ids::NETHER_BRICK_SLAB, Ids::NETHER_BRICK_DOUBLE_SLAB, fn() => Blocks::NETHER_BRICK_SLAB()); - $this->mapStairs(Ids::NETHER_BRICK_STAIRS, fn() => Blocks::NETHER_BRICK_STAIRS()); - $this->map(Ids::NETHER_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::NETHER_BRICK_WALL(), $in)); - $this->map(Ids::NETHER_WART, function(Reader $in) : Block{ - return Blocks::NETHER_WART() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 3)); - }); - $this->mapSlab(Ids::NORMAL_STONE_SLAB, Ids::NORMAL_STONE_DOUBLE_SLAB, fn() => Blocks::STONE_SLAB()); - $this->mapStairs(Ids::NORMAL_STONE_STAIRS, fn() => Blocks::STONE_STAIRS()); - $this->map(Ids::OCHRE_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::OCHRE)->setAxis($in->readPillarAxis())); - $this->map(Ids::PEARLESCENT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::PEARLESCENT)->setAxis($in->readPillarAxis())); - $this->mapSlab(Ids::PETRIFIED_OAK_SLAB, Ids::PETRIFIED_OAK_DOUBLE_SLAB, fn() => Blocks::FAKE_WOODEN_SLAB()); - $this->map(Ids::PINK_PETALS, function(Reader $in) : Block{ - //Pink petals only uses 0-3, but GROWTH state can go up to 7 - $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7); - return Blocks::PINK_PETALS() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setCount(min($growth + 1, PinkPetals::MAX_COUNT)); - }); - $this->map(Ids::PITCHER_CROP, function(Reader $in) : Block{ - $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7); - $top = $in->readBool(StateNames::UPPER_BLOCK_BIT); - if($growth <= PitcherCrop::MAX_AGE){ - //top pitcher crop with age 0-2 is an invalid state - //only the bottom half should exist in this case - return $top ? Blocks::AIR() : Blocks::PITCHER_CROP()->setAge($growth); - } - return Blocks::DOUBLE_PITCHER_CROP() - ->setAge(min($growth - PitcherCrop::MAX_AGE - 1, DoublePitcherCrop::MAX_AGE)) - ->setTop($top); - }); - $this->map(Ids::PITCHER_PLANT, function(Reader $in) : Block{ - return Blocks::PITCHER_PLANT() - ->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT)); - }); - $this->mapSlab(Ids::POLISHED_ANDESITE_SLAB, Ids::POLISHED_ANDESITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_ANDESITE_SLAB()); - $this->mapStairs(Ids::POLISHED_ANDESITE_STAIRS, fn() => Blocks::POLISHED_ANDESITE_STAIRS()); - $this->map(Ids::POLISHED_BASALT, function(Reader $in) : Block{ - return Blocks::POLISHED_BASALT() - ->setAxis($in->readPillarAxis()); - }); - $this->map(Ids::POLISHED_BLACKSTONE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::POLISHED_BLACKSTONE_BUTTON(), $in)); - $this->mapSlab(Ids::POLISHED_BLACKSTONE_SLAB, Ids::POLISHED_BLACKSTONE_DOUBLE_SLAB, fn() => Blocks::POLISHED_BLACKSTONE_SLAB()); - $this->map(Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), $in)); - $this->mapStairs(Ids::POLISHED_BLACKSTONE_STAIRS, fn() => Blocks::POLISHED_BLACKSTONE_STAIRS()); - $this->map(Ids::POLISHED_BLACKSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_BLACKSTONE_WALL(), $in)); - $this->mapSlab(Ids::POLISHED_BLACKSTONE_BRICK_SLAB, Ids::POLISHED_BLACKSTONE_BRICK_DOUBLE_SLAB, fn() => Blocks::POLISHED_BLACKSTONE_BRICK_SLAB()); - $this->mapStairs(Ids::POLISHED_BLACKSTONE_BRICK_STAIRS, fn() => Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS()); - $this->map(Ids::POLISHED_BLACKSTONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_BLACKSTONE_BRICK_WALL(), $in)); - $this->mapSlab(Ids::POLISHED_DEEPSLATE_SLAB, Ids::POLISHED_DEEPSLATE_DOUBLE_SLAB, fn() => Blocks::POLISHED_DEEPSLATE_SLAB()); - $this->mapStairs(Ids::POLISHED_DEEPSLATE_STAIRS, fn() => Blocks::POLISHED_DEEPSLATE_STAIRS()); - $this->map(Ids::POLISHED_DEEPSLATE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_DEEPSLATE_WALL(), $in)); - $this->mapSlab(Ids::POLISHED_DIORITE_SLAB, Ids::POLISHED_DIORITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_DIORITE_SLAB()); - $this->mapStairs(Ids::POLISHED_DIORITE_STAIRS, fn() => Blocks::POLISHED_DIORITE_STAIRS()); - $this->mapSlab(Ids::POLISHED_GRANITE_SLAB, Ids::POLISHED_GRANITE_DOUBLE_SLAB, fn() => Blocks::POLISHED_GRANITE_SLAB()); - $this->mapStairs(Ids::POLISHED_GRANITE_STAIRS, fn() => Blocks::POLISHED_GRANITE_STAIRS()); - $this->mapSlab(Ids::POLISHED_TUFF_SLAB, Ids::POLISHED_TUFF_DOUBLE_SLAB, fn() => Blocks::POLISHED_TUFF_SLAB()); - $this->mapStairs(Ids::POLISHED_TUFF_STAIRS, fn() => Blocks::POLISHED_TUFF_STAIRS()); - $this->map(Ids::POLISHED_TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::POLISHED_TUFF_WALL(), $in)); - $this->map(Ids::PORTAL, function(Reader $in) : Block{ - return Blocks::NETHER_PORTAL() - ->setAxis(match($value = $in->readString(StateNames::PORTAL_AXIS)){ - StringValues::PORTAL_AXIS_UNKNOWN => Axis::X, - StringValues::PORTAL_AXIS_X => Axis::X, - StringValues::PORTAL_AXIS_Z => Axis::Z, - default => throw $in->badValueException(StateNames::PORTAL_AXIS, $value), - }); - }); - $this->map(Ids::POTATOES, fn(Reader $in) => Helper::decodeCrops(Blocks::POTATOES(), $in)); - $this->map(Ids::POWERED_COMPARATOR, fn(Reader $in) => Helper::decodeComparator(Blocks::REDSTONE_COMPARATOR(), $in)); - $this->map(Ids::POWERED_REPEATER, fn(Reader $in) => Helper::decodeRepeater(Blocks::REDSTONE_REPEATER(), $in) - ->setPowered(true)); - $this->mapSlab(Ids::PRISMARINE_BRICK_SLAB, Ids::PRISMARINE_BRICK_DOUBLE_SLAB, fn() => Blocks::PRISMARINE_BRICKS_SLAB()); - $this->mapStairs(Ids::PRISMARINE_BRICKS_STAIRS, fn() => Blocks::PRISMARINE_BRICKS_STAIRS()); - $this->map(Ids::PRISMARINE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::PRISMARINE_WALL(), $in)); - $this->mapSlab(Ids::PRISMARINE_SLAB, Ids::PRISMARINE_DOUBLE_SLAB, fn() => Blocks::PRISMARINE_SLAB()); - $this->mapStairs(Ids::PRISMARINE_STAIRS, fn() => Blocks::PRISMARINE_STAIRS()); - $this->map(Ids::PUMPKIN, function(Reader $in) : Block{ - $in->ignored(StateNames::MC_CARDINAL_DIRECTION); //obsolete - return Blocks::PUMPKIN(); - }); - $this->map(Ids::PUMPKIN_STEM, fn(Reader $in) => Helper::decodeStem(Blocks::PUMPKIN_STEM(), $in)); - $this->map(Ids::PURPUR_BLOCK, function(Reader $in) : Block{ - $in->ignored(StateNames::PILLAR_AXIS); //??? - return Blocks::PURPUR(); - }); - $this->map(Ids::PURPUR_PILLAR, fn(Reader $in) => Blocks::PURPUR_PILLAR()->setAxis($in->readPillarAxis())); - $this->mapSlab(Ids::PURPUR_SLAB, Ids::PURPUR_DOUBLE_SLAB, fn() => Blocks::PURPUR_SLAB()); - $this->mapStairs(Ids::PURPUR_STAIRS, fn() => Blocks::PURPUR_STAIRS()); - $this->map(Ids::QUARTZ_BLOCK, function(Reader $in) : Opaque{ - $in->ignored(StateNames::PILLAR_AXIS); - return Blocks::QUARTZ(); - }); - $this->map(Ids::QUARTZ_PILLAR, function(Reader $in) : Block{ - return Blocks::QUARTZ_PILLAR() - ->setAxis($in->readPillarAxis()); - }); - $this->mapSlab(Ids::QUARTZ_SLAB, Ids::QUARTZ_DOUBLE_SLAB, fn() => Blocks::QUARTZ_SLAB()); - $this->mapStairs(Ids::QUARTZ_STAIRS, fn() => Blocks::QUARTZ_STAIRS()); - $this->map(Ids::RAIL, function(Reader $in) : Block{ - return Blocks::RAIL() - ->setShape($in->readBoundedInt(StateNames::RAIL_DIRECTION, 0, 9)); - }); - $this->map(Ids::RED_MUSHROOM_BLOCK, fn(Reader $in) => Helper::decodeMushroomBlock(Blocks::RED_MUSHROOM_BLOCK(), $in)); - $this->mapSlab(Ids::RED_NETHER_BRICK_SLAB, Ids::RED_NETHER_BRICK_DOUBLE_SLAB, fn() => Blocks::RED_NETHER_BRICK_SLAB()); - $this->mapStairs(Ids::RED_NETHER_BRICK_STAIRS, fn() => Blocks::RED_NETHER_BRICK_STAIRS()); - $this->map(Ids::RED_NETHER_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RED_NETHER_BRICK_WALL(), $in)); - $this->mapSlab(Ids::RED_SANDSTONE_SLAB, Ids::RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::RED_SANDSTONE_SLAB()); - $this->mapStairs(Ids::RED_SANDSTONE_STAIRS, fn() => Blocks::RED_SANDSTONE_STAIRS()); - $this->map(Ids::RED_SANDSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RED_SANDSTONE_WALL(), $in)); - $this->map(Ids::REDSTONE_LAMP, function() : Block{ - return Blocks::REDSTONE_LAMP() - ->setPowered(false); - }); - $this->map(Ids::REDSTONE_ORE, function() : Block{ - return Blocks::REDSTONE_ORE() - ->setLit(false); - }); - $this->map(Ids::REDSTONE_TORCH, function(Reader $in) : Block{ - return Blocks::REDSTONE_TORCH() - ->setFacing($in->readTorchFacing()) - ->setLit(true); - }); - $this->map(Ids::REDSTONE_WIRE, function(Reader $in) : Block{ - return Blocks::REDSTONE_WIRE() - ->setOutputSignalStrength($in->readBoundedInt(StateNames::REDSTONE_SIGNAL, 0, 15)); - }); - $this->map(Ids::REEDS, function(Reader $in) : Block{ - return Blocks::SUGARCANE() - ->setAge($in->readBoundedInt(StateNames::AGE, 0, 15)); - }); - $this->mapSlab(Ids::RESIN_BRICK_SLAB, Ids::RESIN_BRICK_DOUBLE_SLAB, fn() => Blocks::RESIN_BRICK_SLAB()); - $this->mapStairs(Ids::RESIN_BRICK_STAIRS, fn() => Blocks::RESIN_BRICK_STAIRS()); - $this->map(Ids::RESIN_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::RESIN_BRICK_WALL(), $in)); - $this->map(Ids::RESIN_CLUMP, fn(Reader $in) => Blocks::RESIN_CLUMP()->setFaces($in->readFacingFlags())); - $this->map(Ids::RESPAWN_ANCHOR, function(Reader $in) : Block{ - return Blocks::RESPAWN_ANCHOR() - ->setCharges($in->readBoundedInt(StateNames::RESPAWN_ANCHOR_CHARGE, 0, 4)); - }); - $this->mapSlab(Ids::SANDSTONE_SLAB, Ids::SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SANDSTONE_SLAB()); - $this->mapStairs(Ids::SANDSTONE_STAIRS, fn() => Blocks::SANDSTONE_STAIRS()); - $this->map(Ids::SANDSTONE_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::SANDSTONE_WALL(), $in)); - $this->map(Ids::SEA_PICKLE, function(Reader $in) : Block{ - return Blocks::SEA_PICKLE() - ->setCount($in->readBoundedInt(StateNames::CLUSTER_COUNT, 0, 3) + 1) - ->setUnderwater(!$in->readBool(StateNames::DEAD_BIT)); - }); - $this->map(Ids::SMOKER, function(Reader $in) : Block{ - return Blocks::SMOKER() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(false); - }); - $this->map(Ids::SMALL_AMETHYST_BUD, function(Reader $in) : Block{ - return Blocks::AMETHYST_CLUSTER() - ->setStage(AmethystCluster::STAGE_SMALL_BUD) - ->setFacing($in->readBlockFace()); - }); - $this->map(Ids::SMALL_DRIPLEAF_BLOCK, function(Reader $in) : Block{ - return Blocks::SMALL_DRIPLEAF() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setTop($in->readBool(StateNames::UPPER_BLOCK_BIT)); - }); - $this->map(Ids::SMOOTH_QUARTZ, function(Reader $in) : Block{ - $in->ignored(StateNames::PILLAR_AXIS); - return Blocks::SMOOTH_QUARTZ(); - }); - $this->mapSlab(Ids::SMOOTH_QUARTZ_SLAB, Ids::SMOOTH_QUARTZ_DOUBLE_SLAB, fn() => Blocks::SMOOTH_QUARTZ_SLAB()); - $this->mapStairs(Ids::SMOOTH_QUARTZ_STAIRS, fn() => Blocks::SMOOTH_QUARTZ_STAIRS()); - $this->mapSlab(Ids::SMOOTH_RED_SANDSTONE_SLAB, Ids::SMOOTH_RED_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_RED_SANDSTONE_SLAB()); - $this->mapStairs(Ids::SMOOTH_RED_SANDSTONE_STAIRS, fn() => Blocks::SMOOTH_RED_SANDSTONE_STAIRS()); - $this->mapSlab(Ids::SMOOTH_SANDSTONE_SLAB, Ids::SMOOTH_SANDSTONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_SANDSTONE_SLAB()); - $this->mapStairs(Ids::SMOOTH_SANDSTONE_STAIRS, fn() => Blocks::SMOOTH_SANDSTONE_STAIRS()); - $this->mapSlab(Ids::SMOOTH_STONE_SLAB, Ids::SMOOTH_STONE_DOUBLE_SLAB, fn() => Blocks::SMOOTH_STONE_SLAB()); - $this->map(Ids::SNOW_LAYER, function(Reader $in) : Block{ - $in->ignored(StateNames::COVERED_BIT); //seems to be useless - return Blocks::SNOW_LAYER()->setLayers($in->readBoundedInt(StateNames::HEIGHT, 0, 7) + 1); - }); - $this->map(Ids::SOUL_CAMPFIRE, function(Reader $in) : Block{ - return Blocks::SOUL_CAMPFIRE() - ->setFacing($in->readCardinalHorizontalFacing()) - ->setLit(!$in->readBool(StateNames::EXTINGUISHED)); - }); - $this->map(Ids::SOUL_FIRE, function(Reader $in) : Block{ - $in->ignored(StateNames::AGE); //this is useless for soul fire, since it doesn't have the logic associated - return Blocks::SOUL_FIRE(); - }); - $this->map(Ids::SOUL_LANTERN, function(Reader $in) : Block{ - return Blocks::SOUL_LANTERN() - ->setHanging($in->readBool(StateNames::HANGING)); - }); - $this->map(Ids::SOUL_TORCH, function(Reader $in) : Block{ - return Blocks::SOUL_TORCH() - ->setFacing($in->readTorchFacing()); - }); - $this->map(Ids::STANDING_BANNER, function(Reader $in) : Block{ - return Blocks::BANNER() - ->setRotation($in->readBoundedInt(StateNames::GROUND_SIGN_DIRECTION, 0, 15)); - }); - $this->mapSlab(Ids::STONE_BRICK_SLAB, Ids::STONE_BRICK_DOUBLE_SLAB, fn() => Blocks::STONE_BRICK_SLAB()); - $this->mapStairs(Ids::STONE_BRICK_STAIRS, fn() => Blocks::STONE_BRICK_STAIRS()); - $this->map(Ids::STONE_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::STONE_BRICK_WALL(), $in)); - $this->map(Ids::STONE_BUTTON, fn(Reader $in) => Helper::decodeButton(Blocks::STONE_BUTTON(), $in)); - $this->map(Ids::STONE_PRESSURE_PLATE, fn(Reader $in) => Helper::decodeSimplePressurePlate(Blocks::STONE_PRESSURE_PLATE(), $in)); - $this->mapStairs(Ids::STONE_STAIRS, fn() => Blocks::COBBLESTONE_STAIRS()); - $this->map(Ids::STONECUTTER_BLOCK, function(Reader $in) : Block{ - return Blocks::STONECUTTER() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::SWEET_BERRY_BUSH, function(Reader $in) : Block{ - //berry bush only wants 0-3, but it can be bigger in MCPE due to misuse of GROWTH state which goes up to 7 - $growth = $in->readBoundedInt(StateNames::GROWTH, 0, 7); - return Blocks::SWEET_BERRY_BUSH() - ->setAge(min($growth, SweetBerryBush::STAGE_MATURE)); - }); - $this->map(Ids::TNT, function(Reader $in) : Block{ - return Blocks::TNT() - ->setUnstable($in->readBool(StateNames::EXPLODE_BIT)) - ->setWorksUnderwater(false); - }); - $this->map(Ids::TORCH, function(Reader $in) : Block{ - return Blocks::TORCH() - ->setFacing($in->readTorchFacing()); - }); - $this->map(Ids::TORCHFLOWER_CROP, function(Reader $in) : Block{ - return Blocks::TORCHFLOWER_CROP() - //this property can have values 0-7, but only 0-1 are valid - ->setReady($in->readBoundedInt(StateNames::GROWTH, 0, 7) !== 0); - }); - $this->map(Ids::TRAPPED_CHEST, function(Reader $in) : Block{ - return Blocks::TRAPPED_CHEST() - ->setFacing($in->readCardinalHorizontalFacing()); - }); - $this->map(Ids::TRIP_WIRE, function(Reader $in) : Block{ - return Blocks::TRIPWIRE() - ->setConnected($in->readBool(StateNames::ATTACHED_BIT)) - ->setDisarmed($in->readBool(StateNames::DISARMED_BIT)) - ->setSuspended($in->readBool(StateNames::SUSPENDED_BIT)) - ->setTriggered($in->readBool(StateNames::POWERED_BIT)); - }); - $this->map(Ids::TRIPWIRE_HOOK, function(Reader $in) : Block{ - return Blocks::TRIPWIRE_HOOK() - ->setConnected($in->readBool(StateNames::ATTACHED_BIT)) - ->setFacing($in->readLegacyHorizontalFacing()) - ->setPowered($in->readBool(StateNames::POWERED_BIT)); - }); - $this->mapSlab(Ids::TUFF_BRICK_SLAB, Ids::TUFF_BRICK_DOUBLE_SLAB, fn() => Blocks::TUFF_BRICK_SLAB()); - $this->mapStairs(Ids::TUFF_BRICK_STAIRS, fn() => Blocks::TUFF_BRICK_STAIRS()); - $this->map(Ids::TUFF_BRICK_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_BRICK_WALL(), $in)); - $this->mapSlab(Ids::TUFF_SLAB, Ids::TUFF_DOUBLE_SLAB, fn() => Blocks::TUFF_SLAB()); - $this->mapStairs(Ids::TUFF_STAIRS, fn() => Blocks::TUFF_STAIRS()); - $this->map(Ids::TUFF_WALL, fn(Reader $in) => Helper::decodeWall(Blocks::TUFF_WALL(), $in)); - $this->map(Ids::TWISTING_VINES, function(Reader $in) : Block{ - return Blocks::TWISTING_VINES() - ->setAge($in->readBoundedInt(StateNames::TWISTING_VINES_AGE, 0, 25)); - }); - $this->map(Ids::UNDERWATER_TNT, function(Reader $in) : Block{ - return Blocks::TNT() - ->setUnstable($in->readBool(StateNames::EXPLODE_BIT)) - ->setWorksUnderwater(true); - }); - $this->map(Ids::UNDERWATER_TORCH, function(Reader $in) : Block{ - return Blocks::UNDERWATER_TORCH() - ->setFacing($in->readTorchFacing()); - }); - $this->map(Ids::UNLIT_REDSTONE_TORCH, function(Reader $in) : Block{ - return Blocks::REDSTONE_TORCH() - ->setFacing($in->readTorchFacing()) - ->setLit(false); - }); - $this->map(Ids::UNPOWERED_COMPARATOR, fn(Reader $in) => Helper::decodeComparator(Blocks::REDSTONE_COMPARATOR(), $in)); - $this->map(Ids::UNPOWERED_REPEATER, fn(Reader $in) => Helper::decodeRepeater(Blocks::REDSTONE_REPEATER(), $in) - ->setPowered(false)); - $this->map(Ids::VERDANT_FROGLIGHT, fn(Reader $in) => Blocks::FROGLIGHT()->setFroglightType(FroglightType::VERDANT)->setAxis($in->readPillarAxis())); - $this->map(Ids::VINE, function(Reader $in) : Block{ - $vineDirectionFlags = $in->readBoundedInt(StateNames::VINE_DIRECTION_BITS, 0, 15); - return Blocks::VINES() - ->setFace(Facing::NORTH, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_NORTH) !== 0) - ->setFace(Facing::SOUTH, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_SOUTH) !== 0) - ->setFace(Facing::WEST, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_WEST) !== 0) - ->setFace(Facing::EAST, ($vineDirectionFlags & BlockLegacyMetadata::VINE_FLAG_EAST) !== 0); - }); - $this->map(Ids::WALL_BANNER, function(Reader $in) : Block{ - return Blocks::WALL_BANNER() - ->setFacing($in->readHorizontalFacing()); - }); - $this->map(Ids::WATER, fn(Reader $in) => Helper::decodeStillLiquid(Blocks::WATER(), $in)); - - $this->map(Ids::WEEPING_VINES, function(Reader $in) : Block{ - return Blocks::WEEPING_VINES() - ->setAge($in->readBoundedInt(StateNames::WEEPING_VINES_AGE, 0, 25)); - }); - $this->map(Ids::WHEAT, fn(Reader $in) => Helper::decodeCrops(Blocks::WHEAT(), $in)); - } - /** @throws BlockStateDeserializeException */ public function deserializeBlock(BlockStateData $blockStateData) : Block{ $id = $blockStateData->getName(); diff --git a/src/data/bedrock/block/convert/BlockStateWriter.php b/src/data/bedrock/block/convert/BlockStateWriter.php index 63af92d10..0119bd02e 100644 --- a/src/data/bedrock/block/convert/BlockStateWriter.php +++ b/src/data/bedrock/block/convert/BlockStateWriter.php @@ -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 $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 $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 $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 $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); } diff --git a/src/data/bedrock/block/convert/FlattenedIdModel.php b/src/data/bedrock/block/convert/FlattenedIdModel.php new file mode 100644 index 000000000..50bf5cdd9 --- /dev/null +++ b/src/data/bedrock/block/convert/FlattenedIdModel.php @@ -0,0 +1,107 @@ +> + */ + private array $idComponents = []; + + /** + * @var Property[] + * @phpstan-var list> + */ + private array $properties = []; + + /** + * @phpstan-param TBlock $block + */ + private function __construct( + private Block $block + ){} + + /** + * @phpstan-template TBlock_ of Block + * @phpstan-param TBlock_ $block + * @return self + */ + public static function create(Block $block) : self{ + /** @phpstan-var self $result */ + $result = new self($block); + return $result; + } + + /** @phpstan-return TBlock */ + public function getBlock() : Block{ return $this->block; } + + /** + * @return string[]|StringProperty[] + * @phpstan-return list> + */ + public function getIdComponents() : array{ return $this->idComponents; } + + /** + * @return Property[] + * @phpstan-return list> + */ + public function getProperties() : array{ return $this->properties; } + + /** + * @param string[]|StringProperty[] $components + * @phpstan-param non-empty-list> $components + * @return $this + * @phpstan-this-out self + */ + public function idComponents(array $components) : self{ + $this->idComponents = $components; + return $this; + } + + /** + * @param Property[] $properties + * @phpstan-param non-empty-list> $properties + * @return $this + * @phpstan-this-out self + */ + public function properties(array $properties) : self{ + $this->properties = $properties; + return $this; + } +} diff --git a/src/data/bedrock/block/convert/Model.php b/src/data/bedrock/block/convert/Model.php new file mode 100644 index 000000000..3474a8932 --- /dev/null +++ b/src/data/bedrock/block/convert/Model.php @@ -0,0 +1,82 @@ +> + */ + 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> + */ + public function getProperties() : array{ return $this->properties; } + + /** + * @phpstan-template TBlock_ of Block + * @phpstan-param TBlock_ $block + * @phpstan-return self + */ + public static function create(Block $block, string $id) : self{ + return new self($block, $id); + } + + /** + * @param Property[] $properties + * @phpstan-param list> $properties + * @phpstan-return $this + */ + public function properties(array $properties) : self{ + $this->properties = $properties; + return $this; + } +} diff --git a/src/data/bedrock/block/convert/StringEnumMap.php b/src/data/bedrock/block/convert/StringEnumMap.php deleted file mode 100644 index 6171c0e71..000000000 --- a/src/data/bedrock/block/convert/StringEnumMap.php +++ /dev/null @@ -1,78 +0,0 @@ - - */ - private array $enumToValue = []; - - /** - * @var \UnitEnum[] - * @phpstan-var array - */ - private array $valueToEnum = []; - - /** - * @phpstan-param class-string $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 - */ - public function getValueToEnum() : array{ - return $this->valueToEnum; - } -} diff --git a/src/data/bedrock/block/convert/ValueMappings.php b/src/data/bedrock/block/convert/ValueMappings.php deleted file mode 100644 index df57d6f53..000000000 --- a/src/data/bedrock/block/convert/ValueMappings.php +++ /dev/null @@ -1,83 +0,0 @@ -, StringEnumMap> - */ - 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 $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 $class - * @phpstan-return StringEnumMap - */ - public function getEnumMap(string $class) : StringEnumMap{ - if(!isset($this->enumMappings[$class])){ - throw new \InvalidArgumentException("No enum mapping found for class: $class"); - } - /** - * @phpstan-var StringEnumMap $map - */ - $map = $this->enumMappings[$class]; - return $map; - } -} diff --git a/src/data/bedrock/block/convert/VanillaBlockMappings.php b/src/data/bedrock/block/convert/VanillaBlockMappings.php new file mode 100644 index 000000000..fc1c6acb6 --- /dev/null +++ b/src/data/bedrock/block/convert/VanillaBlockMappings.php @@ -0,0 +1,1646 @@ +mapSimple(Blocks::AIR(), Ids::AIR); + $reg->mapSimple(Blocks::AMETHYST(), Ids::AMETHYST_BLOCK); + $reg->mapSimple(Blocks::ANCIENT_DEBRIS(), Ids::ANCIENT_DEBRIS); + $reg->mapSimple(Blocks::ANDESITE(), Ids::ANDESITE); + $reg->mapSimple(Blocks::BARRIER(), Ids::BARRIER); + $reg->mapSimple(Blocks::BEACON(), Ids::BEACON); + $reg->mapSimple(Blocks::BLACKSTONE(), Ids::BLACKSTONE); + $reg->mapSimple(Blocks::BLUE_ICE(), Ids::BLUE_ICE); + $reg->mapSimple(Blocks::BOOKSHELF(), Ids::BOOKSHELF); + $reg->mapSimple(Blocks::BRICKS(), Ids::BRICK_BLOCK); + $reg->mapSimple(Blocks::BROWN_MUSHROOM(), Ids::BROWN_MUSHROOM); + $reg->mapSimple(Blocks::BUDDING_AMETHYST(), Ids::BUDDING_AMETHYST); + $reg->mapSimple(Blocks::CALCITE(), Ids::CALCITE); + $reg->mapSimple(Blocks::CARTOGRAPHY_TABLE(), Ids::CARTOGRAPHY_TABLE); + $reg->mapSimple(Blocks::CHEMICAL_HEAT(), Ids::CHEMICAL_HEAT); + $reg->mapSimple(Blocks::CHISELED_DEEPSLATE(), Ids::CHISELED_DEEPSLATE); + $reg->mapSimple(Blocks::CHISELED_NETHER_BRICKS(), Ids::CHISELED_NETHER_BRICKS); + $reg->mapSimple(Blocks::CHISELED_POLISHED_BLACKSTONE(), Ids::CHISELED_POLISHED_BLACKSTONE); + $reg->mapSimple(Blocks::CHISELED_RED_SANDSTONE(), Ids::CHISELED_RED_SANDSTONE); + $reg->mapSimple(Blocks::CHISELED_RESIN_BRICKS(), Ids::CHISELED_RESIN_BRICKS); + $reg->mapSimple(Blocks::CHISELED_SANDSTONE(), Ids::CHISELED_SANDSTONE); + $reg->mapSimple(Blocks::CHISELED_STONE_BRICKS(), Ids::CHISELED_STONE_BRICKS); + $reg->mapSimple(Blocks::CHISELED_TUFF(), Ids::CHISELED_TUFF); + $reg->mapSimple(Blocks::CHISELED_TUFF_BRICKS(), Ids::CHISELED_TUFF_BRICKS); + $reg->mapSimple(Blocks::CHORUS_PLANT(), Ids::CHORUS_PLANT); + $reg->mapSimple(Blocks::CLAY(), Ids::CLAY); + $reg->mapSimple(Blocks::COAL(), Ids::COAL_BLOCK); + $reg->mapSimple(Blocks::COAL_ORE(), Ids::COAL_ORE); + $reg->mapSimple(Blocks::COBBLED_DEEPSLATE(), Ids::COBBLED_DEEPSLATE); + $reg->mapSimple(Blocks::COBBLESTONE(), Ids::COBBLESTONE); + $reg->mapSimple(Blocks::COBWEB(), Ids::WEB); + $reg->mapSimple(Blocks::COPPER_ORE(), Ids::COPPER_ORE); + $reg->mapSimple(Blocks::CRACKED_DEEPSLATE_BRICKS(), Ids::CRACKED_DEEPSLATE_BRICKS); + $reg->mapSimple(Blocks::CRACKED_DEEPSLATE_TILES(), Ids::CRACKED_DEEPSLATE_TILES); + $reg->mapSimple(Blocks::CRACKED_NETHER_BRICKS(), Ids::CRACKED_NETHER_BRICKS); + $reg->mapSimple(Blocks::CRACKED_POLISHED_BLACKSTONE_BRICKS(), Ids::CRACKED_POLISHED_BLACKSTONE_BRICKS); + $reg->mapSimple(Blocks::CRACKED_STONE_BRICKS(), Ids::CRACKED_STONE_BRICKS); + $reg->mapSimple(Blocks::CRAFTING_TABLE(), Ids::CRAFTING_TABLE); + $reg->mapSimple(Blocks::CRIMSON_ROOTS(), Ids::CRIMSON_ROOTS); + $reg->mapSimple(Blocks::CRYING_OBSIDIAN(), Ids::CRYING_OBSIDIAN); + $reg->mapSimple(Blocks::DANDELION(), Ids::DANDELION); + $reg->mapSimple(Blocks::CUT_RED_SANDSTONE(), Ids::CUT_RED_SANDSTONE); + $reg->mapSimple(Blocks::CUT_SANDSTONE(), Ids::CUT_SANDSTONE); + $reg->mapSimple(Blocks::DARK_PRISMARINE(), Ids::DARK_PRISMARINE); + $reg->mapSimple(Blocks::DEAD_BUSH(), Ids::DEADBUSH); + $reg->mapSimple(Blocks::DEEPSLATE_BRICKS(), Ids::DEEPSLATE_BRICKS); + $reg->mapSimple(Blocks::DEEPSLATE_COAL_ORE(), Ids::DEEPSLATE_COAL_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_COPPER_ORE(), Ids::DEEPSLATE_COPPER_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_DIAMOND_ORE(), Ids::DEEPSLATE_DIAMOND_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_EMERALD_ORE(), Ids::DEEPSLATE_EMERALD_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_GOLD_ORE(), Ids::DEEPSLATE_GOLD_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_IRON_ORE(), Ids::DEEPSLATE_IRON_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_LAPIS_LAZULI_ORE(), Ids::DEEPSLATE_LAPIS_ORE); + $reg->mapSimple(Blocks::DEEPSLATE_TILES(), Ids::DEEPSLATE_TILES); + $reg->mapSimple(Blocks::DIAMOND(), Ids::DIAMOND_BLOCK); + $reg->mapSimple(Blocks::DIAMOND_ORE(), Ids::DIAMOND_ORE); + $reg->mapSimple(Blocks::DIORITE(), Ids::DIORITE); + $reg->mapSimple(Blocks::DRAGON_EGG(), Ids::DRAGON_EGG); + $reg->mapSimple(Blocks::DRIED_KELP(), Ids::DRIED_KELP_BLOCK); + $reg->mapSimple(Blocks::ELEMENT_ACTINIUM(), Ids::ELEMENT_89); + $reg->mapSimple(Blocks::ELEMENT_ALUMINUM(), Ids::ELEMENT_13); + $reg->mapSimple(Blocks::ELEMENT_AMERICIUM(), Ids::ELEMENT_95); + $reg->mapSimple(Blocks::ELEMENT_ANTIMONY(), Ids::ELEMENT_51); + $reg->mapSimple(Blocks::ELEMENT_ARGON(), Ids::ELEMENT_18); + $reg->mapSimple(Blocks::ELEMENT_ARSENIC(), Ids::ELEMENT_33); + $reg->mapSimple(Blocks::ELEMENT_ASTATINE(), Ids::ELEMENT_85); + $reg->mapSimple(Blocks::ELEMENT_BARIUM(), Ids::ELEMENT_56); + $reg->mapSimple(Blocks::ELEMENT_BERKELIUM(), Ids::ELEMENT_97); + $reg->mapSimple(Blocks::ELEMENT_BERYLLIUM(), Ids::ELEMENT_4); + $reg->mapSimple(Blocks::ELEMENT_BISMUTH(), Ids::ELEMENT_83); + $reg->mapSimple(Blocks::ELEMENT_BOHRIUM(), Ids::ELEMENT_107); + $reg->mapSimple(Blocks::ELEMENT_BORON(), Ids::ELEMENT_5); + $reg->mapSimple(Blocks::ELEMENT_BROMINE(), Ids::ELEMENT_35); + $reg->mapSimple(Blocks::ELEMENT_CADMIUM(), Ids::ELEMENT_48); + $reg->mapSimple(Blocks::ELEMENT_CALCIUM(), Ids::ELEMENT_20); + $reg->mapSimple(Blocks::ELEMENT_CALIFORNIUM(), Ids::ELEMENT_98); + $reg->mapSimple(Blocks::ELEMENT_CARBON(), Ids::ELEMENT_6); + $reg->mapSimple(Blocks::ELEMENT_CERIUM(), Ids::ELEMENT_58); + $reg->mapSimple(Blocks::ELEMENT_CESIUM(), Ids::ELEMENT_55); + $reg->mapSimple(Blocks::ELEMENT_CHLORINE(), Ids::ELEMENT_17); + $reg->mapSimple(Blocks::ELEMENT_CHROMIUM(), Ids::ELEMENT_24); + $reg->mapSimple(Blocks::ELEMENT_COBALT(), Ids::ELEMENT_27); + $reg->mapSimple(Blocks::ELEMENT_COPERNICIUM(), Ids::ELEMENT_112); + $reg->mapSimple(Blocks::ELEMENT_COPPER(), Ids::ELEMENT_29); + $reg->mapSimple(Blocks::ELEMENT_CURIUM(), Ids::ELEMENT_96); + $reg->mapSimple(Blocks::ELEMENT_DARMSTADTIUM(), Ids::ELEMENT_110); + $reg->mapSimple(Blocks::ELEMENT_DUBNIUM(), Ids::ELEMENT_105); + $reg->mapSimple(Blocks::ELEMENT_DYSPROSIUM(), Ids::ELEMENT_66); + $reg->mapSimple(Blocks::ELEMENT_EINSTEINIUM(), Ids::ELEMENT_99); + $reg->mapSimple(Blocks::ELEMENT_ERBIUM(), Ids::ELEMENT_68); + $reg->mapSimple(Blocks::ELEMENT_EUROPIUM(), Ids::ELEMENT_63); + $reg->mapSimple(Blocks::ELEMENT_FERMIUM(), Ids::ELEMENT_100); + $reg->mapSimple(Blocks::ELEMENT_FLEROVIUM(), Ids::ELEMENT_114); + $reg->mapSimple(Blocks::ELEMENT_FLUORINE(), Ids::ELEMENT_9); + $reg->mapSimple(Blocks::ELEMENT_FRANCIUM(), Ids::ELEMENT_87); + $reg->mapSimple(Blocks::ELEMENT_GADOLINIUM(), Ids::ELEMENT_64); + $reg->mapSimple(Blocks::ELEMENT_GALLIUM(), Ids::ELEMENT_31); + $reg->mapSimple(Blocks::ELEMENT_GERMANIUM(), Ids::ELEMENT_32); + $reg->mapSimple(Blocks::ELEMENT_GOLD(), Ids::ELEMENT_79); + $reg->mapSimple(Blocks::ELEMENT_HAFNIUM(), Ids::ELEMENT_72); + $reg->mapSimple(Blocks::ELEMENT_HASSIUM(), Ids::ELEMENT_108); + $reg->mapSimple(Blocks::ELEMENT_HELIUM(), Ids::ELEMENT_2); + $reg->mapSimple(Blocks::ELEMENT_HOLMIUM(), Ids::ELEMENT_67); + $reg->mapSimple(Blocks::ELEMENT_HYDROGEN(), Ids::ELEMENT_1); + $reg->mapSimple(Blocks::ELEMENT_INDIUM(), Ids::ELEMENT_49); + $reg->mapSimple(Blocks::ELEMENT_IODINE(), Ids::ELEMENT_53); + $reg->mapSimple(Blocks::ELEMENT_IRIDIUM(), Ids::ELEMENT_77); + $reg->mapSimple(Blocks::ELEMENT_IRON(), Ids::ELEMENT_26); + $reg->mapSimple(Blocks::ELEMENT_KRYPTON(), Ids::ELEMENT_36); + $reg->mapSimple(Blocks::ELEMENT_LANTHANUM(), Ids::ELEMENT_57); + $reg->mapSimple(Blocks::ELEMENT_LAWRENCIUM(), Ids::ELEMENT_103); + $reg->mapSimple(Blocks::ELEMENT_LEAD(), Ids::ELEMENT_82); + $reg->mapSimple(Blocks::ELEMENT_LITHIUM(), Ids::ELEMENT_3); + $reg->mapSimple(Blocks::ELEMENT_LIVERMORIUM(), Ids::ELEMENT_116); + $reg->mapSimple(Blocks::ELEMENT_LUTETIUM(), Ids::ELEMENT_71); + $reg->mapSimple(Blocks::ELEMENT_MAGNESIUM(), Ids::ELEMENT_12); + $reg->mapSimple(Blocks::ELEMENT_MANGANESE(), Ids::ELEMENT_25); + $reg->mapSimple(Blocks::ELEMENT_MEITNERIUM(), Ids::ELEMENT_109); + $reg->mapSimple(Blocks::ELEMENT_MENDELEVIUM(), Ids::ELEMENT_101); + $reg->mapSimple(Blocks::ELEMENT_MERCURY(), Ids::ELEMENT_80); + $reg->mapSimple(Blocks::ELEMENT_MOLYBDENUM(), Ids::ELEMENT_42); + $reg->mapSimple(Blocks::ELEMENT_MOSCOVIUM(), Ids::ELEMENT_115); + $reg->mapSimple(Blocks::ELEMENT_NEODYMIUM(), Ids::ELEMENT_60); + $reg->mapSimple(Blocks::ELEMENT_NEON(), Ids::ELEMENT_10); + $reg->mapSimple(Blocks::ELEMENT_NEPTUNIUM(), Ids::ELEMENT_93); + $reg->mapSimple(Blocks::ELEMENT_NICKEL(), Ids::ELEMENT_28); + $reg->mapSimple(Blocks::ELEMENT_NIHONIUM(), Ids::ELEMENT_113); + $reg->mapSimple(Blocks::ELEMENT_NIOBIUM(), Ids::ELEMENT_41); + $reg->mapSimple(Blocks::ELEMENT_NITROGEN(), Ids::ELEMENT_7); + $reg->mapSimple(Blocks::ELEMENT_NOBELIUM(), Ids::ELEMENT_102); + $reg->mapSimple(Blocks::ELEMENT_OGANESSON(), Ids::ELEMENT_118); + $reg->mapSimple(Blocks::ELEMENT_OSMIUM(), Ids::ELEMENT_76); + $reg->mapSimple(Blocks::ELEMENT_OXYGEN(), Ids::ELEMENT_8); + $reg->mapSimple(Blocks::ELEMENT_PALLADIUM(), Ids::ELEMENT_46); + $reg->mapSimple(Blocks::ELEMENT_PHOSPHORUS(), Ids::ELEMENT_15); + $reg->mapSimple(Blocks::ELEMENT_PLATINUM(), Ids::ELEMENT_78); + $reg->mapSimple(Blocks::ELEMENT_PLUTONIUM(), Ids::ELEMENT_94); + $reg->mapSimple(Blocks::ELEMENT_POLONIUM(), Ids::ELEMENT_84); + $reg->mapSimple(Blocks::ELEMENT_POTASSIUM(), Ids::ELEMENT_19); + $reg->mapSimple(Blocks::ELEMENT_PRASEODYMIUM(), Ids::ELEMENT_59); + $reg->mapSimple(Blocks::ELEMENT_PROMETHIUM(), Ids::ELEMENT_61); + $reg->mapSimple(Blocks::ELEMENT_PROTACTINIUM(), Ids::ELEMENT_91); + $reg->mapSimple(Blocks::ELEMENT_RADIUM(), Ids::ELEMENT_88); + $reg->mapSimple(Blocks::ELEMENT_RADON(), Ids::ELEMENT_86); + $reg->mapSimple(Blocks::ELEMENT_RHENIUM(), Ids::ELEMENT_75); + $reg->mapSimple(Blocks::ELEMENT_RHODIUM(), Ids::ELEMENT_45); + $reg->mapSimple(Blocks::ELEMENT_ROENTGENIUM(), Ids::ELEMENT_111); + $reg->mapSimple(Blocks::ELEMENT_RUBIDIUM(), Ids::ELEMENT_37); + $reg->mapSimple(Blocks::ELEMENT_RUTHENIUM(), Ids::ELEMENT_44); + $reg->mapSimple(Blocks::ELEMENT_RUTHERFORDIUM(), Ids::ELEMENT_104); + $reg->mapSimple(Blocks::ELEMENT_SAMARIUM(), Ids::ELEMENT_62); + $reg->mapSimple(Blocks::ELEMENT_SCANDIUM(), Ids::ELEMENT_21); + $reg->mapSimple(Blocks::ELEMENT_SEABORGIUM(), Ids::ELEMENT_106); + $reg->mapSimple(Blocks::ELEMENT_SELENIUM(), Ids::ELEMENT_34); + $reg->mapSimple(Blocks::ELEMENT_SILICON(), Ids::ELEMENT_14); + $reg->mapSimple(Blocks::ELEMENT_SILVER(), Ids::ELEMENT_47); + $reg->mapSimple(Blocks::ELEMENT_SODIUM(), Ids::ELEMENT_11); + $reg->mapSimple(Blocks::ELEMENT_STRONTIUM(), Ids::ELEMENT_38); + $reg->mapSimple(Blocks::ELEMENT_SULFUR(), Ids::ELEMENT_16); + $reg->mapSimple(Blocks::ELEMENT_TANTALUM(), Ids::ELEMENT_73); + $reg->mapSimple(Blocks::ELEMENT_TECHNETIUM(), Ids::ELEMENT_43); + $reg->mapSimple(Blocks::ELEMENT_TELLURIUM(), Ids::ELEMENT_52); + $reg->mapSimple(Blocks::ELEMENT_TENNESSINE(), Ids::ELEMENT_117); + $reg->mapSimple(Blocks::ELEMENT_TERBIUM(), Ids::ELEMENT_65); + $reg->mapSimple(Blocks::ELEMENT_THALLIUM(), Ids::ELEMENT_81); + $reg->mapSimple(Blocks::ELEMENT_THORIUM(), Ids::ELEMENT_90); + $reg->mapSimple(Blocks::ELEMENT_THULIUM(), Ids::ELEMENT_69); + $reg->mapSimple(Blocks::ELEMENT_TIN(), Ids::ELEMENT_50); + $reg->mapSimple(Blocks::ELEMENT_TITANIUM(), Ids::ELEMENT_22); + $reg->mapSimple(Blocks::ELEMENT_TUNGSTEN(), Ids::ELEMENT_74); + $reg->mapSimple(Blocks::ELEMENT_URANIUM(), Ids::ELEMENT_92); + $reg->mapSimple(Blocks::ELEMENT_VANADIUM(), Ids::ELEMENT_23); + $reg->mapSimple(Blocks::ELEMENT_XENON(), Ids::ELEMENT_54); + $reg->mapSimple(Blocks::ELEMENT_YTTERBIUM(), Ids::ELEMENT_70); + $reg->mapSimple(Blocks::ELEMENT_YTTRIUM(), Ids::ELEMENT_39); + $reg->mapSimple(Blocks::ELEMENT_ZERO(), Ids::ELEMENT_0); + $reg->mapSimple(Blocks::ELEMENT_ZINC(), Ids::ELEMENT_30); + $reg->mapSimple(Blocks::ELEMENT_ZIRCONIUM(), Ids::ELEMENT_40); + $reg->mapSimple(Blocks::EMERALD(), Ids::EMERALD_BLOCK); + $reg->mapSimple(Blocks::EMERALD_ORE(), Ids::EMERALD_ORE); + $reg->mapSimple(Blocks::ENCHANTING_TABLE(), Ids::ENCHANTING_TABLE); + $reg->mapSimple(Blocks::END_STONE(), Ids::END_STONE); + $reg->mapSimple(Blocks::END_STONE_BRICKS(), Ids::END_BRICKS); + $reg->mapSimple(Blocks::FERN(), Ids::FERN); + $reg->mapSimple(Blocks::FLETCHING_TABLE(), Ids::FLETCHING_TABLE); + $reg->mapSimple(Blocks::GILDED_BLACKSTONE(), Ids::GILDED_BLACKSTONE); + $reg->mapSimple(Blocks::GLASS(), Ids::GLASS); + $reg->mapSimple(Blocks::GLASS_PANE(), Ids::GLASS_PANE); + $reg->mapSimple(Blocks::GLOWING_OBSIDIAN(), Ids::GLOWINGOBSIDIAN); + $reg->mapSimple(Blocks::GLOWSTONE(), Ids::GLOWSTONE); + $reg->mapSimple(Blocks::GOLD(), Ids::GOLD_BLOCK); + $reg->mapSimple(Blocks::GOLD_ORE(), Ids::GOLD_ORE); + $reg->mapSimple(Blocks::GRANITE(), Ids::GRANITE); + $reg->mapSimple(Blocks::GRASS(), Ids::GRASS_BLOCK); + $reg->mapSimple(Blocks::GRASS_PATH(), Ids::GRASS_PATH); + $reg->mapSimple(Blocks::GRAVEL(), Ids::GRAVEL); + $reg->mapSimple(Blocks::HANGING_ROOTS(), Ids::HANGING_ROOTS); + $reg->mapSimple(Blocks::HARDENED_CLAY(), Ids::HARDENED_CLAY); + $reg->mapSimple(Blocks::HARDENED_GLASS(), Ids::HARD_GLASS); + $reg->mapSimple(Blocks::HARDENED_GLASS_PANE(), Ids::HARD_GLASS_PANE); + $reg->mapSimple(Blocks::HONEYCOMB(), Ids::HONEYCOMB_BLOCK); + $reg->mapSimple(Blocks::ICE(), Ids::ICE); + $reg->mapSimple(Blocks::INFESTED_CHISELED_STONE_BRICK(), Ids::INFESTED_CHISELED_STONE_BRICKS); + $reg->mapSimple(Blocks::INFESTED_COBBLESTONE(), Ids::INFESTED_COBBLESTONE); + $reg->mapSimple(Blocks::INFESTED_CRACKED_STONE_BRICK(), Ids::INFESTED_CRACKED_STONE_BRICKS); + $reg->mapSimple(Blocks::INFESTED_MOSSY_STONE_BRICK(), Ids::INFESTED_MOSSY_STONE_BRICKS); + $reg->mapSimple(Blocks::INFESTED_STONE(), Ids::INFESTED_STONE); + $reg->mapSimple(Blocks::INFESTED_STONE_BRICK(), Ids::INFESTED_STONE_BRICKS); + $reg->mapSimple(Blocks::INFO_UPDATE(), Ids::INFO_UPDATE); + $reg->mapSimple(Blocks::INFO_UPDATE2(), Ids::INFO_UPDATE2); + $reg->mapSimple(Blocks::INVISIBLE_BEDROCK(), Ids::INVISIBLE_BEDROCK); + $reg->mapSimple(Blocks::IRON(), Ids::IRON_BLOCK); + $reg->mapSimple(Blocks::IRON_BARS(), Ids::IRON_BARS); + $reg->mapSimple(Blocks::IRON_ORE(), Ids::IRON_ORE); + $reg->mapSimple(Blocks::JUKEBOX(), Ids::JUKEBOX); + $reg->mapSimple(Blocks::LAPIS_LAZULI(), Ids::LAPIS_BLOCK); + $reg->mapSimple(Blocks::LAPIS_LAZULI_ORE(), Ids::LAPIS_ORE); + $reg->mapSimple(Blocks::LEGACY_STONECUTTER(), Ids::STONECUTTER); + $reg->mapSimple(Blocks::LILY_PAD(), Ids::WATERLILY); + $reg->mapSimple(Blocks::MAGMA(), Ids::MAGMA); + $reg->mapSimple(Blocks::MANGROVE_ROOTS(), Ids::MANGROVE_ROOTS); + $reg->mapSimple(Blocks::MELON(), Ids::MELON_BLOCK); + $reg->mapSimple(Blocks::MONSTER_SPAWNER(), Ids::MOB_SPAWNER); + $reg->mapSimple(Blocks::MOSSY_COBBLESTONE(), Ids::MOSSY_COBBLESTONE); + $reg->mapSimple(Blocks::MOSSY_STONE_BRICKS(), Ids::MOSSY_STONE_BRICKS); + $reg->mapSimple(Blocks::MUD(), Ids::MUD); + $reg->mapSimple(Blocks::MUD_BRICKS(), Ids::MUD_BRICKS); + $reg->mapSimple(Blocks::MYCELIUM(), Ids::MYCELIUM); + $reg->mapSimple(Blocks::NETHERITE(), Ids::NETHERITE_BLOCK); + $reg->mapSimple(Blocks::NETHERRACK(), Ids::NETHERRACK); + $reg->mapSimple(Blocks::NETHER_BRICKS(), Ids::NETHER_BRICK); + $reg->mapSimple(Blocks::NETHER_BRICK_FENCE(), Ids::NETHER_BRICK_FENCE); + $reg->mapSimple(Blocks::NETHER_GOLD_ORE(), Ids::NETHER_GOLD_ORE); + $reg->mapSimple(Blocks::NETHER_QUARTZ_ORE(), Ids::QUARTZ_ORE); + $reg->mapSimple(Blocks::NETHER_REACTOR_CORE(), Ids::NETHERREACTOR); + $reg->mapSimple(Blocks::NETHER_WART_BLOCK(), Ids::NETHER_WART_BLOCK); + $reg->mapSimple(Blocks::NOTE_BLOCK(), Ids::NOTEBLOCK); + $reg->mapSimple(Blocks::OBSIDIAN(), Ids::OBSIDIAN); + $reg->mapSimple(Blocks::PACKED_ICE(), Ids::PACKED_ICE); + $reg->mapSimple(Blocks::PACKED_MUD(), Ids::PACKED_MUD); + $reg->mapSimple(Blocks::PODZOL(), Ids::PODZOL); + $reg->mapSimple(Blocks::POLISHED_ANDESITE(), Ids::POLISHED_ANDESITE); + $reg->mapSimple(Blocks::POLISHED_BLACKSTONE(), Ids::POLISHED_BLACKSTONE); + $reg->mapSimple(Blocks::POLISHED_BLACKSTONE_BRICKS(), Ids::POLISHED_BLACKSTONE_BRICKS); + $reg->mapSimple(Blocks::POLISHED_DEEPSLATE(), Ids::POLISHED_DEEPSLATE); + $reg->mapSimple(Blocks::POLISHED_DIORITE(), Ids::POLISHED_DIORITE); + $reg->mapSimple(Blocks::POLISHED_GRANITE(), Ids::POLISHED_GRANITE); + $reg->mapSimple(Blocks::POLISHED_TUFF(), Ids::POLISHED_TUFF); + $reg->mapSimple(Blocks::PRISMARINE(), Ids::PRISMARINE); + $reg->mapSimple(Blocks::PRISMARINE_BRICKS(), Ids::PRISMARINE_BRICKS); + $reg->mapSimple(Blocks::QUARTZ_BRICKS(), Ids::QUARTZ_BRICKS); + $reg->mapSimple(Blocks::RAW_COPPER(), Ids::RAW_COPPER_BLOCK); + $reg->mapSimple(Blocks::RAW_GOLD(), Ids::RAW_GOLD_BLOCK); + $reg->mapSimple(Blocks::RAW_IRON(), Ids::RAW_IRON_BLOCK); + $reg->mapSimple(Blocks::REDSTONE(), Ids::REDSTONE_BLOCK); + $reg->mapSimple(Blocks::RED_MUSHROOM(), Ids::RED_MUSHROOM); + $reg->mapSimple(Blocks::RED_NETHER_BRICKS(), Ids::RED_NETHER_BRICK); + $reg->mapSimple(Blocks::RED_SAND(), Ids::RED_SAND); + $reg->mapSimple(Blocks::RED_SANDSTONE(), Ids::RED_SANDSTONE); + $reg->mapSimple(Blocks::REINFORCED_DEEPSLATE(), Ids::REINFORCED_DEEPSLATE); + $reg->mapSimple(Blocks::RESERVED6(), Ids::RESERVED6); + $reg->mapSimple(Blocks::RESIN(), Ids::RESIN_BLOCK); + $reg->mapSimple(Blocks::RESIN_BRICKS(), Ids::RESIN_BRICKS); + $reg->mapSimple(Blocks::SAND(), Ids::SAND); + $reg->mapSimple(Blocks::SANDSTONE(), Ids::SANDSTONE); + $reg->mapSimple(Blocks::SCULK(), Ids::SCULK); + $reg->mapSimple(Blocks::SEA_LANTERN(), Ids::SEA_LANTERN); + $reg->mapSimple(Blocks::SHROOMLIGHT(), Ids::SHROOMLIGHT); + $reg->mapSimple(Blocks::SHULKER_BOX(), Ids::UNDYED_SHULKER_BOX); + $reg->mapSimple(Blocks::SLIME(), Ids::SLIME); + $reg->mapSimple(Blocks::SMITHING_TABLE(), Ids::SMITHING_TABLE); + $reg->mapSimple(Blocks::SMOOTH_BASALT(), Ids::SMOOTH_BASALT); + $reg->mapSimple(Blocks::SMOOTH_RED_SANDSTONE(), Ids::SMOOTH_RED_SANDSTONE); + $reg->mapSimple(Blocks::SMOOTH_SANDSTONE(), Ids::SMOOTH_SANDSTONE); + $reg->mapSimple(Blocks::SMOOTH_STONE(), Ids::SMOOTH_STONE); + $reg->mapSimple(Blocks::SNOW(), Ids::SNOW); + $reg->mapSimple(Blocks::SOUL_SAND(), Ids::SOUL_SAND); + $reg->mapSimple(Blocks::SOUL_SOIL(), Ids::SOUL_SOIL); + $reg->mapSimple(Blocks::SPORE_BLOSSOM(), Ids::SPORE_BLOSSOM); + $reg->mapSimple(Blocks::STONE(), Ids::STONE); + $reg->mapSimple(Blocks::STONE_BRICKS(), Ids::STONE_BRICKS); + $reg->mapSimple(Blocks::TALL_GRASS(), Ids::SHORT_GRASS); //no, this is not a typo - tall_grass is now the double block, just to be confusing :( + $reg->mapSimple(Blocks::TINTED_GLASS(), Ids::TINTED_GLASS); + $reg->mapSimple(Blocks::TORCHFLOWER(), Ids::TORCHFLOWER); + $reg->mapSimple(Blocks::TUFF(), Ids::TUFF); + $reg->mapSimple(Blocks::TUFF_BRICKS(), Ids::TUFF_BRICKS); + $reg->mapSimple(Blocks::WARPED_WART_BLOCK(), Ids::WARPED_WART_BLOCK); + $reg->mapSimple(Blocks::WARPED_ROOTS(), Ids::WARPED_ROOTS); + $reg->mapSimple(Blocks::WITHER_ROSE(), Ids::WITHER_ROSE); + + $reg->mapSimple(Blocks::ALLIUM(), Ids::ALLIUM); + $reg->mapSimple(Blocks::CORNFLOWER(), Ids::CORNFLOWER); + $reg->mapSimple(Blocks::AZURE_BLUET(), Ids::AZURE_BLUET); + $reg->mapSimple(Blocks::LILY_OF_THE_VALLEY(), Ids::LILY_OF_THE_VALLEY); + $reg->mapSimple(Blocks::BLUE_ORCHID(), Ids::BLUE_ORCHID); + $reg->mapSimple(Blocks::OXEYE_DAISY(), Ids::OXEYE_DAISY); + $reg->mapSimple(Blocks::POPPY(), Ids::POPPY); + $reg->mapSimple(Blocks::ORANGE_TULIP(), Ids::ORANGE_TULIP); + $reg->mapSimple(Blocks::PINK_TULIP(), Ids::PINK_TULIP); + $reg->mapSimple(Blocks::RED_TULIP(), Ids::RED_TULIP); + $reg->mapSimple(Blocks::WHITE_TULIP(), Ids::WHITE_TULIP); + } + + private static function registerColoredMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + $reg->mapColored(Blocks::STAINED_HARDENED_GLASS(), "minecraft:hard_", "_stained_glass"); + $reg->mapColored(Blocks::STAINED_HARDENED_GLASS_PANE(), "minecraft:hard_", "_stained_glass_pane"); + + $reg->mapColored(Blocks::CARPET(), "minecraft:", "_carpet"); + $reg->mapColored(Blocks::CONCRETE(), "minecraft:", "_concrete"); + $reg->mapColored(Blocks::CONCRETE_POWDER(), "minecraft:", "_concrete_powder"); + $reg->mapColored(Blocks::DYED_SHULKER_BOX(), "minecraft:", "_shulker_box"); + $reg->mapColored(Blocks::STAINED_CLAY(), "minecraft:", "_terracotta"); + $reg->mapColored(Blocks::STAINED_GLASS(), "minecraft:", "_stained_glass"); + $reg->mapColored(Blocks::STAINED_GLASS_PANE(), "minecraft:", "_stained_glass_pane"); + $reg->mapColored(Blocks::WOOL(), "minecraft:", "_wool"); + + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::GLAZED_TERRACOTTA()) + ->idComponents([ + "minecraft:", + new ValueFromStringProperty("color", ValueMappings::getInstance()->dyeColorWithSilver, fn(GlazedTerracotta $b) => $b->getColor(), fn(GlazedTerracotta $b, DyeColor $v) => $b->setColor($v)), + "_glazed_terracotta" + ]) + ->properties([$commonProperties->horizontalFacingClassic]) + ); + } + + private static function registerCandleMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + $candleProperties = [ + $commonProperties->lit, + new IntProperty(StateNames::CANDLES, 0, 3, fn(Candle $b) => $b->getCount(), fn(Candle $b, int $v) => $b->setCount($v), offset: 1), + ]; + $cakeWithCandleProperties = [$commonProperties->lit]; + $reg->mapModel(Model::create(Blocks::CANDLE(), Ids::CANDLE)->properties($candleProperties)); + $reg->mapModel(Model::create(Blocks::CAKE_WITH_CANDLE(), Ids::CANDLE_CAKE)->properties($cakeWithCandleProperties)); + + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DYED_CANDLE()) + ->idComponents([ + "minecraft:", + $commonProperties->dyeColorIdInfix, + "_candle" + ]) + ->properties($candleProperties) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CAKE_WITH_DYED_CANDLE()) + ->idComponents([ + "minecraft:", + $commonProperties->dyeColorIdInfix, + "_candle_cake" + ]) + ->properties($cakeWithCandleProperties) + ); + } + + private static function registerLeavesMappings(BlockSerializerDeserializerRegistrar $reg) : void{ + $properties = [ + new BoolProperty(StateNames::PERSISTENT_BIT, fn(Leaves $b) => $b->isNoDecay(), fn(Leaves $b, bool $v) => $b->setNoDecay($v)), + new BoolProperty(StateNames::UPDATE_BIT, fn(Leaves $b) => $b->isCheckDecay(), fn(Leaves $b, bool $v) => $b->setCheckDecay($v)), + ]; + foreach([ + Ids::ACACIA_LEAVES => Blocks::ACACIA_LEAVES(), + Ids::AZALEA_LEAVES => Blocks::AZALEA_LEAVES(), + Ids::AZALEA_LEAVES_FLOWERED => Blocks::FLOWERING_AZALEA_LEAVES(), + Ids::BIRCH_LEAVES => Blocks::BIRCH_LEAVES(), + Ids::CHERRY_LEAVES => Blocks::CHERRY_LEAVES(), + Ids::DARK_OAK_LEAVES => Blocks::DARK_OAK_LEAVES(), + Ids::JUNGLE_LEAVES => Blocks::JUNGLE_LEAVES(), + Ids::MANGROVE_LEAVES => Blocks::MANGROVE_LEAVES(), + Ids::OAK_LEAVES => Blocks::OAK_LEAVES(), + Ids::PALE_OAK_LEAVES => Blocks::PALE_OAK_LEAVES(), + Ids::SPRUCE_LEAVES => Blocks::SPRUCE_LEAVES() + ] as $id => $block){ + $reg->mapModel(Model::create($block, $id)->properties($properties)); + } + } + + private static function registerSaplingMappings(BlockSerializerDeserializerRegistrar $reg) : void{ + $properties = [ + new BoolProperty(StateNames::AGE_BIT, fn(Sapling $b) => $b->isReady(), fn(Sapling $b, bool $v) => $b->setReady($v)), + ]; + foreach([ + Ids::ACACIA_SAPLING => Blocks::ACACIA_SAPLING(), + Ids::BIRCH_SAPLING => Blocks::BIRCH_SAPLING(), + Ids::DARK_OAK_SAPLING => Blocks::DARK_OAK_SAPLING(), + Ids::JUNGLE_SAPLING => Blocks::JUNGLE_SAPLING(), + Ids::OAK_SAPLING => Blocks::OAK_SAPLING(), + Ids::SPRUCE_SAPLING => Blocks::SPRUCE_SAPLING(), + ] as $id => $block){ + $reg->mapModel(Model::create($block, $id)->properties($properties)); + } + } + + private static function registerPlantMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + $reg->mapModel(Model::create(Blocks::BEETROOTS(), Ids::BEETROOT)->properties([$commonProperties->cropAgeMax7])); + $reg->mapModel(Model::create(Blocks::CARROTS(), Ids::CARROTS)->properties([$commonProperties->cropAgeMax7])); + $reg->mapModel(Model::create(Blocks::POTATOES(), Ids::POTATOES)->properties([$commonProperties->cropAgeMax7])); + $reg->mapModel(Model::create(Blocks::WHEAT(), Ids::WHEAT)->properties([$commonProperties->cropAgeMax7])); + + $reg->mapModel(Model::create(Blocks::MELON_STEM(), Ids::MELON_STEM)->properties($commonProperties->stemProperties)); + $reg->mapModel(Model::create(Blocks::PUMPKIN_STEM(), Ids::PUMPKIN_STEM)->properties($commonProperties->stemProperties)); + + foreach([ + [Blocks::DOUBLE_TALLGRASS(), Ids::TALL_GRASS], + [Blocks::LARGE_FERN(), Ids::LARGE_FERN], + [Blocks::LILAC(), Ids::LILAC], + [Blocks::PEONY(), Ids::PEONY], + [Blocks::ROSE_BUSH(), Ids::ROSE_BUSH], + [Blocks::SUNFLOWER(), Ids::SUNFLOWER], + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->doublePlantHalf])); + } + + foreach([ + [Blocks::BROWN_MUSHROOM_BLOCK(), Ids::BROWN_MUSHROOM_BLOCK], + [Blocks::RED_MUSHROOM_BLOCK(), Ids::RED_MUSHROOM_BLOCK] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([ + new ValueFromIntProperty(StateNames::HUGE_MUSHROOM_BITS, ValueMappings::getInstance()->mushroomBlockType, fn(RedMushroomBlock $b) => $b->getMushroomBlockType(), fn(RedMushroomBlock $b, MushroomBlockType $v) => $b->setMushroomBlockType($v)), + ])); + } + + $reg->mapModel(Model::create(Blocks::GLOW_LICHEN(), Ids::GLOW_LICHEN)->properties([$commonProperties->multiFacingFlags])); + $reg->mapModel(Model::create(Blocks::RESIN_CLUMP(), Ids::RESIN_CLUMP)->properties([$commonProperties->multiFacingFlags])); + + $reg->mapModel(Model::create(Blocks::VINES(), Ids::VINE)->properties([ + new OptionSetFromIntProperty( + StateNames::VINE_DIRECTION_BITS, + IntFromRawStateMap::int([ + Facing::NORTH => BlockLegacyMetadata::VINE_FLAG_NORTH, + Facing::SOUTH => BlockLegacyMetadata::VINE_FLAG_SOUTH, + Facing::WEST => BlockLegacyMetadata::VINE_FLAG_WEST, + Facing::EAST => BlockLegacyMetadata::VINE_FLAG_EAST, + ]), + fn(Vine $b) => $b->getFaces(), + fn(Vine $b, array $v) => $b->setFaces($v) + ) + ])); + + $reg->mapModel(Model::create(Blocks::SWEET_BERRY_BUSH(), Ids::SWEET_BERRY_BUSH)->properties([ + //TODO: berry bush only wants 0-3, but it can be bigger in MCPE due to misuse of GROWTH state which goes up to 7 + new IntProperty(StateNames::GROWTH, 0, 7, fn(SweetBerryBush $b) => $b->getAge(), fn(SweetBerryBush $b, int $v) => $b->setAge(min($v, SweetBerryBush::STAGE_MATURE))) + ])); + $reg->mapModel(Model::create(Blocks::TORCHFLOWER_CROP(), Ids::TORCHFLOWER_CROP)->properties([ + //TODO: this property can have values 0-7, but only 0-1 are valid + new IntProperty(StateNames::GROWTH, 0, 7, fn(TorchflowerCrop $b) => $b->isReady() ? 1 : 0, fn(TorchflowerCrop $b, int $v) => $b->setReady($v !== 0)) + ])); + } + + private static function registerCoralMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL())->idComponents([...$commonProperties->coralIdPrefixes, "_coral"])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL_BLOCK())->idComponents([...$commonProperties->coralIdPrefixes, "_coral_block"])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CORAL_FAN()) + ->idComponents([...$commonProperties->coralIdPrefixes, "_coral_fan"]) + ->properties([ + new ValueFromIntProperty(StateNames::CORAL_FAN_DIRECTION, ValueMappings::getInstance()->coralAxis, fn(FloorCoralFan $b) => $b->getAxis(), fn(FloorCoralFan $b, int $v) => $b->setAxis($v)) + ]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::WALL_CORAL_FAN()) + ->idComponents([...$commonProperties->coralIdPrefixes, "_coral_wall_fan"]) + ->properties([ + new ValueFromIntProperty(StateNames::CORAL_DIRECTION, ValueMappings::getInstance()->horizontalFacingCoral, fn(HorizontalFacing $b) => $b->getFacing(), fn(HorizontalFacing $b, int $v) => $b->setFacing($v)), + ]) + ); + } + + private static function registerCopperMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_BULB()) + ->idComponents([...$commonProperties->copperIdPrefixes, "copper_bulb"]) + ->properties([ + $commonProperties->lit, + new BoolProperty(StateNames::POWERED_BIT, fn(PoweredByRedstone $b) => $b->isPowered(), fn(PoweredByRedstone $b, bool $v) => $b->setPowered($v)), + ]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER()) + ->idComponents([ + ...$commonProperties->copperIdPrefixes, + "copper", + //HACK: the non-waxed, non-oxidised variant has a _block suffix, but none of the others do + new BoolFromStringProperty("bruhhhh", "", "_block", fn(Copper $b) => !$b->isWaxed() && $b->getOxidation() === CopperOxidation::NONE, fn() => null) + ]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CHISELED_COPPER())->idComponents([...$commonProperties->copperIdPrefixes, "chiseled_copper"])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_GRATE())->idComponents([...$commonProperties->copperIdPrefixes, "copper_grate"])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER())->idComponents([...$commonProperties->copperIdPrefixes, "cut_copper"])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER_STAIRS()) + ->idComponents([...$commonProperties->copperIdPrefixes, "cut_copper_stairs"]) + ->properties($commonProperties->stairProperties) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_TRAPDOOR()) + ->idComponents([...$commonProperties->copperIdPrefixes, "copper_trapdoor"]) + ->properties($commonProperties->trapdoorProperties) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::COPPER_DOOR()) + ->idComponents([...$commonProperties->copperIdPrefixes, "copper_door"]) + ->properties($commonProperties->doorProperties) + ); + + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CUT_COPPER_SLAB()) + ->idComponents([ + ...$commonProperties->copperIdPrefixes, + $commonProperties->slabIdInfix, + "cut_copper_slab" + ]) + ->properties([$commonProperties->slabPositionProperty]) + ); + } + + private static function registerFlattenedEnumMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + //A + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::ANVIL()) + ->idComponents([ + new ValueFromStringProperty("id", IntFromRawStateMap::string([ + 0 => Ids::ANVIL, + 1 => Ids::CHIPPED_ANVIL, + 2 => Ids::DAMAGED_ANVIL, + ]), fn(Anvil $b) => $b->getDamage(), fn(Anvil $b, int $v) => $b->setDamage($v)) + ]) + ->properties([$commonProperties->horizontalFacingCardinal]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::AMETHYST_CLUSTER()) + ->idComponents([ + new ValueFromStringProperty("id", IntFromRawStateMap::string([ + AmethystCluster::STAGE_SMALL_BUD => Ids::SMALL_AMETHYST_BUD, + AmethystCluster::STAGE_MEDIUM_BUD => Ids::MEDIUM_AMETHYST_BUD, + AmethystCluster::STAGE_LARGE_BUD => Ids::LARGE_AMETHYST_BUD, + AmethystCluster::STAGE_CLUSTER => Ids::AMETHYST_CLUSTER + ]), fn(AmethystCluster $b) => $b->getStage(), fn(AmethystCluster $b, int $v) => $b->setStage($v)) + ]) + ->properties([$commonProperties->blockFace]) + ); + + //C + //This one is a special offender :< + //I have no idea why this only has 3 IDs - there are 4 in Java and 4 visually distinct states in Bedrock + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::CAVE_VINES()) + ->idComponents([ + "minecraft:cave_vines", + new ValueFromStringProperty( + "variant", + EnumFromRawStateMap::string(FlattenedCaveVinesVariant::class, fn(FlattenedCaveVinesVariant $case) => $case->value), + fn(CaveVines $b) => $b->hasBerries() ? + ($b->isHead() ? + FlattenedCaveVinesVariant::HEAD_WITH_BERRIES : + FlattenedCaveVinesVariant::BODY_WITH_BERRIES) : + FlattenedCaveVinesVariant::NO_BERRIES, + fn(CaveVines $b, FlattenedCaveVinesVariant $v) => match($v){ + FlattenedCaveVinesVariant::HEAD_WITH_BERRIES => $b->setBerries(true)->setHead(true), + FlattenedCaveVinesVariant::BODY_WITH_BERRIES => $b->setBerries(true)->setHead(false), + FlattenedCaveVinesVariant::NO_BERRIES => $b->setBerries(false)->setHead(false), //assume this isn't a head, since we don't have enough information + } + ) + ]) + ->properties([ + new IntProperty(StateNames::GROWING_PLANT_AGE, 0, 25, fn(CaveVines $b) => $b->getAge(), fn(CaveVines $b, int $v) => $b->setAge($v)), + ]) + ); + + //D + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DIRT()) + ->idComponents([ + new ValueFromStringProperty("id", EnumFromRawStateMap::string(DirtType::class, fn(DirtType $case) => match ($case) { + DirtType::NORMAL => Ids::DIRT, + DirtType::COARSE => Ids::COARSE_DIRT, + DirtType::ROOTED => Ids::DIRT_WITH_ROOTS, + }), fn(Dirt $b) => $b->getDirtType(), fn(Dirt $b, DirtType $v) => $b->setDirtType($v)) + ]) + ); + + //F + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::FROGLIGHT()) + ->idComponents([ + new ValueFromStringProperty("id", ValueMappings::getInstance()->froglightType, fn(Froglight $b) => $b->getFroglightType(), fn(Froglight $b, FroglightType $v) => $b->setFroglightType($v)), + ]) + ->properties([$commonProperties->pillarAxis]) + ); + + //L + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::LIGHT()) + ->idComponents([ + "minecraft:light_block_", + //this is a bit shit but it's easier than adapting IntProperty to support flattening :D + new ValueFromStringProperty( + "light_level", + IntFromRawStateMap::string(array_map(strval(...), range(0, 15))), + fn(Light $b) => $b->getLightLevel(), + fn(Light $b, int $v) => $b->setLightLevel($v) + ) + ]) + ); + + //M + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::MOB_HEAD()) + ->idComponents([ + new ValueFromStringProperty("id", ValueMappings::getInstance()->mobHeadType, fn(MobHead $b) => $b->getMobHeadType(), fn(MobHead $b, MobHeadType $v) => $b->setMobHeadType($v)), + ]) + ->properties([ + new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingExceptDown, fn(MobHead $b) => $b->getFacing(), fn(MobHead $b, int $v) => $b->setFacing($v)) + ]) + ); + + foreach([ + [Blocks::LAVA(), "lava"], + [Blocks::WATER(), "water"] + ] as [$block, $idSuffix]){ + $reg->mapFlattenedId(FlattenedIdModel::create($block) + ->idComponents([...$commonProperties->liquidIdPrefixes, $idSuffix]) + ->properties([$commonProperties->liquidData]) + ); + } + } + + private static function registerFlattenedBoolMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + foreach([ + [Blocks::BLAST_FURNACE(), "blast_furnace"], + [Blocks::FURNACE(), "furnace"], + [Blocks::SMOKER(), "smoker"] + ] as [$block, $idSuffix]){ + $reg->mapFlattenedId(FlattenedIdModel::create($block) + ->idComponents([...$commonProperties->furnaceIdPrefixes, $idSuffix]) + ->properties([$commonProperties->horizontalFacingCardinal]) + ); + } + + foreach([ + [Blocks::REDSTONE_LAMP(), "redstone_lamp"], + [Blocks::REDSTONE_ORE(), "redstone_ore"], + [Blocks::DEEPSLATE_REDSTONE_ORE(), "deepslate_redstone_ore"] + ] as [$block, $idSuffix]){ + $reg->mapFlattenedId(FlattenedIdModel::create($block)->idComponents(["minecraft:", $commonProperties->litIdInfix, $idSuffix])); + } + + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::DAYLIGHT_SENSOR()) + ->idComponents([ + "minecraft:daylight_detector", + new BoolFromStringProperty("inverted", "", "_inverted", fn(DaylightSensor $b) => $b->isInverted(), fn(DaylightSensor $b, bool $v) => $b->setInverted($v)) + ]) + ->properties([$commonProperties->analogRedstoneSignal]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_REPEATER()) + ->idComponents([ + "minecraft:", + new BoolFromStringProperty("powered", "un", "", fn(RedstoneRepeater $b) => $b->isPowered(), fn(RedstoneRepeater $b, bool $v) => $b->setPowered($v)), + "powered_repeater" + ]) + ->properties([ + $commonProperties->horizontalFacingCardinal, + new IntProperty(StateNames::REPEATER_DELAY, 0, 3, fn(RedstoneRepeater $b) => $b->getDelay(), fn(RedstoneRepeater $b, int $v) => $b->setDelay($v), offset: 1), + ]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_COMPARATOR()) + ->idComponents([ + "minecraft:", + //this property also appears in the state, so we ignore it in the ID + //this is baked here purely to keep minecraft happy + new BoolFromStringProperty("dummy_powered", "un", "", fn(RedstoneComparator $b) => $b->isPowered(), fn() => null), + "powered_comparator" + ]) + ->properties([ + $commonProperties->horizontalFacingCardinal, + new BoolProperty(StateNames::OUTPUT_LIT_BIT, fn(RedstoneComparator $b) => $b->isPowered(), fn(RedstoneComparator $b, bool $v) => $b->setPowered($v)), + new BoolProperty(StateNames::OUTPUT_SUBTRACT_BIT, fn(RedstoneComparator $b) => $b->isSubtractMode(), fn(RedstoneComparator $b, bool $v) => $b->setSubtractMode($v)), + ]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::REDSTONE_TORCH()) + ->idComponents([ + "minecraft:", + new BoolFromStringProperty("lit", "unlit_", "", fn(RedstoneTorch $b) => $b->isLit(), fn(RedstoneTorch $b, bool $v) => $b->setLit($v)), + "redstone_torch" + ]) + ->properties([$commonProperties->torchFacing]) + ); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::SPONGE())->idComponents([ + "minecraft:", + new BoolFromStringProperty("wet", "", "wet_", fn(Sponge $b) => $b->isWet(), fn(Sponge $b, bool $v) => $b->setWet($v)), + "sponge" + ])); + $reg->mapFlattenedId(FlattenedIdModel::create(Blocks::TNT()) + ->idComponents([ + "minecraft:", + new BoolFromStringProperty("underwater", "", "underwater_", fn(TNT $b) => $b->worksUnderwater(), fn(TNT $b, bool $v) => $b->setWorksUnderwater($v)), + "tnt" + ]) + ->properties([ + new BoolProperty(StateNames::EXPLODE_BIT, fn(TNT $b) => $b->isUnstable(), fn(TNT $b, bool $v) => $b->setUnstable($v)), + ]) + ); + } + + private static function registerStoneLikeSlabMappings(BlockSerializerDeserializerRegistrar $reg) : void{ + $reg->mapSlab(Blocks::ANDESITE_SLAB(), "andesite"); + $reg->mapSlab(Blocks::BLACKSTONE_SLAB(), "blackstone"); + $reg->mapSlab(Blocks::BRICK_SLAB(), "brick"); + $reg->mapSlab(Blocks::COBBLED_DEEPSLATE_SLAB(), "cobbled_deepslate"); + $reg->mapSlab(Blocks::COBBLESTONE_SLAB(), "cobblestone"); + $reg->mapSlab(Blocks::CUT_RED_SANDSTONE_SLAB(), "cut_red_sandstone"); + $reg->mapSlab(Blocks::CUT_SANDSTONE_SLAB(), "cut_sandstone"); + $reg->mapSlab(Blocks::DARK_PRISMARINE_SLAB(), "dark_prismarine"); + $reg->mapSlab(Blocks::DEEPSLATE_BRICK_SLAB(), "deepslate_brick"); + $reg->mapSlab(Blocks::DEEPSLATE_TILE_SLAB(), "deepslate_tile"); + $reg->mapSlab(Blocks::DIORITE_SLAB(), "diorite"); + $reg->mapSlab(Blocks::END_STONE_BRICK_SLAB(), "end_stone_brick"); + $reg->mapSlab(Blocks::FAKE_WOODEN_SLAB(), "petrified_oak"); + $reg->mapSlab(Blocks::GRANITE_SLAB(), "granite"); + $reg->mapSlab(Blocks::MOSSY_COBBLESTONE_SLAB(), "mossy_cobblestone"); + $reg->mapSlab(Blocks::MOSSY_STONE_BRICK_SLAB(), "mossy_stone_brick"); + $reg->mapSlab(Blocks::MUD_BRICK_SLAB(), "mud_brick"); + $reg->mapSlab(Blocks::NETHER_BRICK_SLAB(), "nether_brick"); + $reg->mapSlab(Blocks::POLISHED_ANDESITE_SLAB(), "polished_andesite"); + $reg->mapSlab(Blocks::POLISHED_BLACKSTONE_BRICK_SLAB(), "polished_blackstone_brick"); + $reg->mapSlab(Blocks::POLISHED_BLACKSTONE_SLAB(), "polished_blackstone"); + $reg->mapSlab(Blocks::POLISHED_DEEPSLATE_SLAB(), "polished_deepslate"); + $reg->mapSlab(Blocks::POLISHED_DIORITE_SLAB(), "polished_diorite"); + $reg->mapSlab(Blocks::POLISHED_GRANITE_SLAB(), "polished_granite"); + $reg->mapSlab(Blocks::POLISHED_TUFF_SLAB(), "polished_tuff"); + $reg->mapSlab(Blocks::PRISMARINE_BRICKS_SLAB(), "prismarine_brick"); + $reg->mapSlab(Blocks::PRISMARINE_SLAB(), "prismarine"); + $reg->mapSlab(Blocks::PURPUR_SLAB(), "purpur"); + $reg->mapSlab(Blocks::QUARTZ_SLAB(), "quartz"); + $reg->mapSlab(Blocks::RED_NETHER_BRICK_SLAB(), "red_nether_brick"); + $reg->mapSlab(Blocks::RED_SANDSTONE_SLAB(), "red_sandstone"); + $reg->mapSlab(Blocks::RESIN_BRICK_SLAB(), "resin_brick"); + $reg->mapSlab(Blocks::SANDSTONE_SLAB(), "sandstone"); + $reg->mapSlab(Blocks::SMOOTH_QUARTZ_SLAB(), "smooth_quartz"); + $reg->mapSlab(Blocks::SMOOTH_RED_SANDSTONE_SLAB(), "smooth_red_sandstone"); + $reg->mapSlab(Blocks::SMOOTH_SANDSTONE_SLAB(), "smooth_sandstone"); + $reg->mapSlab(Blocks::SMOOTH_STONE_SLAB(), "smooth_stone"); + $reg->mapSlab(Blocks::STONE_BRICK_SLAB(), "stone_brick"); + $reg->mapSlab(Blocks::STONE_SLAB(), "normal_stone"); + $reg->mapSlab(Blocks::TUFF_BRICK_SLAB(), "tuff_brick"); + $reg->mapSlab(Blocks::TUFF_SLAB(), "tuff"); + } + + private static function registerStoneLikeStairMappings(BlockSerializerDeserializerRegistrar $reg) : void{ + $reg->mapStairs(Blocks::ANDESITE_STAIRS(), Ids::ANDESITE_STAIRS); + $reg->mapStairs(Blocks::BLACKSTONE_STAIRS(), Ids::BLACKSTONE_STAIRS); + $reg->mapStairs(Blocks::BRICK_STAIRS(), Ids::BRICK_STAIRS); + $reg->mapStairs(Blocks::COBBLED_DEEPSLATE_STAIRS(), Ids::COBBLED_DEEPSLATE_STAIRS); + $reg->mapStairs(Blocks::COBBLESTONE_STAIRS(), Ids::STONE_STAIRS); + $reg->mapStairs(Blocks::DARK_PRISMARINE_STAIRS(), Ids::DARK_PRISMARINE_STAIRS); + $reg->mapStairs(Blocks::DEEPSLATE_BRICK_STAIRS(), Ids::DEEPSLATE_BRICK_STAIRS); + $reg->mapStairs(Blocks::DEEPSLATE_TILE_STAIRS(), Ids::DEEPSLATE_TILE_STAIRS); + $reg->mapStairs(Blocks::DIORITE_STAIRS(), Ids::DIORITE_STAIRS); + $reg->mapStairs(Blocks::END_STONE_BRICK_STAIRS(), Ids::END_BRICK_STAIRS); + $reg->mapStairs(Blocks::GRANITE_STAIRS(), Ids::GRANITE_STAIRS); + $reg->mapStairs(Blocks::MOSSY_COBBLESTONE_STAIRS(), Ids::MOSSY_COBBLESTONE_STAIRS); + $reg->mapStairs(Blocks::MOSSY_STONE_BRICK_STAIRS(), Ids::MOSSY_STONE_BRICK_STAIRS); + $reg->mapStairs(Blocks::MUD_BRICK_STAIRS(), Ids::MUD_BRICK_STAIRS); + $reg->mapStairs(Blocks::NETHER_BRICK_STAIRS(), Ids::NETHER_BRICK_STAIRS); + $reg->mapStairs(Blocks::POLISHED_ANDESITE_STAIRS(), Ids::POLISHED_ANDESITE_STAIRS); + $reg->mapStairs(Blocks::POLISHED_BLACKSTONE_BRICK_STAIRS(), Ids::POLISHED_BLACKSTONE_BRICK_STAIRS); + $reg->mapStairs(Blocks::POLISHED_BLACKSTONE_STAIRS(), Ids::POLISHED_BLACKSTONE_STAIRS); + $reg->mapStairs(Blocks::POLISHED_DEEPSLATE_STAIRS(), Ids::POLISHED_DEEPSLATE_STAIRS); + $reg->mapStairs(Blocks::POLISHED_DIORITE_STAIRS(), Ids::POLISHED_DIORITE_STAIRS); + $reg->mapStairs(Blocks::POLISHED_GRANITE_STAIRS(), Ids::POLISHED_GRANITE_STAIRS); + $reg->mapStairs(Blocks::POLISHED_TUFF_STAIRS(), Ids::POLISHED_TUFF_STAIRS); + $reg->mapStairs(Blocks::PRISMARINE_BRICKS_STAIRS(), Ids::PRISMARINE_BRICKS_STAIRS); + $reg->mapStairs(Blocks::PRISMARINE_STAIRS(), Ids::PRISMARINE_STAIRS); + $reg->mapStairs(Blocks::PURPUR_STAIRS(), Ids::PURPUR_STAIRS); + $reg->mapStairs(Blocks::QUARTZ_STAIRS(), Ids::QUARTZ_STAIRS); + $reg->mapStairs(Blocks::RED_NETHER_BRICK_STAIRS(), Ids::RED_NETHER_BRICK_STAIRS); + $reg->mapStairs(Blocks::RED_SANDSTONE_STAIRS(), Ids::RED_SANDSTONE_STAIRS); + $reg->mapStairs(Blocks::RESIN_BRICK_STAIRS(), Ids::RESIN_BRICK_STAIRS); + $reg->mapStairs(Blocks::SANDSTONE_STAIRS(), Ids::SANDSTONE_STAIRS); + $reg->mapStairs(Blocks::SMOOTH_QUARTZ_STAIRS(), Ids::SMOOTH_QUARTZ_STAIRS); + $reg->mapStairs(Blocks::SMOOTH_RED_SANDSTONE_STAIRS(), Ids::SMOOTH_RED_SANDSTONE_STAIRS); + $reg->mapStairs(Blocks::SMOOTH_SANDSTONE_STAIRS(), Ids::SMOOTH_SANDSTONE_STAIRS); + $reg->mapStairs(Blocks::STONE_BRICK_STAIRS(), Ids::STONE_BRICK_STAIRS); + $reg->mapStairs(Blocks::STONE_STAIRS(), Ids::NORMAL_STONE_STAIRS); + $reg->mapStairs(Blocks::TUFF_BRICK_STAIRS(), Ids::TUFF_BRICK_STAIRS); + $reg->mapStairs(Blocks::TUFF_STAIRS(), Ids::TUFF_STAIRS); + } + + private static function registerStoneLikeWallMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + foreach([ + Ids::ANDESITE_WALL => Blocks::ANDESITE_WALL(), + Ids::BLACKSTONE_WALL => Blocks::BLACKSTONE_WALL(), + Ids::BRICK_WALL => Blocks::BRICK_WALL(), + Ids::COBBLED_DEEPSLATE_WALL => Blocks::COBBLED_DEEPSLATE_WALL(), + Ids::COBBLESTONE_WALL => Blocks::COBBLESTONE_WALL(), + Ids::DEEPSLATE_BRICK_WALL => Blocks::DEEPSLATE_BRICK_WALL(), + Ids::DEEPSLATE_TILE_WALL => Blocks::DEEPSLATE_TILE_WALL(), + Ids::DIORITE_WALL => Blocks::DIORITE_WALL(), + Ids::END_STONE_BRICK_WALL => Blocks::END_STONE_BRICK_WALL(), + Ids::GRANITE_WALL => Blocks::GRANITE_WALL(), + Ids::MOSSY_COBBLESTONE_WALL => Blocks::MOSSY_COBBLESTONE_WALL(), + Ids::MOSSY_STONE_BRICK_WALL => Blocks::MOSSY_STONE_BRICK_WALL(), + Ids::MUD_BRICK_WALL => Blocks::MUD_BRICK_WALL(), + Ids::NETHER_BRICK_WALL => Blocks::NETHER_BRICK_WALL(), + Ids::POLISHED_BLACKSTONE_BRICK_WALL => Blocks::POLISHED_BLACKSTONE_BRICK_WALL(), + Ids::POLISHED_BLACKSTONE_WALL => Blocks::POLISHED_BLACKSTONE_WALL(), + Ids::POLISHED_DEEPSLATE_WALL => Blocks::POLISHED_DEEPSLATE_WALL(), + Ids::POLISHED_TUFF_WALL => Blocks::POLISHED_TUFF_WALL(), + Ids::PRISMARINE_WALL => Blocks::PRISMARINE_WALL(), + Ids::RED_NETHER_BRICK_WALL => Blocks::RED_NETHER_BRICK_WALL(), + Ids::RED_SANDSTONE_WALL => Blocks::RED_SANDSTONE_WALL(), + Ids::RESIN_BRICK_WALL => Blocks::RESIN_BRICK_WALL(), + Ids::SANDSTONE_WALL => Blocks::SANDSTONE_WALL(), + Ids::STONE_BRICK_WALL => Blocks::STONE_BRICK_WALL(), + Ids::TUFF_BRICK_WALL => Blocks::TUFF_BRICK_WALL(), + Ids::TUFF_WALL => Blocks::TUFF_WALL() + ] as $id => $block){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->wallProperties)); + } + } + + private static function registerWoodMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + //buttons + foreach([ + [Blocks::ACACIA_BUTTON(), Ids::ACACIA_BUTTON], + [Blocks::BIRCH_BUTTON(), Ids::BIRCH_BUTTON], + [Blocks::CHERRY_BUTTON(), Ids::CHERRY_BUTTON], + [Blocks::CRIMSON_BUTTON(), Ids::CRIMSON_BUTTON], + [Blocks::DARK_OAK_BUTTON(), Ids::DARK_OAK_BUTTON], + [Blocks::JUNGLE_BUTTON(), Ids::JUNGLE_BUTTON], + [Blocks::MANGROVE_BUTTON(), Ids::MANGROVE_BUTTON], + [Blocks::OAK_BUTTON(), Ids::WOODEN_BUTTON], + [Blocks::PALE_OAK_BUTTON(), Ids::PALE_OAK_BUTTON], + [Blocks::SPRUCE_BUTTON(), Ids::SPRUCE_BUTTON], + [Blocks::WARPED_BUTTON(), Ids::WARPED_BUTTON] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->buttonProperties)); + } + + //doors + foreach([ + [Blocks::ACACIA_DOOR(), Ids::ACACIA_DOOR], + [Blocks::BIRCH_DOOR(), Ids::BIRCH_DOOR], + [Blocks::CHERRY_DOOR(), Ids::CHERRY_DOOR], + [Blocks::CRIMSON_DOOR(), Ids::CRIMSON_DOOR], + [Blocks::DARK_OAK_DOOR(), Ids::DARK_OAK_DOOR], + [Blocks::JUNGLE_DOOR(), Ids::JUNGLE_DOOR], + [Blocks::MANGROVE_DOOR(), Ids::MANGROVE_DOOR], + [Blocks::OAK_DOOR(), Ids::WOODEN_DOOR], + [Blocks::PALE_OAK_DOOR(), Ids::PALE_OAK_DOOR], + [Blocks::SPRUCE_DOOR(), Ids::SPRUCE_DOOR], + [Blocks::WARPED_DOOR(), Ids::WARPED_DOOR] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->doorProperties)); + } + + //fences + foreach([ + [Blocks::ACACIA_FENCE(), Ids::ACACIA_FENCE], + [Blocks::BIRCH_FENCE(), Ids::BIRCH_FENCE], + [Blocks::CHERRY_FENCE(), Ids::CHERRY_FENCE], + [Blocks::DARK_OAK_FENCE(), Ids::DARK_OAK_FENCE], + [Blocks::JUNGLE_FENCE(), Ids::JUNGLE_FENCE], + [Blocks::MANGROVE_FENCE(), Ids::MANGROVE_FENCE], + [Blocks::OAK_FENCE(), Ids::OAK_FENCE], + [Blocks::PALE_OAK_FENCE(), Ids::PALE_OAK_FENCE], + [Blocks::SPRUCE_FENCE(), Ids::SPRUCE_FENCE], + [Blocks::CRIMSON_FENCE(), Ids::CRIMSON_FENCE], + [Blocks::WARPED_FENCE(), Ids::WARPED_FENCE] + ] as [$block, $id]){ + $reg->mapSimple($block, $id); + } + + foreach([ + [Blocks::ACACIA_FENCE_GATE(), Ids::ACACIA_FENCE_GATE], + [Blocks::BIRCH_FENCE_GATE(), Ids::BIRCH_FENCE_GATE], + [Blocks::CHERRY_FENCE_GATE(), Ids::CHERRY_FENCE_GATE], + [Blocks::DARK_OAK_FENCE_GATE(), Ids::DARK_OAK_FENCE_GATE], + [Blocks::JUNGLE_FENCE_GATE(), Ids::JUNGLE_FENCE_GATE], + [Blocks::MANGROVE_FENCE_GATE(), Ids::MANGROVE_FENCE_GATE], + [Blocks::OAK_FENCE_GATE(), Ids::FENCE_GATE], + [Blocks::PALE_OAK_FENCE_GATE(), Ids::PALE_OAK_FENCE_GATE], + [Blocks::SPRUCE_FENCE_GATE(), Ids::SPRUCE_FENCE_GATE], + [Blocks::CRIMSON_FENCE_GATE(), Ids::CRIMSON_FENCE_GATE], + [Blocks::WARPED_FENCE_GATE(), Ids::WARPED_FENCE_GATE] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->fenceGateProperties)); + } + + foreach([ + [Blocks::ACACIA_SIGN(), Ids::ACACIA_STANDING_SIGN], + [Blocks::BIRCH_SIGN(), Ids::BIRCH_STANDING_SIGN], + [Blocks::CHERRY_SIGN(), Ids::CHERRY_STANDING_SIGN], + [Blocks::DARK_OAK_SIGN(), Ids::DARKOAK_STANDING_SIGN], + [Blocks::JUNGLE_SIGN(), Ids::JUNGLE_STANDING_SIGN], + [Blocks::MANGROVE_SIGN(), Ids::MANGROVE_STANDING_SIGN], + [Blocks::OAK_SIGN(), Ids::STANDING_SIGN], + [Blocks::PALE_OAK_SIGN(), Ids::PALE_OAK_STANDING_SIGN], + [Blocks::SPRUCE_SIGN(), Ids::SPRUCE_STANDING_SIGN], + [Blocks::CRIMSON_SIGN(), Ids::CRIMSON_STANDING_SIGN], + [Blocks::WARPED_SIGN(), Ids::WARPED_STANDING_SIGN] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->floorSignLikeRotation])); + } + + //logs + foreach([ + [Blocks::ACACIA_LOG(), "acacia_log"], + [Blocks::BIRCH_LOG(), "birch_log"], + [Blocks::CHERRY_LOG(), "cherry_log"], + [Blocks::DARK_OAK_LOG(), "dark_oak_log"], + [Blocks::JUNGLE_LOG(), "jungle_log"], + [Blocks::MANGROVE_LOG(), "mangrove_log"], + [Blocks::OAK_LOG(), "oak_log"], + [Blocks::PALE_OAK_LOG(), "pale_oak_log"], + [Blocks::SPRUCE_LOG(), "spruce_log"], + [Blocks::CRIMSON_STEM(), "crimson_stem"], + [Blocks::WARPED_STEM(), "warped_stem"], + + //all-sided logs + [Blocks::ACACIA_WOOD(), "acacia_wood"], + [Blocks::BIRCH_WOOD(), "birch_wood"], + [Blocks::CHERRY_WOOD(), "cherry_wood"], + [Blocks::DARK_OAK_WOOD(), "dark_oak_wood"], + [Blocks::JUNGLE_WOOD(), "jungle_wood"], + [Blocks::MANGROVE_WOOD(), "mangrove_wood"], + [Blocks::OAK_WOOD(), "oak_wood"], + [Blocks::PALE_OAK_WOOD(), "pale_oak_wood"], + [Blocks::SPRUCE_WOOD(), "spruce_wood"], + [Blocks::CRIMSON_HYPHAE(), "crimson_hyphae"], + [Blocks::WARPED_HYPHAE(), "warped_hyphae"] + ] as [$block, $idSuffix]){ + $reg->mapFlattenedId(FlattenedIdModel::create($block) + ->idComponents([...$commonProperties->woodIdPrefixes, $idSuffix]) + ->properties([$commonProperties->pillarAxis]) + ); + } + + //planks + foreach([ + [Blocks::ACACIA_PLANKS(), Ids::ACACIA_PLANKS], + [Blocks::BIRCH_PLANKS(), Ids::BIRCH_PLANKS], + [Blocks::CHERRY_PLANKS(), Ids::CHERRY_PLANKS], + [Blocks::DARK_OAK_PLANKS(), Ids::DARK_OAK_PLANKS], + [Blocks::JUNGLE_PLANKS(), Ids::JUNGLE_PLANKS], + [Blocks::MANGROVE_PLANKS(), Ids::MANGROVE_PLANKS], + [Blocks::OAK_PLANKS(), Ids::OAK_PLANKS], + [Blocks::PALE_OAK_PLANKS(), Ids::PALE_OAK_PLANKS], + [Blocks::SPRUCE_PLANKS(), Ids::SPRUCE_PLANKS], + [Blocks::CRIMSON_PLANKS(), Ids::CRIMSON_PLANKS], + [Blocks::WARPED_PLANKS(), Ids::WARPED_PLANKS] + ] as [$block, $id]){ + $reg->mapSimple($block, $id); + } + + //pressure plates + foreach([ + [Blocks::ACACIA_PRESSURE_PLATE(), Ids::ACACIA_PRESSURE_PLATE], + [Blocks::BIRCH_PRESSURE_PLATE(), Ids::BIRCH_PRESSURE_PLATE], + [Blocks::CHERRY_PRESSURE_PLATE(), Ids::CHERRY_PRESSURE_PLATE], + [Blocks::DARK_OAK_PRESSURE_PLATE(), Ids::DARK_OAK_PRESSURE_PLATE], + [Blocks::JUNGLE_PRESSURE_PLATE(), Ids::JUNGLE_PRESSURE_PLATE], + [Blocks::MANGROVE_PRESSURE_PLATE(), Ids::MANGROVE_PRESSURE_PLATE], + [Blocks::OAK_PRESSURE_PLATE(), Ids::WOODEN_PRESSURE_PLATE], + [Blocks::PALE_OAK_PRESSURE_PLATE(), Ids::PALE_OAK_PRESSURE_PLATE], + [Blocks::SPRUCE_PRESSURE_PLATE(), Ids::SPRUCE_PRESSURE_PLATE], + [Blocks::CRIMSON_PRESSURE_PLATE(), Ids::CRIMSON_PRESSURE_PLATE], + [Blocks::WARPED_PRESSURE_PLATE(), Ids::WARPED_PRESSURE_PLATE] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->simplePressurePlateProperties)); + } + + //slabs + foreach([ + [Blocks::ACACIA_SLAB(), "acacia"], + [Blocks::BIRCH_SLAB(), "birch"], + [Blocks::CHERRY_SLAB(), "cherry"], + [Blocks::DARK_OAK_SLAB(), "dark_oak"], + [Blocks::JUNGLE_SLAB(), "jungle"], + [Blocks::MANGROVE_SLAB(), "mangrove"], + [Blocks::OAK_SLAB(), "oak"], + [Blocks::PALE_OAK_SLAB(), "pale_oak"], + [Blocks::SPRUCE_SLAB(), "spruce"], + [Blocks::CRIMSON_SLAB(), "crimson"], + [Blocks::WARPED_SLAB(), "warped"] + ] as [$block, $type]){ + $reg->mapSlab($block, $type); + } + + //stairs + foreach([ + [Blocks::ACACIA_STAIRS(), Ids::ACACIA_STAIRS], + [Blocks::BIRCH_STAIRS(), Ids::BIRCH_STAIRS], + [Blocks::CHERRY_STAIRS(), Ids::CHERRY_STAIRS], + [Blocks::DARK_OAK_STAIRS(), Ids::DARK_OAK_STAIRS], + [Blocks::JUNGLE_STAIRS(), Ids::JUNGLE_STAIRS], + [Blocks::MANGROVE_STAIRS(), Ids::MANGROVE_STAIRS], + [Blocks::OAK_STAIRS(), Ids::OAK_STAIRS], + [Blocks::PALE_OAK_STAIRS(), Ids::PALE_OAK_STAIRS], + [Blocks::SPRUCE_STAIRS(), Ids::SPRUCE_STAIRS], + [Blocks::CRIMSON_STAIRS(), Ids::CRIMSON_STAIRS], + [Blocks::WARPED_STAIRS(), Ids::WARPED_STAIRS] + ] as [$block, $id]){ + $reg->mapStairs($block, $id); + } + + //trapdoors + foreach([ + [Blocks::ACACIA_TRAPDOOR(), Ids::ACACIA_TRAPDOOR], + [Blocks::BIRCH_TRAPDOOR(), Ids::BIRCH_TRAPDOOR], + [Blocks::CHERRY_TRAPDOOR(), Ids::CHERRY_TRAPDOOR], + [Blocks::DARK_OAK_TRAPDOOR(), Ids::DARK_OAK_TRAPDOOR], + [Blocks::JUNGLE_TRAPDOOR(), Ids::JUNGLE_TRAPDOOR], + [Blocks::MANGROVE_TRAPDOOR(), Ids::MANGROVE_TRAPDOOR], + [Blocks::OAK_TRAPDOOR(), Ids::TRAPDOOR], + [Blocks::PALE_OAK_TRAPDOOR(), Ids::PALE_OAK_TRAPDOOR], + [Blocks::SPRUCE_TRAPDOOR(), Ids::SPRUCE_TRAPDOOR], + [Blocks::CRIMSON_TRAPDOOR(), Ids::CRIMSON_TRAPDOOR], + [Blocks::WARPED_TRAPDOOR(), Ids::WARPED_TRAPDOOR] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties($commonProperties->trapdoorProperties)); + } + + //wall signs + foreach([ + [Blocks::ACACIA_WALL_SIGN(), Ids::ACACIA_WALL_SIGN], + [Blocks::BIRCH_WALL_SIGN(), Ids::BIRCH_WALL_SIGN], + [Blocks::CHERRY_WALL_SIGN(), Ids::CHERRY_WALL_SIGN], + [Blocks::DARK_OAK_WALL_SIGN(), Ids::DARKOAK_WALL_SIGN], + [Blocks::JUNGLE_WALL_SIGN(), Ids::JUNGLE_WALL_SIGN], + [Blocks::MANGROVE_WALL_SIGN(), Ids::MANGROVE_WALL_SIGN], + [Blocks::OAK_WALL_SIGN(), Ids::WALL_SIGN], + [Blocks::PALE_OAK_WALL_SIGN(), Ids::PALE_OAK_WALL_SIGN], + [Blocks::SPRUCE_WALL_SIGN(), Ids::SPRUCE_WALL_SIGN], + [Blocks::CRIMSON_WALL_SIGN(), Ids::CRIMSON_WALL_SIGN], + [Blocks::WARPED_WALL_SIGN(), Ids::WARPED_WALL_SIGN] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->horizontalFacingClassic])); + } + } + + private static function registerTorchMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + foreach([ + [Blocks::BLUE_TORCH(), Ids::COLORED_TORCH_BLUE], + [Blocks::GREEN_TORCH(), Ids::COLORED_TORCH_GREEN], + [Blocks::PURPLE_TORCH(), Ids::COLORED_TORCH_PURPLE], + [Blocks::RED_TORCH(), Ids::COLORED_TORCH_RED], + [Blocks::SOUL_TORCH(), Ids::SOUL_TORCH], + [Blocks::TORCH(), Ids::TORCH], + [Blocks::UNDERWATER_TORCH(), Ids::UNDERWATER_TORCH] + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->torchFacing])); + } + } + + private static function registerChemistryMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + foreach([ + [Blocks::COMPOUND_CREATOR(), Ids::COMPOUND_CREATOR], + [Blocks::ELEMENT_CONSTRUCTOR(), Ids::ELEMENT_CONSTRUCTOR], + [Blocks::LAB_TABLE(), Ids::LAB_TABLE], + [Blocks::MATERIAL_REDUCER(), Ids::MATERIAL_REDUCER], + ] as [$block, $id]){ + $reg->mapModel(Model::create($block, $id)->properties([$commonProperties->horizontalFacingSWNEInverted])); + } + } + + private static function register1to1CustomMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + //TODO: some of these have repeated accessor refs, we might be able to deduplicate them + //A + $reg->mapModel(Model::create(Blocks::ACTIVATOR_RAIL(), Ids::ACTIVATOR_RAIL)->properties([ + new BoolProperty(StateNames::RAIL_DATA_BIT, fn(ActivatorRail $b) => $b->isPowered(), fn(ActivatorRail $b, bool $v) => $b->setPowered($v)), + new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(ActivatorRail $b) => $b->getShape(), fn(ActivatorRail $b, int $v) => $b->setShape($v)) + ])); + + //B + $reg->mapModel(Model::create(Blocks::BAMBOO(), Ids::BAMBOO)->properties([ + new ValueFromStringProperty(StateNames::BAMBOO_LEAF_SIZE, ValueMappings::getInstance()->bambooLeafSize, fn(Bamboo $b) => $b->getLeafSize(), fn(Bamboo $b, int $v) => $b->setLeafSize($v)), + new BoolProperty(StateNames::AGE_BIT, fn(Bamboo $b) => $b->isReady(), fn(Bamboo $b, bool $v) => $b->setReady($v)), + new BoolFromStringProperty(StateNames::BAMBOO_STALK_THICKNESS, StringValues::BAMBOO_STALK_THICKNESS_THIN, StringValues::BAMBOO_STALK_THICKNESS_THICK, fn(Bamboo $b) => $b->isThick(), fn(Bamboo $b, bool $v) => $b->setThick($v)) + ])); + $reg->mapModel(Model::create(Blocks::BAMBOO_SAPLING(), Ids::BAMBOO_SAPLING)->properties([ + new BoolProperty(StateNames::AGE_BIT, fn(BambooSapling $b) => $b->isReady(), fn(BambooSapling $b, bool $v) => $b->setReady($v)) + ])); + $reg->mapModel(Model::create(Blocks::BANNER(), Ids::STANDING_BANNER)->properties([$commonProperties->floorSignLikeRotation])); + $reg->mapModel(Model::create(Blocks::BARREL(), Ids::BARREL)->properties([ + $commonProperties->anyFacingClassic, + new BoolProperty(StateNames::OPEN_BIT, fn(Barrel $b) => $b->isOpen(), fn(Barrel $b, bool $v) => $b->setOpen($v)) + ])); + $reg->mapModel(Model::create(Blocks::BASALT(), Ids::BASALT)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::BED(), Ids::BED)->properties([ + new BoolProperty(StateNames::HEAD_PIECE_BIT, fn(Bed $b) => $b->isHeadPart(), fn(Bed $b, bool $v) => $b->setHead($v)), + new BoolProperty(StateNames::OCCUPIED_BIT, fn(Bed $b) => $b->isOccupied(), fn(Bed $b, bool $v) => $b->setOccupied($v)), + $commonProperties->horizontalFacingSWNE + ])); + $reg->mapModel(Model::create(Blocks::BEDROCK(), Ids::BEDROCK)->properties([ + new BoolProperty(StateNames::INFINIBURN_BIT, fn(Bedrock $b) => $b->burnsForever(), fn(Bedrock $b, bool $v) => $b->setBurnsForever($v)) + ])); + $reg->mapModel(Model::create(Blocks::BELL(), Ids::BELL)->properties([ + BoolProperty::unused(StateNames::TOGGLE_BIT, false), + new ValueFromStringProperty(StateNames::ATTACHMENT, ValueMappings::getInstance()->bellAttachmentType, fn(Bell $b) => $b->getAttachmentType(), fn(Bell $b, BellAttachmentType $v) => $b->setAttachmentType($v)), + $commonProperties->horizontalFacingSWNE + ])); + $reg->mapModel(Model::create(Blocks::BONE_BLOCK(), Ids::BONE_BLOCK)->properties([ + IntProperty::unused(StateNames::DEPRECATED, 0), + $commonProperties->pillarAxis + ])); + + $reg->mapModel(Model::create(Blocks::BREWING_STAND(), Ids::BREWING_STAND)->properties(array_map(fn(BrewingStandSlot $slot) => new BoolProperty(match ($slot) { + BrewingStandSlot::EAST => StateNames::BREWING_STAND_SLOT_A_BIT, + BrewingStandSlot::SOUTHWEST => StateNames::BREWING_STAND_SLOT_B_BIT, + BrewingStandSlot::NORTHWEST => StateNames::BREWING_STAND_SLOT_C_BIT + }, fn(BrewingStand $b) => $b->hasSlot($slot), fn(BrewingStand $b, bool $v) => $b->setSlot($slot, $v)), BrewingStandSlot::cases()))); + + //C + $reg->mapModel(Model::create(Blocks::CACTUS(), Ids::CACTUS)->properties([ + new IntProperty(StateNames::AGE, 0, 15, fn(Cactus $b) => $b->getAge(), fn(Cactus $b, int $v) => $b->setAge($v)) + ])); + $reg->mapModel(Model::create(Blocks::CAKE(), Ids::CAKE)->properties([ + new IntProperty(StateNames::BITE_COUNTER, 0, 6, fn(Cake $b) => $b->getBites(), fn(Cake $b, int $v) => $b->setBites($v)) + ])); + $reg->mapModel(Model::create(Blocks::CAMPFIRE(), Ids::CAMPFIRE)->properties($commonProperties->campfireProperties)); + $reg->mapModel(Model::create(Blocks::CARVED_PUMPKIN(), Ids::CARVED_PUMPKIN)->properties([ + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::CHAIN(), Ids::CHAIN)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::CHISELED_BOOKSHELF(), Ids::CHISELED_BOOKSHELF)->properties([ + $commonProperties->horizontalFacingSWNE, + new OptionSetFromIntProperty( + StateNames::BOOKS_STORED, + EnumFromRawStateMap::int(ChiseledBookshelfSlot::class, fn(ChiseledBookshelfSlot $case) => match($case){ + //these are (currently) the same as the internal values, but it's best not to rely on those in case Mojang mess with the flags + ChiseledBookshelfSlot::TOP_LEFT => 1 << 0, + ChiseledBookshelfSlot::TOP_MIDDLE => 1 << 1, + ChiseledBookshelfSlot::TOP_RIGHT => 1 << 2, + ChiseledBookshelfSlot::BOTTOM_LEFT => 1 << 3, + ChiseledBookshelfSlot::BOTTOM_MIDDLE => 1 << 4, + ChiseledBookshelfSlot::BOTTOM_RIGHT => 1 << 5 + }), + fn(ChiseledBookshelf $b) => $b->getSlots(), + fn(ChiseledBookshelf $b, array $v) => $b->setSlots($v) + ) + ])); + $reg->mapModel(Model::create(Blocks::CHISELED_QUARTZ(), Ids::CHISELED_QUARTZ_BLOCK)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::CHEST(), Ids::CHEST)->properties([$commonProperties->horizontalFacingCardinal])); + $reg->mapModel(Model::create(Blocks::CHORUS_FLOWER(), Ids::CHORUS_FLOWER)->properties([ + new IntProperty(StateNames::AGE, ChorusFlower::MIN_AGE, ChorusFlower::MAX_AGE, fn(ChorusFlower $b) => $b->getAge(), fn(ChorusFlower $b, int $v) => $b->setAge($v)) + ])); + $reg->mapModel(Model::create(Blocks::COCOA_POD(), Ids::COCOA)->properties([ + new IntProperty(StateNames::AGE, 0, 2, fn(CocoaBlock $b) => $b->getAge(), fn(CocoaBlock $b, int $v) => $b->setAge($v)), + $commonProperties->horizontalFacingSWNEInverted + ])); + + //D + $reg->mapModel(Model::create(Blocks::DEEPSLATE(), Ids::DEEPSLATE)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::DETECTOR_RAIL(), Ids::DETECTOR_RAIL)->properties([ + new BoolProperty(StateNames::RAIL_DATA_BIT, fn(DetectorRail $b) => $b->isActivated(), fn(DetectorRail $b, bool $v) => $b->setActivated($v)), + new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail + ])); + + //E + $reg->mapModel(Model::create(Blocks::ENDER_CHEST(), Ids::ENDER_CHEST)->properties([$commonProperties->horizontalFacingCardinal])); + $reg->mapModel(Model::create(Blocks::END_PORTAL_FRAME(), Ids::END_PORTAL_FRAME)->properties([ + new BoolProperty(StateNames::END_PORTAL_EYE_BIT, fn(EndPortalFrame $b) => $b->hasEye(), fn(EndPortalFrame $b, bool $v) => $b->setEye($v)), + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::END_ROD(), Ids::END_ROD)->properties([ + new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingEndRod, fn(EndRod $b) => $b->getFacing(), fn(EndRod $b, int $v) => $b->setFacing($v)), + ])); + + //F + $reg->mapModel(Model::create(Blocks::FARMLAND(), Ids::FARMLAND)->properties([ + new IntProperty(StateNames::MOISTURIZED_AMOUNT, 0, 7, fn(Farmland $b) => $b->getWetness(), fn(Farmland $b, int $v) => $b->setWetness($v)) + ])); + $reg->mapModel(Model::create(Blocks::FIRE(), Ids::FIRE)->properties([ + new IntProperty(StateNames::AGE, 0, 15, fn(Fire $b) => $b->getAge(), fn(Fire $b, int $v) => $b->setAge($v)) + ])); + $reg->mapModel(Model::create(Blocks::FLOWER_POT(), Ids::FLOWER_POT)->properties([ + BoolProperty::unused(StateNames::UPDATE_BIT, false) + ])); + $reg->mapModel(Model::create(Blocks::FROSTED_ICE(), Ids::FROSTED_ICE)->properties([ + new IntProperty(StateNames::AGE, 0, 3, fn(FrostedIce $b) => $b->getAge(), fn(FrostedIce $b, int $v) => $b->setAge($v)) + ])); + + //G + $reg->mapModel(Model::create(Blocks::GLOWING_ITEM_FRAME(), Ids::GLOW_FRAME)->properties($commonProperties->itemFrameProperties)); + + //H + $reg->mapModel(Model::create(Blocks::HAY_BALE(), Ids::HAY_BLOCK)->properties([ + IntProperty::unused(StateNames::DEPRECATED, 0), + $commonProperties->pillarAxis + ])); + $reg->mapModel(Model::create(Blocks::HOPPER(), Ids::HOPPER)->properties([ + //kinda weird this doesn't use powered_bit? + new BoolProperty(StateNames::TOGGLE_BIT, fn(PoweredByRedstone $b) => $b->isPowered(), fn(PoweredByRedstone $b, bool $v) => $b->setPowered($v)), + new ValueFromIntProperty(StateNames::FACING_DIRECTION, ValueMappings::getInstance()->facingExceptUp, fn(Hopper $b) => $b->getFacing(), fn(Hopper $b, int $v) => $b->setFacing($v)), + ])); + + //I + $reg->mapModel(Model::create(Blocks::IRON_DOOR(), Ids::IRON_DOOR)->properties($commonProperties->doorProperties)); + $reg->mapModel(Model::create(Blocks::IRON_TRAPDOOR(), Ids::IRON_TRAPDOOR)->properties($commonProperties->trapdoorProperties)); + $reg->mapModel(Model::create(Blocks::ITEM_FRAME(), Ids::FRAME)->properties($commonProperties->itemFrameProperties)); + + //L + $reg->mapModel(Model::create(Blocks::LADDER(), Ids::LADDER)->properties([$commonProperties->horizontalFacingClassic])); + $reg->mapModel(Model::create(Blocks::LANTERN(), Ids::LANTERN)->properties([ + new BoolProperty(StateNames::HANGING, fn(Lantern $b) => $b->isHanging(), fn(Lantern $b, bool $v) => $b->setHanging($v)) + ])); + $reg->mapModel(Model::create(Blocks::LECTERN(), Ids::LECTERN)->properties([ + new BoolProperty(StateNames::POWERED_BIT, fn(Lectern $b) => $b->isProducingSignal(), fn(Lectern $b, bool $v) => $b->setProducingSignal($v)), + $commonProperties->horizontalFacingCardinal, + ])); + $reg->mapModel(Model::create(Blocks::LEVER(), Ids::LEVER)->properties([ + new ValueFromStringProperty(StateNames::LEVER_DIRECTION, ValueMappings::getInstance()->leverFacing, fn(Lever $b) => $b->getFacing(), fn(Lever $b, LeverFacing $v) => $b->setFacing($v)), + new BoolProperty(StateNames::OPEN_BIT, fn(Lever $b) => $b->isActivated(), fn(Lever $b, bool $v) => $b->setActivated($v)), + ])); + $reg->mapModel(Model::create(Blocks::LIGHTNING_ROD(), Ids::LIGHTNING_ROD)->properties([$commonProperties->anyFacingClassic])); + $reg->mapModel(Model::create(Blocks::LIT_PUMPKIN(), Ids::LIT_PUMPKIN)->properties([$commonProperties->horizontalFacingCardinal])); + $reg->mapModel(Model::create(Blocks::LOOM(), Ids::LOOM)->properties([$commonProperties->horizontalFacingSWNE])); + + //M + $reg->mapModel(Model::create(Blocks::MUDDY_MANGROVE_ROOTS(), Ids::MUDDY_MANGROVE_ROOTS)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::NETHER_WART(), Ids::NETHER_WART)->properties([ + new IntProperty(StateNames::AGE, 0, 3, fn(NetherWartPlant $b) => $b->getAge(), fn(NetherWartPlant $b, int $v) => $b->setAge($v)) + ])); + $reg->mapModel(Model::create(Blocks::NETHER_PORTAL(), Ids::PORTAL)->properties([ + new ValueFromStringProperty(StateNames::PORTAL_AXIS, ValueMappings::getInstance()->portalAxis, fn(NetherPortal $b) => $b->getAxis(), fn(NetherPortal $b, int $v) => $b->setAxis($v)) + ])); + + //P + $reg->mapModel(Model::create(Blocks::PINK_PETALS(), Ids::PINK_PETALS)->properties([ + //Pink petals only uses 0-3, but GROWTH state can go up to 7 + new IntProperty(StateNames::GROWTH, 0, 7, fn(PinkPetals $b) => $b->getCount(), fn(PinkPetals $b, int $v) => $b->setCount(min($v, PinkPetals::MAX_COUNT)), offset: 1), + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::POWERED_RAIL(), Ids::GOLDEN_RAIL)->properties([ + new BoolProperty(StateNames::RAIL_DATA_BIT, fn(PoweredRail $b) => $b->isPowered(), fn(PoweredRail $b, bool $v) => $b->setPowered($v)), //TODO: shared with ActivatorRail + new IntProperty(StateNames::RAIL_DIRECTION, 0, 5, fn(StraightOnlyRail $b) => $b->getShape(), fn(StraightOnlyRail $b, int $v) => $b->setShape($v)) //TODO: shared with ActivatorRail + ])); + $reg->mapModel(Model::create(Blocks::PITCHER_PLANT(), Ids::PITCHER_PLANT)->properties([ + new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePlant $b) => $b->isTop(), fn(DoublePlant $b, bool $v) => $b->setTop($v)), //TODO: don't we have helpers for this? + ])); + $reg->mapModel(Model::create(Blocks::POLISHED_BASALT(), Ids::POLISHED_BASALT)->properties([$commonProperties->pillarAxis])); + $reg->mapModel(Model::create(Blocks::POLISHED_BLACKSTONE_BUTTON(), Ids::POLISHED_BLACKSTONE_BUTTON)->properties($commonProperties->buttonProperties)); + $reg->mapModel(Model::create(Blocks::POLISHED_BLACKSTONE_PRESSURE_PLATE(), Ids::POLISHED_BLACKSTONE_PRESSURE_PLATE)->properties($commonProperties->simplePressurePlateProperties)); + $reg->mapModel(Model::create(Blocks::PUMPKIN(), Ids::PUMPKIN)->properties([ + //not used, has no visible effect + $commonProperties->dummyCardinalDirection + ])); + $reg->mapModel(Model::create(Blocks::PURPUR(), Ids::PURPUR_BLOCK)->properties([ + $commonProperties->dummyPillarAxis + ])); + $reg->mapModel(Model::create(Blocks::PURPUR_PILLAR(), Ids::PURPUR_PILLAR)->properties([$commonProperties->pillarAxis])); + + //Q + $reg->mapModel(Model::create(Blocks::QUARTZ(), Ids::QUARTZ_BLOCK)->properties([ + $commonProperties->dummyPillarAxis + ])); + $reg->mapModel(Model::create(Blocks::QUARTZ_PILLAR(), Ids::QUARTZ_PILLAR)->properties([$commonProperties->pillarAxis])); + + //R + $reg->mapModel(Model::create(Blocks::RAIL(), Ids::RAIL)->properties([ + new IntProperty(StateNames::RAIL_DIRECTION, 0, 9, fn(Rail $b) => $b->getShape(), fn(Rail $b, int $v) => $b->setShape($v)) + ])); + $reg->mapModel(Model::create(Blocks::REDSTONE_WIRE(), Ids::REDSTONE_WIRE)->properties([$commonProperties->analogRedstoneSignal])); + $reg->mapModel(Model::create(Blocks::RESPAWN_ANCHOR(), Ids::RESPAWN_ANCHOR)->properties([ + new IntProperty(StateNames::RESPAWN_ANCHOR_CHARGE, 0, 4, fn(RespawnAnchor $b) => $b->getCharges(), fn(RespawnAnchor $b, int $v) => $b->setCharges($v)) + ])); + + //S + $reg->mapModel(Model::create(Blocks::SEA_PICKLE(), Ids::SEA_PICKLE)->properties([ + new IntProperty(StateNames::CLUSTER_COUNT, 0, 3, fn(SeaPickle $b) => $b->getCount(), fn(SeaPickle $b, int $v) => $b->setCount($v), offset: 1), + new BoolProperty(StateNames::DEAD_BIT, fn(SeaPickle $b) => $b->isUnderwater(), fn(SeaPickle $b, bool $v) => $b->setUnderwater($v), inverted: true) + ])); + $reg->mapModel(Model::create(Blocks::SMALL_DRIPLEAF(), Ids::SMALL_DRIPLEAF_BLOCK)->properties([ + new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(SmallDripleaf $b) => $b->isTop(), fn(SmallDripleaf $b, bool $v) => $b->setTop($v)), + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::SMOOTH_QUARTZ(), Ids::SMOOTH_QUARTZ)->properties([ + $commonProperties->dummyPillarAxis + ])); + $reg->mapModel(Model::create(Blocks::SNOW_LAYER(), Ids::SNOW_LAYER)->properties([ + new DummyProperty(StateNames::COVERED_BIT, false), + new IntProperty(StateNames::HEIGHT, 0, 7, fn(SnowLayer $b) => $b->getLayers(), fn(SnowLayer $b, int $v) => $b->setLayers($v), offset: 1) + ])); + $reg->mapModel(Model::create(Blocks::SOUL_CAMPFIRE(), Ids::SOUL_CAMPFIRE)->properties($commonProperties->campfireProperties)); + $reg->mapModel(Model::create(Blocks::SOUL_FIRE(), Ids::SOUL_FIRE)->properties([ + new DummyProperty(StateNames::AGE, 0) //this is useless for soul fire, since it doesn't have the logic associated + ])); + $reg->mapModel(Model::create(Blocks::SOUL_LANTERN(), Ids::SOUL_LANTERN)->properties([ + new BoolProperty(StateNames::HANGING, fn(Lantern $b) => $b->isHanging(), fn(Lantern $b, bool $v) => $b->setHanging($v)) //TODO: repeated + ])); + $reg->mapModel(Model::create(Blocks::STONE_BUTTON(), Ids::STONE_BUTTON)->properties($commonProperties->buttonProperties)); + $reg->mapModel(Model::create(Blocks::STONE_PRESSURE_PLATE(), Ids::STONE_PRESSURE_PLATE)->properties($commonProperties->simplePressurePlateProperties)); + $reg->mapModel(Model::create(Blocks::STONECUTTER(), Ids::STONECUTTER_BLOCK)->properties([ + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::SUGARCANE(), Ids::REEDS)->properties([ + new IntProperty(StateNames::AGE, 0, 15, fn(Sugarcane $b) => $b->getAge(), fn(Sugarcane $b, int $v) => $b->setAge($v)) + ])); + + //T + $reg->mapModel(Model::create(Blocks::TRAPPED_CHEST(), Ids::TRAPPED_CHEST)->properties([ + $commonProperties->horizontalFacingCardinal + ])); + $reg->mapModel(Model::create(Blocks::TRIPWIRE(), Ids::TRIP_WIRE)->properties([ + new BoolProperty(StateNames::ATTACHED_BIT, fn(Tripwire $b) => $b->isConnected(), fn(Tripwire $b, bool $v) => $b->setConnected($v)), + new BoolProperty(StateNames::DISARMED_BIT, fn(Tripwire $b) => $b->isDisarmed(), fn(Tripwire $b, bool $v) => $b->setDisarmed($v)), + new BoolProperty(StateNames::SUSPENDED_BIT, fn(Tripwire $b) => $b->isSuspended(), fn(Tripwire $b, bool $v) => $b->setSuspended($v)), + new BoolProperty(StateNames::POWERED_BIT, fn(Tripwire $b) => $b->isTriggered(), fn(Tripwire $b, bool $v) => $b->setTriggered($v)), + ])); + $reg->mapModel(Model::create(Blocks::TRIPWIRE_HOOK(), Ids::TRIPWIRE_HOOK)->properties([ + new BoolProperty(StateNames::ATTACHED_BIT, fn(TripwireHook $b) => $b->isConnected(), fn(TripwireHook $b, bool $v) => $b->setConnected($v)), + new BoolProperty(StateNames::POWERED_BIT, fn(TripwireHook $b) => $b->isPowered(), fn(TripwireHook $b, bool $v) => $b->setPowered($v)), + $commonProperties->horizontalFacingSWNE + ])); + + $reg->mapModel(Model::create(Blocks::TWISTING_VINES(), Ids::TWISTING_VINES)->properties([ + new IntProperty(StateNames::TWISTING_VINES_AGE, 0, 25, fn(NetherVines $b) => $b->getAge(), fn(NetherVines $b, int $v) => $b->setAge($v)) + ])); + + //W + $reg->mapModel(Model::create(Blocks::WALL_BANNER(), Ids::WALL_BANNER)->properties([$commonProperties->horizontalFacingClassic])); + $reg->mapModel(Model::create(Blocks::WEEPING_VINES(), Ids::WEEPING_VINES)->properties([ + new IntProperty(StateNames::WEEPING_VINES_AGE, 0, 25, fn(NetherVines $b) => $b->getAge(), fn(NetherVines $b, int $v) => $b->setAge($v)) + ])); + $reg->mapModel(Model::create(Blocks::WEIGHTED_PRESSURE_PLATE_HEAVY(), Ids::HEAVY_WEIGHTED_PRESSURE_PLATE)->properties([$commonProperties->analogRedstoneSignal])); + $reg->mapModel(Model::create(Blocks::WEIGHTED_PRESSURE_PLATE_LIGHT(), Ids::LIGHT_WEIGHTED_PRESSURE_PLATE)->properties([$commonProperties->analogRedstoneSignal])); + } + + /** + * @phpstan-template TBlock of Block + * @phpstan-param Model $model + */ + private static function mapAsymmetricSerializer(BlockSerializerDeserializerRegistrar $reg, Model $model) : void{ + $id = $model->getId(); + $properties = $model->getProperties(); + $reg->serializer->map($model->getBlock(), function(Block $block) use ($id, $properties) : Writer{ + $writer = new Writer($id); + foreach($properties as $property){ + $property->serialize($block, $writer); + } + return $writer; + }); + } + + /** + * @phpstan-template TBlock of Block + * @phpstan-param Model $model + * @phpstan-return TBlock + */ + private static function deserializeAsymmetric(Model $model, Reader $in) : Block{ + $block = clone $model->getBlock(); + foreach($model->getProperties() as $property){ + $property->deserialize($block, $in); + } + return $block; + } + + /** + * All mappings that still use the split form of serializer/deserializer registration + * This is typically only used by blocks with one ID but multiple PM types (split by property) + * These currently can't be registered in a unified way, and due to their small number it may not be worth the + * effort to implement a unified way to deal with them + */ + private static function registerSplitMappings(BlockSerializerDeserializerRegistrar $reg, CommonProperties $commonProperties) : void{ + //big dripleaf - split into head / stem variants, as stems don't have tilt or leaf state + $bigDripleafHeadModel = Model::create(Blocks::BIG_DRIPLEAF_HEAD(), Ids::BIG_DRIPLEAF)->properties([ + $commonProperties->horizontalFacingCardinal, + new ValueFromStringProperty(StateNames::BIG_DRIPLEAF_TILT, ValueMappings::getInstance()->dripleafState, fn(BigDripleafHead $b) => $b->getLeafState(), fn(BigDripleafHead $b, DripleafState $v) => $b->setLeafState($v)), + new DummyProperty(StateNames::BIG_DRIPLEAF_HEAD, true) + ]); + $bigDripleafStemModel = Model::create(Blocks::BIG_DRIPLEAF_STEM(), Ids::BIG_DRIPLEAF)->properties([ + $commonProperties->horizontalFacingCardinal, + new DummyProperty(StateNames::BIG_DRIPLEAF_TILT, StringValues::BIG_DRIPLEAF_TILT_NONE), + new DummyProperty(StateNames::BIG_DRIPLEAF_HEAD, false) + ]); + self::mapAsymmetricSerializer($reg, $bigDripleafHeadModel); + self::mapAsymmetricSerializer($reg, $bigDripleafStemModel); + $reg->deserializer->map(Ids::BIG_DRIPLEAF, fn(Reader $in) => $in->readBool(StateNames::BIG_DRIPLEAF_HEAD) ? + self::deserializeAsymmetric($bigDripleafHeadModel, $in) : + self::deserializeAsymmetric($bigDripleafStemModel, $in) + ); + + $fillLevelProperty = new IntProperty(StateNames::FILL_LEVEL, 1, 6, fn(FillableCauldron $b) => $b->getFillLevel(), fn(FillableCauldron $b, int $v) => $b->setFillLevel($v)); + + //this pretends to be a water cauldron on disk and stores its real information in the block actor data, therefore only a serializer is needed + self::mapAsymmetricSerializer($reg, Model::create(Blocks::POTION_CAULDRON(), Ids::CAULDRON)->properties([$fillLevelProperty, new DummyProperty(StateNames::CAULDRON_LIQUID, StringValues::CAULDRON_LIQUID_WATER)])); + + $lavaCauldronModel = Model::create(Blocks::LAVA_CAULDRON(), Ids::CAULDRON)->properties([ + $fillLevelProperty, + new DummyProperty(StateNames::CAULDRON_LIQUID, StringValues::CAULDRON_LIQUID_LAVA) + ]); + $waterCauldronModel = Model::create(Blocks::WATER_CAULDRON(), Ids::CAULDRON)->properties([ + $fillLevelProperty, + new DummyProperty(StateNames::CAULDRON_LIQUID, StringValues::CAULDRON_LIQUID_WATER) + ]); + $emptyCauldronModel = Model::create(Blocks::CAULDRON(), Ids::CAULDRON)->properties([ + new DummyProperty(StateNames::FILL_LEVEL, 0), + new DummyProperty(StateNames::CAULDRON_LIQUID, StringValues::CAULDRON_LIQUID_WATER) + ]); + self::mapAsymmetricSerializer($reg, $lavaCauldronModel); + self::mapAsymmetricSerializer($reg, $waterCauldronModel); + self::mapAsymmetricSerializer($reg, $emptyCauldronModel); + $reg->deserializer->map(Ids::CAULDRON, fn(Reader $in) => $in->readInt(StateNames::FILL_LEVEL) === 0 ? + self::deserializeAsymmetric($emptyCauldronModel, $in) : + match ($liquid = $in->readString(StateNames::CAULDRON_LIQUID)) { + StringValues::CAULDRON_LIQUID_WATER => self::deserializeAsymmetric($waterCauldronModel, $in), + StringValues::CAULDRON_LIQUID_LAVA => self::deserializeAsymmetric($lavaCauldronModel, $in), + StringValues::CAULDRON_LIQUID_POWDER_SNOW => throw new UnsupportedBlockStateException("Powder snow is not supported yet"), + default => throw $in->badValueException(StateNames::CAULDRON_LIQUID, $liquid) + } + ); + + //mushroom stems, split for consistency with all-sided logs vs normal logs + $allSidedMushroomStemModel = Model::create(Blocks::ALL_SIDED_MUSHROOM_STEM(), Ids::MUSHROOM_STEM)->properties([new DummyProperty(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM)]); + $mushroomStemModel = Model::create(Blocks::MUSHROOM_STEM(), Ids::MUSHROOM_STEM)->properties([new DummyProperty(StateNames::HUGE_MUSHROOM_BITS, BlockLegacyMetadata::MUSHROOM_BLOCK_STEM)]); + self::mapAsymmetricSerializer($reg, $allSidedMushroomStemModel); + self::mapAsymmetricSerializer($reg, $mushroomStemModel); + $reg->deserializer->map(Ids::MUSHROOM_STEM, fn(Reader $in) : Block => match ($in->readInt(StateNames::HUGE_MUSHROOM_BITS)) { + BlockLegacyMetadata::MUSHROOM_BLOCK_ALL_STEM => self::deserializeAsymmetric($allSidedMushroomStemModel, $in), + BlockLegacyMetadata::MUSHROOM_BLOCK_STEM => self::deserializeAsymmetric($mushroomStemModel, $in), + default => throw new BlockStateDeserializeException("This state does not exist"), + }); + + //pitcher crop, split into single and double variants as double has different properties and behaviour + //this will probably be the most annoying to unify + $pitcherCropModel = Model::create(Blocks::PITCHER_CROP(), Ids::PITCHER_CROP)->properties([ + new IntProperty(StateNames::GROWTH, 0, PitcherCrop::MAX_AGE, fn(PitcherCrop $b) => $b->getAge(), fn(PitcherCrop $b, int $v) => $b->setAge($v)), + new DummyProperty(StateNames::UPPER_BLOCK_BIT, false) + ]); + $doublePitcherCropAgeOffset = PitcherCrop::MAX_AGE + 1; + $doublePitcherCropModel = Model::create(Blocks::DOUBLE_PITCHER_CROP(), Ids::PITCHER_CROP)->properties([ + new IntProperty( + StateNames::GROWTH, + $doublePitcherCropAgeOffset, //TODO: it would be a bit less awkward if the bounds applied _after_ applying the offset, instead of before + 7, + fn(DoublePitcherCrop $b) => $b->getAge(), + fn(DoublePitcherCrop $b, int $v) => $b->setAge(min($v, DoublePitcherCrop::MAX_AGE)), //state may give up to 7, but only up to 4 is valid + offset: -$doublePitcherCropAgeOffset + ), + new BoolProperty(StateNames::UPPER_BLOCK_BIT, fn(DoublePitcherCrop $b) => $b->isTop(), fn(DoublePitcherCrop $b, bool $v) => $b->setTop($v)) + ]); + self::mapAsymmetricSerializer($reg, $pitcherCropModel); + self::mapAsymmetricSerializer($reg, $doublePitcherCropModel); + $reg->deserializer->map(Ids::PITCHER_CROP, fn(Reader $in) => $in->readInt(StateNames::GROWTH) <= PitcherCrop::MAX_AGE ? + ($in->readBool(StateNames::UPPER_BLOCK_BIT) ? + //top pitcher crop with age 0-2 is an invalid state, only the bottom half should exist in this case + Blocks::AIR() : + self::deserializeAsymmetric($pitcherCropModel, $in) + ) : self::deserializeAsymmetric($doublePitcherCropModel, $in) + ); + + //these only exist within PM (mapped from tile properties) as they don't support the same properties as a + //normal banner, therefore no deserializer is needed + self::mapAsymmetricSerializer($reg, Model::create(Blocks::OMINOUS_BANNER(), Ids::STANDING_BANNER)->properties([$commonProperties->floorSignLikeRotation])); + self::mapAsymmetricSerializer($reg, Model::create(Blocks::OMINOUS_WALL_BANNER(), Ids::WALL_BANNER)->properties([$commonProperties->horizontalFacingClassic])); + + foreach([ + Ids::ACACIA_HANGING_SIGN => [Blocks::ACACIA_CEILING_CENTER_HANGING_SIGN(), Blocks::ACACIA_CEILING_EDGES_HANGING_SIGN(), Blocks::ACACIA_WALL_HANGING_SIGN()], + Ids::BIRCH_HANGING_SIGN => [Blocks::BIRCH_CEILING_CENTER_HANGING_SIGN(), Blocks::BIRCH_CEILING_EDGES_HANGING_SIGN(), Blocks::BIRCH_WALL_HANGING_SIGN()], + Ids::CHERRY_HANGING_SIGN => [Blocks::CHERRY_CEILING_CENTER_HANGING_SIGN(), Blocks::CHERRY_CEILING_EDGES_HANGING_SIGN(), Blocks::CHERRY_WALL_HANGING_SIGN()], + Ids::CRIMSON_HANGING_SIGN => [Blocks::CRIMSON_CEILING_CENTER_HANGING_SIGN(), Blocks::CRIMSON_CEILING_EDGES_HANGING_SIGN(), Blocks::CRIMSON_WALL_HANGING_SIGN()], + Ids::DARK_OAK_HANGING_SIGN => [Blocks::DARK_OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::DARK_OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::DARK_OAK_WALL_HANGING_SIGN()], + Ids::JUNGLE_HANGING_SIGN => [Blocks::JUNGLE_CEILING_CENTER_HANGING_SIGN(), Blocks::JUNGLE_CEILING_EDGES_HANGING_SIGN(), Blocks::JUNGLE_WALL_HANGING_SIGN()], + Ids::MANGROVE_HANGING_SIGN => [Blocks::MANGROVE_CEILING_CENTER_HANGING_SIGN(), Blocks::MANGROVE_CEILING_EDGES_HANGING_SIGN(), Blocks::MANGROVE_WALL_HANGING_SIGN()], + Ids::OAK_HANGING_SIGN => [Blocks::OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::OAK_WALL_HANGING_SIGN()], + Ids::PALE_OAK_HANGING_SIGN => [Blocks::PALE_OAK_CEILING_CENTER_HANGING_SIGN(), Blocks::PALE_OAK_CEILING_EDGES_HANGING_SIGN(), Blocks::PALE_OAK_WALL_HANGING_SIGN()], + Ids::SPRUCE_HANGING_SIGN => [Blocks::SPRUCE_CEILING_CENTER_HANGING_SIGN(), Blocks::SPRUCE_CEILING_EDGES_HANGING_SIGN(), Blocks::SPRUCE_WALL_HANGING_SIGN()], + Ids::WARPED_HANGING_SIGN => [Blocks::WARPED_CEILING_CENTER_HANGING_SIGN(), Blocks::WARPED_CEILING_EDGES_HANGING_SIGN(), Blocks::WARPED_WALL_HANGING_SIGN()], + ] as $id => [$center, $edges, $wall]){ + //attached_bit - true for ceiling center signs, false for ceiling edges signs and wall signs + //hanging - true for all ceiling signs, false for wall signs + //facing_direction - used for ceiling edges signs and wall signs + //ground_sign_direction - used by ceiling center signs only + $centerModel = Model::create($center, $id)->properties([ + $commonProperties->floorSignLikeRotation, + new DummyProperty(StateNames::ATTACHED_BIT, true), + new DummyProperty(StateNames::HANGING, true), + new DummyProperty(StateNames::FACING_DIRECTION, 2) + ]); + $edgesModel = Model::create($edges, $id)->properties([ + new DummyProperty(StateNames::GROUND_SIGN_DIRECTION, 0), + new DummyProperty(StateNames::ATTACHED_BIT, false), + new DummyProperty(StateNames::HANGING, true), + $commonProperties->horizontalFacingClassic, + ]); + $wallModel = Model::create($wall, $id)->properties([ + new DummyProperty(StateNames::GROUND_SIGN_DIRECTION, 0), + new DummyProperty(StateNames::ATTACHED_BIT, false), + new DummyProperty(StateNames::HANGING, false), + $commonProperties->horizontalFacingClassic + ]); + self::mapAsymmetricSerializer($reg, $centerModel); + self::mapAsymmetricSerializer($reg, $edgesModel); + self::mapAsymmetricSerializer($reg, $wallModel); + $reg->deserializer->map($id, fn(Reader $in) => $in->readBool(StateNames::HANGING) ? + ($in->readBool(StateNames::ATTACHED_BIT) ? + self::deserializeAsymmetric($centerModel, $in) : + self::deserializeAsymmetric($edgesModel, $in) + ) : + self::deserializeAsymmetric($wallModel, $in)); + } + } +} diff --git a/src/data/bedrock/block/convert/property/BoolFromStringProperty.php b/src/data/bedrock/block/convert/property/BoolFromStringProperty.php new file mode 100644 index 000000000..89c64188d --- /dev/null +++ b/src/data/bedrock/block/convert/property/BoolFromStringProperty.php @@ -0,0 +1,78 @@ + + */ +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; + } +} diff --git a/src/data/bedrock/block/convert/property/BoolProperty.php b/src/data/bedrock/block/convert/property/BoolProperty.php new file mode 100644 index 000000000..299ec4076 --- /dev/null +++ b/src/data/bedrock/block/convert/property/BoolProperty.php @@ -0,0 +1,71 @@ + + */ +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 + */ + 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); + } +} diff --git a/src/data/bedrock/block/convert/property/CommonProperties.php b/src/data/bedrock/block/convert/property/CommonProperties.php new file mode 100644 index 000000000..1a3224270 --- /dev/null +++ b/src/data/bedrock/block/convert/property/CommonProperties.php @@ -0,0 +1,428 @@ + */ + public readonly ValueFromStringProperty $blockFace; + /** @phpstan-var ValueFromStringProperty */ + public readonly ValueFromStringProperty $pillarAxis; + /** @phpstan-var ValueFromStringProperty */ + public readonly ValueFromStringProperty $torchFacing; + + /** @phpstan-var ValueFromStringProperty */ + public readonly ValueFromStringProperty $horizontalFacingCardinal; + /** @phpstan-var ValueFromIntProperty */ + public readonly ValueFromIntProperty $horizontalFacingSWNE; + /** @phpstan-var ValueFromIntProperty */ + public readonly ValueFromIntProperty $horizontalFacingSWNEInverted; + /** @phpstan-var ValueFromIntProperty */ + public readonly ValueFromIntProperty $horizontalFacingClassic; + + /** @phpstan-var ValueFromIntProperty */ + public readonly ValueFromIntProperty $anyFacingClassic; + + /** @phpstan-var OptionSetFromIntProperty */ + public readonly OptionSetFromIntProperty $multiFacingFlags; + + /** @phpstan-var IntProperty */ + public readonly IntProperty $floorSignLikeRotation; + + /** @phpstan-var IntProperty */ + public readonly IntProperty $analogRedstoneSignal; + + /** @phpstan-var IntProperty */ + public readonly IntProperty $cropAgeMax7; + /** @phpstan-var BoolProperty */ + public readonly BoolProperty $doublePlantHalf; + + /** @phpstan-var IntProperty */ + public readonly IntProperty $liquidData; + + /** @phpstan-var BoolProperty */ + public readonly BoolProperty $lit; + + public readonly DummyProperty $dummyCardinalDirection; + public readonly DummyProperty $dummyPillarAxis; + + /** @phpstan-var ValueFromStringProperty */ + public readonly ValueFromStringProperty $dyeColorIdInfix; + + /** @phpstan-var BoolFromStringProperty */ + public readonly BoolFromStringProperty $litIdInfix; + + /** @phpstan-var BoolFromStringProperty */ + public readonly BoolFromStringProperty $slabIdInfix; + /** @phpstan-var BoolFromStringProperty */ + public readonly BoolFromStringProperty $slabPositionProperty; + + /** + * @var StringProperty[] + * @phpstan-var non-empty-list> + */ + public readonly array $coralIdPrefixes; + /** + * @var StringProperty[] + * @phpstan-var non-empty-list> + */ + public readonly array $copperIdPrefixes; + + /** + * @var StringProperty[] + * @phpstan-var non-empty-list> + */ + public readonly array $furnaceIdPrefixes; + + /** + * @var StringProperty[]|string[] + * @phpstan-var non-empty-list> + */ + public readonly array $liquidIdPrefixes; + + /** + * @var StringProperty[] + * @phpstan-var non-empty-list> + */ + public readonly array $woodIdPrefixes; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $buttonProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $campfireProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $doorProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $fenceGateProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $itemFrameProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $simplePressurePlateProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $stairProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $stemProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + public readonly array $trapdoorProperties; + + /** + * @var Property[] + * @phpstan-var non-empty-list> + */ + 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; + } +} diff --git a/src/data/bedrock/block/convert/property/DummyProperty.php b/src/data/bedrock/block/convert/property/DummyProperty.php new file mode 100644 index 000000000..a9d32b417 --- /dev/null +++ b/src/data/bedrock/block/convert/property/DummyProperty.php @@ -0,0 +1,61 @@ + + */ +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(); + } + } +} diff --git a/src/data/bedrock/block/convert/property/EnumFromRawStateMap.php b/src/data/bedrock/block/convert/property/EnumFromRawStateMap.php new file mode 100644 index 000000000..c6f4d0516 --- /dev/null +++ b/src/data/bedrock/block/convert/property/EnumFromRawStateMap.php @@ -0,0 +1,109 @@ + + */ +class EnumFromRawStateMap implements StateMap{ + /** + * @var int[] + * @phpstan-var array + */ + private array $enumToValue = []; + + /** + * @var \UnitEnum[] + * @phpstan-var array + */ + private array $valueToEnum = []; + + /** + * @phpstan-param class-string $class + * @phpstan-param \Closure(TEnum) : TRaw $mapper + * @phpstan-param ?\Closure(TEnum) : list $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 $class + * @param \Closure(TEnum_) : string $mapper + * @param ?\Closure(TEnum_) : list $aliasMapper + * + * @phpstan-return EnumFromRawStateMap + */ + 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 $class + * @param \Closure(TEnum_) : int $mapper + * @param ?\Closure(TEnum_) : list $aliasMapper + * + * @phpstan-return EnumFromRawStateMap + */ + 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; + } +} diff --git a/src/data/bedrock/block/convert/property/FlattenedCaveVinesVariant.php b/src/data/bedrock/block/convert/property/FlattenedCaveVinesVariant.php new file mode 100644 index 000000000..979fc4751 --- /dev/null +++ b/src/data/bedrock/block/convert/property/FlattenedCaveVinesVariant.php @@ -0,0 +1,35 @@ + + */ +class IntFromRawStateMap implements StateMap{ + + /** + * @var int[] + * @phpstan-var array + */ + 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 $serializeMap + * @phpstan-param array> $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 $serializeMap + * @phpstan-param array> $deserializeAliases + * + * @phpstan-return self + */ + public static function int(array $serializeMap, array $deserializeAliases = []) : self{ return new self($serializeMap, $deserializeAliases); } + + /** + * @param string[] $serializeMap + * @param (string|string[]) $deserializeAliases + * + * @phpstan-param array $serializeMap + * @phpstan-param array> $deserializeAliases + * + * @phpstan-return self + */ + 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"; + } +} diff --git a/src/data/bedrock/block/convert/property/IntProperty.php b/src/data/bedrock/block/convert/property/IntProperty.php new file mode 100644 index 000000000..bab865522 --- /dev/null +++ b/src/data/bedrock/block/convert/property/IntProperty.php @@ -0,0 +1,70 @@ + + */ +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 + */ + 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); + } +} diff --git a/src/data/bedrock/block/convert/property/OptionSetFromIntProperty.php b/src/data/bedrock/block/convert/property/OptionSetFromIntProperty.php new file mode 100644 index 000000000..a91c681b8 --- /dev/null +++ b/src/data/bedrock/block/convert/property/OptionSetFromIntProperty.php @@ -0,0 +1,93 @@ + + */ +class OptionSetFromIntProperty implements Property{ + + private int $maxValue = 0; + + /** + * @phpstan-param StateMap $map + * @phpstan-param \Closure(TBlock) : array $getter + * @phpstan-param \Closure(TBlock, array) : 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); + } +} diff --git a/src/data/bedrock/block/convert/property/Property.php b/src/data/bedrock/block/convert/property/Property.php new file mode 100644 index 000000000..30868dcd1 --- /dev/null +++ b/src/data/bedrock/block/convert/property/Property.php @@ -0,0 +1,44 @@ + + */ + 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; +} diff --git a/src/data/bedrock/block/convert/property/StringProperty.php b/src/data/bedrock/block/convert/property/StringProperty.php new file mode 100644 index 000000000..14ef1beff --- /dev/null +++ b/src/data/bedrock/block/convert/property/StringProperty.php @@ -0,0 +1,50 @@ + + */ +interface StringProperty extends Property{ + /** + * @return string[] + * @phpstan-return list + */ + 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; +} diff --git a/src/data/bedrock/block/convert/property/ValueFromIntProperty.php b/src/data/bedrock/block/convert/property/ValueFromIntProperty.php new file mode 100644 index 000000000..46b721255 --- /dev/null +++ b/src/data/bedrock/block/convert/property/ValueFromIntProperty.php @@ -0,0 +1,75 @@ + + */ +final class ValueFromIntProperty implements Property{ + + /** + * @phpstan-param StateMap $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 + */ + 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); + } +} diff --git a/src/data/bedrock/block/convert/property/ValueFromStringProperty.php b/src/data/bedrock/block/convert/property/ValueFromStringProperty.php new file mode 100644 index 000000000..b33634ae9 --- /dev/null +++ b/src/data/bedrock/block/convert/property/ValueFromStringProperty.php @@ -0,0 +1,81 @@ + + */ +final class ValueFromStringProperty implements StringProperty{ + + /** + * @phpstan-param StateMap $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 + */ + 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); + } +} diff --git a/src/data/bedrock/block/convert/property/ValueMappings.php b/src/data/bedrock/block/convert/property/ValueMappings.php new file mode 100644 index 000000000..22e9803a5 --- /dev/null +++ b/src/data/bedrock/block/convert/property/ValueMappings.php @@ -0,0 +1,305 @@ + */ + public readonly EnumFromRawStateMap $dyeColor; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $dyeColorWithSilver; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $mobHeadType; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $froglightType; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $dirtType; + + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $dripleafState; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $bellAttachmentType; + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $leverFacing; + + /** @phpstan-var EnumFromRawStateMap */ + public readonly EnumFromRawStateMap $mushroomBlockType; + + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $cardinalDirection; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $blockFace; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $pillarAxis; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $torchFacing; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $portalAxis; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $bambooLeafSize; + + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $horizontalFacing5Minus; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $horizontalFacingSWNE; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $horizontalFacingSWNEInverted; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $horizontalFacingCoral; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $horizontalFacingClassic; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $facing; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $facingEndRod; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $coralAxis; + + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $facingExceptDown; + /** @phpstan-var IntFromRawStateMap */ + public readonly IntFromRawStateMap $facingExceptUp; + /** @phpstan-var IntFromRawStateMap */ + 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] + ); + } +} diff --git a/src/data/bedrock/block/convert/property/WallConnectionTypeShim.php b/src/data/bedrock/block/convert/property/WallConnectionTypeShim.php new file mode 100644 index 000000000..bdd878b52 --- /dev/null +++ b/src/data/bedrock/block/convert/property/WallConnectionTypeShim.php @@ -0,0 +1,66 @@ + 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, + }; + } +} diff --git a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php index 771154d46..f5c03dbeb 100644 --- a/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php +++ b/src/data/bedrock/item/ItemSerializerDeserializerRegistrar.php @@ -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())); + }); } /** diff --git a/src/item/HangingSign.php b/src/item/HangingSign.php new file mode 100644 index 000000000..7143637ba --- /dev/null +++ b/src/item/HangingSign.php @@ -0,0 +1,65 @@ +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; + } +} diff --git a/src/item/Item.php b/src/item/Item.php index 8f8623c79..1ad22f1c9 100644 --- a/src/item/Item.php +++ b/src/item/Item.php @@ -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. */ diff --git a/src/item/ItemTypeIds.php b/src/item/ItemTypeIds.php index c63046c6b..af32cbcc2 100644 --- a/src/item/ItemTypeIds.php +++ b/src/item/ItemTypeIds.php @@ -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; diff --git a/src/item/StringToItemParser.php b/src/item/StringToItemParser.php index 7a90babed..2f316f66b 100644 --- a/src/item/StringToItemParser.php +++ b/src/item/StringToItemParser.php @@ -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()); diff --git a/src/item/VanillaItems.php b/src/item/VanillaItems.php index f76cf369f..e4eeffc1d 100644 --- a/src/item/VanillaItems.php +++ b/src/item/VanillaItems.php @@ -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")); diff --git a/src/world/World.php b/src/world/World.php index 56324c195..b3cb1d984 100644 --- a/src/world/World.php +++ b/src/world/World.php @@ -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){ diff --git a/src/world/format/io/GlobalBlockStateHandlers.php b/src/world/format/io/GlobalBlockStateHandlers.php index c1d3934cf..731b15f74 100644 --- a/src/world/format/io/GlobalBlockStateHandlers.php +++ b/src/world/format/io/GlobalBlockStateHandlers.php @@ -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{ diff --git a/tests/phpstan/configs/actual-problems.neon b/tests/phpstan/configs/actual-problems.neon index 2d609ae2c..06abe7fee 100644 --- a/tests/phpstan/configs/actual-problems.neon +++ b/tests/phpstan/configs/actual-problems.neon @@ -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\ 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\, array\ given\.$#' identifier: argument.type diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon index cb92bf968..e67f5768e 100644 --- a/tests/phpstan/configs/phpstan-bugs.neon +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -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 - diff --git a/tests/phpunit/block/block_factory_consistency_check.json b/tests/phpunit/block/block_factory_consistency_check.json index c7629656d..b96607c0b 100644 --- a/tests/phpunit/block/block_factory_consistency_check.json +++ b/tests/phpunit/block/block_factory_consistency_check.json @@ -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" } diff --git a/tests/phpunit/data/bedrock/block/convert/BlockSerializerDeserializerTest.php b/tests/phpunit/data/bedrock/block/convert/BlockSerializerDeserializerTest.php index a47a9b155..c0f850027 100644 --- a/tests/phpunit/data/bedrock/block/convert/BlockSerializerDeserializerTest.php +++ b/tests/phpunit/data/bedrock/block/convert/BlockSerializerDeserializerTest.php @@ -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; }