BlockStateSerializer can now serialize all currently implemented PM blocks

This commit is contained in:
Dylan K. Taylor 2022-02-01 05:21:16 +00:00
parent 40e46dbca2
commit f323e3c43f
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
5 changed files with 1346 additions and 3122 deletions

View File

@ -37,6 +37,7 @@ use pocketmine\data\bedrock\blockstate\BlockStateStringValues as StringValues;
use pocketmine\data\bedrock\blockstate\BlockTypeNames as Ids;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
use pocketmine\nbt\NbtException;
use pocketmine\nbt\tag\CompoundTag;
use function array_key_exists;
use function min;
@ -2499,10 +2500,21 @@ final class BlockStateDeserializer{
}
/** @throws BlockStateDeserializeException */
public function deserialize(string $id, CompoundTag $blockState) : Block{
public function deserialize(CompoundTag $blockState) : Block{
try{
$id = $blockState->getString("name");
$states = $blockState->getCompoundTag("states");
}catch(NbtException $e){
throw new BlockStateDeserializeException("Error reading blockstate NBT: " . $e->getMessage(), 0, $e);
}
if($states === null){
throw new BlockStateDeserializeException("\"states\" tag must always be present, even if it has no data");
}
if(!array_key_exists($id, $this->deserializeFuncs)){
throw new BlockStateDeserializeException("Unknown block ID \"$id\"");
}
return $this->deserializeFuncs[$id](new BlockStateReader($blockState));
return $this->deserializeFuncs[$id](new BlockStateReader($states));
}
}

