diff --git a/src/data/bedrock/blockstate/BlockStateData.php b/src/data/bedrock/blockstate/BlockStateData.php new file mode 100644 index 000000000..c6485c748 --- /dev/null +++ b/src/data/bedrock/blockstate/BlockStateData.php @@ -0,0 +1,88 @@ +name; } + + public function getStates() : CompoundTag{ return $this->states; } + + public function getVersion() : int{ return $this->version; } + + /** + * @throws BlockStateDeserializeException + */ + public static function fromNbt(CompoundTag $nbt) : self{ + try{ + $name = $nbt->getString(self::TAG_NAME); + $states = $nbt->getCompoundTag(self::TAG_STATES) ?? throw new BlockStateDeserializeException("Missing tag \"" . self::TAG_STATES . "\""); + $version = $nbt->getInt(self::TAG_VERSION, 0); + }catch(NbtException $e){ + throw new BlockStateDeserializeException($e->getMessage(), 0, $e); + } + + $allKeys = $nbt->getValue(); + unset($allKeys[self::TAG_NAME], $allKeys[self::TAG_STATES], $allKeys[self::TAG_VERSION]); + if(count($allKeys) !== 0){ + throw new BlockStateDeserializeException("Unexpected extra keys: " . implode(", ", array_keys($allKeys))); + } + + return new self($name, $states, $version); + } + + public function toNbt() : CompoundTag{ + return CompoundTag::create() + ->setString(self::TAG_NAME, $this->name) + ->setInt(self::TAG_VERSION, $this->version) + ->setTag(self::TAG_STATES, $this->states); + } +} diff --git a/src/data/bedrock/blockstate/BlockStateDeserializer.php b/src/data/bedrock/blockstate/BlockStateDeserializer.php index 7a6d44463..1d3caef3f 100644 --- a/src/data/bedrock/blockstate/BlockStateDeserializer.php +++ b/src/data/bedrock/blockstate/BlockStateDeserializer.php @@ -37,7 +37,6 @@ 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; @@ -2501,20 +2500,12 @@ final class BlockStateDeserializer{ /** @throws BlockStateDeserializeException */ 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"); - } + $blockStateData = BlockStateData::fromNbt($blockState); + $id = $blockStateData->getName(); if(!array_key_exists($id, $this->deserializeFuncs)){ throw new BlockStateDeserializeException("Unknown block ID \"$id\""); } - return $this->deserializeFuncs[$id](new BlockStateReader($states)); + return $this->deserializeFuncs[$id](new BlockStateReader($blockStateData)); } } diff --git a/src/data/bedrock/blockstate/BlockStateReader.php b/src/data/bedrock/blockstate/BlockStateReader.php index dad5dc62d..043b16ef1 100644 --- a/src/data/bedrock/blockstate/BlockStateReader.php +++ b/src/data/bedrock/blockstate/BlockStateReader.php @@ -31,7 +31,6 @@ use pocketmine\data\bedrock\blockstate\BlockStateStringValues as StringValues; use pocketmine\math\Axis; use pocketmine\math\Facing; use pocketmine\nbt\tag\ByteTag; -use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\Tag; @@ -39,13 +38,9 @@ use function get_class; final class BlockStateReader{ - private CompoundTag $nbt; - - public function __construct(CompoundTag $nbt){ - $this->nbt = $nbt; - } - - public function getNbt() : CompoundTag{ return $this->nbt; } + public function __construct( + private BlockStateData $data + ){} public function missingOrWrongTypeException(string $name, ?Tag $tag) : BlockStateDeserializeException{ return new BlockStateDeserializeException("Property \"$name\" " . ($tag !== null ? "has unexpected type " . get_class($tag) : "is missing")); @@ -60,7 +55,7 @@ final class BlockStateReader{ /** @throws BlockStateDeserializeException */ public function readBool(string $name) : bool{ - $tag = $this->nbt->getTag($name); + $tag = $this->data->getStates()->getTag($name); if($tag instanceof ByteTag){ switch($tag->getValue()){ case 0: return false; @@ -73,7 +68,7 @@ final class BlockStateReader{ /** @throws BlockStateDeserializeException */ public function readInt(string $name) : int{ - $tag = $this->nbt->getTag($name); + $tag = $this->data->getStates()->getTag($name); if($tag instanceof IntTag){ return $tag->getValue(); } @@ -92,7 +87,7 @@ final class BlockStateReader{ /** @throws BlockStateDeserializeException */ public function readString(string $name) : string{ //TODO: only allow a specific set of values (strings are primarily used for enums) - $tag = $this->nbt->getTag($name); + $tag = $this->data->getStates()->getTag($name); if($tag instanceof StringTag){ return $tag->getValue(); } diff --git a/src/data/bedrock/blockstate/BlockStateSerializer.php b/src/data/bedrock/blockstate/BlockStateSerializer.php index 6385bc794..8c705ca2f 100644 --- a/src/data/bedrock/blockstate/BlockStateSerializer.php +++ b/src/data/bedrock/blockstate/BlockStateSerializer.php @@ -143,7 +143,6 @@ use pocketmine\data\bedrock\blockstate\BlockStateWriter as Writer; use pocketmine\data\bedrock\blockstate\BlockTypeNames as Ids; use pocketmine\math\Axis; use pocketmine\math\Facing; -use pocketmine\nbt\tag\CompoundTag; use pocketmine\utils\AssumptionFailedError; use function class_parents; use function get_class; @@ -175,7 +174,7 @@ final class BlockStateSerializer{ * @phpstan-template TBlockType of Block * @phpstan-param TBlockType $blockState */ - public function serialize(Block $blockState) : CompoundTag{ + public function serialize(Block $blockState) : BlockStateData{ $typeId = $blockState->getTypeId(); $locatedSerializer = $this->serializers[$typeId][get_class($blockState)] ?? null; @@ -204,7 +203,7 @@ final class BlockStateSerializer{ /** @var Writer $writer */ $writer = $serializer($blockState); - return $writer->writeBlockStateNbt(); + return $writer->getBlockStateData(); } public function __construct(){ diff --git a/src/data/bedrock/blockstate/BlockStateWriter.php b/src/data/bedrock/blockstate/BlockStateWriter.php index 34fce1001..907db99c2 100644 --- a/src/data/bedrock/blockstate/BlockStateWriter.php +++ b/src/data/bedrock/blockstate/BlockStateWriter.php @@ -246,10 +246,7 @@ final class BlockStateWriter{ return $this; } - public function writeBlockStateNbt() : CompoundTag{ - //TODO: add `version` field - return CompoundTag::create() - ->setString("name", $this->id) - ->setTag("states", $this->states); + public function getBlockStateData() : BlockStateData{ + return new BlockStateData($this->id, $this->states, BlockStateData::CURRENT_VERSION); } }