View File

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace pocketmine\data\bedrock\blockstate;
use pocketmine\block\BlockLegacyMetadata;
use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DyeColor;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\data\bedrock\blockstate;
use pocketmine\block\Button;
use pocketmine\block\ChemistryTable;
use pocketmine\block\Crops;
use pocketmine\block\Door;
use pocketmine\block\DoublePlant;
use pocketmine\block\FenceGate;
use pocketmine\block\FloorSign;
use pocketmine\block\Furnace;
use pocketmine\block\GlazedTerracotta;
use pocketmine\block\Leaves;
use pocketmine\block\Liquid;
use pocketmine\block\Log;
use pocketmine\block\RedMushroomBlock;
use pocketmine\block\Sapling;
use pocketmine\block\SimplePressurePlate;
use pocketmine\block\Slab;
use pocketmine\block\Stair;
use pocketmine\block\Stem;
use pocketmine\block\Torch;
use pocketmine\block\Trapdoor;
use pocketmine\block\utils\SlabType;
use pocketmine\block\Wall;
use pocketmine\block\WallSign;
use pocketmine\block\Wood;
use pocketmine\data\bedrock\blockstate\BlockTypeNames as Ids;
use pocketmine\data\bedrock\MushroomBlockTypeIdMap;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
final class BlockStateSerializerHelper{
public static function encodeAllSidedLog(Wood $block) : BlockStateWriter{
return BlockStateWriter::create(Ids::WOOD)
->writeBool(BlockStateNames::STRIPPED_BIT, $block->isStripped())
->writePillarAxis(Axis::Y) //TODO: our implementation doesn't support this yet
->writeTreeType($block->getTreeType());
}
public static function encodeButton(Button $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeFacingDirection($block->getFacing())
->writeBool(BlockStateNames::BUTTON_PRESSED_BIT, $block->isPressed());
}
public static function encodeChemistryTable(ChemistryTable $block, string $chemistryTableType, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeString(BlockStateNames::CHEMISTRY_TABLE_TYPE, $chemistryTableType)
->writeLegacyHorizontalFacing($block->getFacing());
}
public static function encodeCrops(Crops $block, BlockStateWriter $out) : BlockStateWriter{
return $out->writeInt(BlockStateNames::GROWTH, $block->getAge());
}
public static function encodeColoredTorch(Torch $block, bool $highBit, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(BlockStateNames::COLOR_BIT, $highBit)
->writeTorchFacing($block->getFacing());
}
public static function encodeDoor(Door $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
->writeLegacyHorizontalFacing(Facing::rotateY($block->getFacing(), true))
->writeBool(BlockStateNames::DOOR_HINGE_BIT, $block->isHingeRight())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
public static function encodeDoublePlant(DoublePlant $block, string $doublePlantType, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(BlockStateNames::UPPER_BLOCK_BIT, $block->isTop())
->writeString(BlockStateNames::DOUBLE_PLANT_TYPE, $doublePlantType);
}
public static function encodeFenceGate(FenceGate $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeLegacyHorizontalFacing($block->getFacing())
->writeBool(BlockStateNames::IN_WALL_BIT, $block->isInWall())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
public static function encodeFloorSign(FloorSign $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeInt(BlockStateNames::GROUND_SIGN_DIRECTION, $block->getRotation());
}
public static function encodeFurnace(Furnace $block, string $unlitId, string $litId) : BlockStateWriter{
return BlockStateWriter::create($block->isLit() ? $litId : $unlitId)
->writeHorizontalFacing($block->getFacing());
}
public static function encodeGlazedTerracotta(GlazedTerracotta $block, BlockStateWriter $out) : BlockStateWriter{
return $out->writeHorizontalFacing($block->getFacing());
}
private static function encodeLeaves(Leaves $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(BlockStateNames::PERSISTENT_BIT, $block->isNoDecay())
->writeBool(BlockStateNames::UPDATE_BIT, $block->isCheckDecay());
}
public static function encodeLeaves1(Leaves $block, string $type) : BlockStateWriter{
return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES)
->writeString(BlockStateNames::OLD_LEAF_TYPE, $type));
}
public static function encodeLeaves2(Leaves $block, string $type) : BlockStateWriter{
return self::encodeLeaves($block, BlockStateWriter::create(Ids::LEAVES2)
->writeString(BlockStateNames::NEW_LEAF_TYPE, $type));
}
public static function encodeLiquid(Liquid $block, string $stillId, string $flowingId) : BlockStateWriter{
return BlockStateWriter::create($block->isStill() ? $stillId : $flowingId)
->writeInt(BlockStateNames::LIQUID_DEPTH, $block->getDecay() | ($block->isFalling() ? 0x8 : 0));
}
private static function encodeLog(Log $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writePillarAxis($block->getAxis());
}
public static function encodeLog1(Log $block, string $type) : BlockStateWriter{
return self::encodeLog($block, BlockStateWriter::create(Ids::LOG)
->writeString(BlockStateNames::OLD_LOG_TYPE, $type));
}
public static function encodeLog2(Log $block, string $type) : BlockStateWriter{
return self::encodeLog($block, BlockStateWriter::create(Ids::LOG2)
->writeString(BlockStateNames::NEW_LOG_TYPE, $type));
}
public static function encodeMushroomBlock(RedMushroomBlock $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeInt(BlockStateNames::HUGE_MUSHROOM_BITS, MushroomBlockTypeIdMap::getInstance()->toId($block->getMushroomBlockType()));
}
public static function encodeQuartz(string $type, int $axis) : BlockStateWriter{
return BlockStateWriter::create(Ids::QUARTZ_BLOCK)
->writeString(BlockStateNames::CHISEL_TYPE, $type)
->writePillarAxis($axis); //this isn't needed for all types, but we have to write it anyway
}
public static function encodeRedFlower(string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::RED_FLOWER)->writeString(BlockStateNames::FLOWER_TYPE, $type);
}
public static function encodeSandstone(string $id, string $type) : BlockStateWriter{
return BlockStateWriter::create($id)->writeString(BlockStateNames::SAND_STONE_TYPE, $type);
}
public static function encodeSapling(Sapling $block, string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::SAPLING)
->writeBool(BlockStateNames::AGE_BIT, $block->isReady())
->writeString(BlockStateNames::SAPLING_TYPE, $type);
}
public static function encodeSimplePressurePlate(SimplePressurePlate $block, BlockStateWriter $out) : BlockStateWriter{
//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...
return $out
->writeInt(BlockStateNames::REDSTONE_SIGNAL, $block->isPressed() ? 15 : 0);
}
private static function encodeSlab(Slab $block, string $singleId, string $doubleId) : BlockStateWriter{
$slabType = $block->getSlabType();
return BlockStateWriter::create($slabType->equals(SlabType::DOUBLE()) ? $doubleId : $singleId)
//this is (intentionally) also written for double slabs (as zero) to maintain bug parity with MCPE
->writeBool(BlockStateNames::TOP_SLOT_BIT, $slabType->equals(SlabType::TOP()));
}
public static function encodeStairs(Stair $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isUpsideDown())
->writeWeirdoHorizontalFacing($block->getFacing());
}
public static function encodeStem(Stem $block, BlockStateWriter $out) : BlockStateWriter{
return self::encodeCrops($block, $out)
->writeHorizontalFacing(Facing::NORTH); //TODO: PM impl doesn't support this yet
}
public static function encodeStone(string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::STONE)
->writeString(BlockStateNames::STONE_TYPE, $type);
}
public static function encodeStoneBricks(string $type) : BlockStateWriter{
return BlockStateWriter::create(Ids::STONEBRICK)
->writeString(BlockStateNames::STONE_BRICK_TYPE, $type);
}
private static function encodeStoneSlab(Slab $block, string $singleId, string $doubleId, string $typeKey, string $typeValue) : BlockStateWriter{
return self::encodeSlab($block, $singleId, $doubleId)
->writeString($typeKey, $typeValue);
}
public static function encodeStoneSlab1(Slab $block, string $typeValue) : BlockStateWriter{
return self::encodeStoneSlab($block, Ids::STONE_SLAB, Ids::DOUBLE_STONE_SLAB, BlockStateNames::STONE_SLAB_TYPE, $typeValue);
}
public static function encodeStoneSlab2(Slab $block, string $typeValue) : BlockStateWriter{
return self::encodeStoneSlab($block, Ids::STONE_SLAB2, Ids::DOUBLE_STONE_SLAB2, BlockStateNames::STONE_SLAB_TYPE_2, $typeValue);
}
public static function encodeStoneSlab3(Slab $block, string $typeValue) : BlockStateWriter{
return self::encodeStoneSlab($block, Ids::STONE_SLAB3, Ids::DOUBLE_STONE_SLAB3, BlockStateNames::STONE_SLAB_TYPE_3, $typeValue);
}
public static function encodeStoneSlab4(Slab $block, string $typeValue) : BlockStateWriter{
return self::encodeStoneSlab($block, Ids::STONE_SLAB4, Ids::DOUBLE_STONE_SLAB4, BlockStateNames::STONE_SLAB_TYPE_4, $typeValue);
}
public static function encodeTrapdoor(Trapdoor $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeLegacyHorizontalFacing($block->getFacing())
->writeBool(BlockStateNames::UPSIDE_DOWN_BIT, $block->isTop())
->writeBool(BlockStateNames::OPEN_BIT, $block->isOpen());
}
public static function encodeWall(Wall $block, BlockStateWriter $out) : BlockStateWriter{
//TODO: our walls don't support the full range of needed states yet
return $out
->writeBool(BlockStateNames::WALL_POST_BIT, false)
->writeString(BlockStateNames::WALL_CONNECTION_TYPE_EAST, BlockStateStringValues::WALL_CONNECTION_TYPE_EAST_NONE)
->writeString(BlockStateNames::WALL_CONNECTION_TYPE_NORTH, BlockStateStringValues::WALL_CONNECTION_TYPE_NORTH_NONE)
->writeString(BlockStateNames::WALL_CONNECTION_TYPE_SOUTH, BlockStateStringValues::WALL_CONNECTION_TYPE_SOUTH_NONE)
->writeString(BlockStateNames::WALL_CONNECTION_TYPE_WEST, BlockStateStringValues::WALL_CONNECTION_TYPE_WEST_NONE);
}
public static function encodeLegacyWall(Wall $block, string $type) : BlockStateWriter{
return self::encodeWall($block, BlockStateWriter::create(Ids::COBBLESTONE_WALL))
->writeString(BlockStateNames::WALL_BLOCK_TYPE, $type);
}
public static function encodeWallSign(WallSign $block, BlockStateWriter $out) : BlockStateWriter{
return $out
->writeHorizontalFacing($block->getFacing());
}
public static function encodeWoodenSlab(Slab $block, string $typeValue) : BlockStateWriter{
return self::encodeSlab($block, Ids::WOODEN_SLAB, Ids::DOUBLE_WOODEN_SLAB)
->writeString(BlockStateNames::WOOD_TYPE, $typeValue);
}
}

View File

@ -27,6 +27,7 @@ use pocketmine\block\utils\BellAttachmentType;
use pocketmine\block\utils\CoralType;
use pocketmine\block\utils\DyeColor;
use pocketmine\block\utils\SlabType;
use pocketmine\block\utils\TreeType;
use pocketmine\data\bedrock\blockstate\BlockStateStringValues as StringValues;
use pocketmine\math\Axis;
use pocketmine\math\Facing;
@ -42,6 +43,10 @@ final class BlockStateWriter{
$this->states = CompoundTag::create();
}
public static function create(string $id) : self{
return new self($id);
}
/** @return $this */
public function writeBool(string $name, bool $value) : self{
$this->states->setByte($name, $value ? 1 : 0);
@ -195,6 +200,20 @@ final class BlockStateWriter{
return $this;
}
/** @return $this */
public function writeTreeType(TreeType $treeType) : self{
$this->writeString(BlockStateNames::WOOD_TYPE, match($treeType->id()){
TreeType::OAK()->id() => StringValues::WOOD_TYPE_OAK,
TreeType::SPRUCE()->id() => StringValues::WOOD_TYPE_SPRUCE,
TreeType::BIRCH()->id() => StringValues::WOOD_TYPE_BIRCH,
TreeType::JUNGLE()->id() => StringValues::WOOD_TYPE_JUNGLE,
TreeType::ACACIA()->id() => StringValues::WOOD_TYPE_ACACIA,
TreeType::DARK_OAK()->id() => StringValues::WOOD_TYPE_DARK_OAK,
default => throw new BlockStateSerializeException("Invalid Tree type " . $treeType->name())
});
return $this;
}
/** @return $this */
public function writeCoralType(CoralType $coralType) : self{
$this->writeString(BlockStateNames::CORAL_COLOR, match($coralType->id()){