diff --git a/src/network/mcpe/convert/BlockStateDictionary.php b/src/network/mcpe/convert/BlockStateDictionary.php index 6322f5255..24d49e34c 100644 --- a/src/network/mcpe/convert/BlockStateDictionary.php +++ b/src/network/mcpe/convert/BlockStateDictionary.php @@ -25,6 +25,10 @@ namespace pocketmine\network\mcpe\convert; use pocketmine\data\bedrock\block\BlockStateData; use pocketmine\nbt\NbtDataException; +use pocketmine\nbt\tag\ByteTag; +use pocketmine\nbt\tag\CompoundTag; +use pocketmine\nbt\tag\IntTag; +use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\TreeRoot; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; use function array_map; @@ -108,6 +112,33 @@ final class BlockStateDictionary{ */ public function getStates() : array{ return $this->states; } + /** + * @param string[] $keyIndex + * @param (ByteTag|StringTag|IntTag)[][] $valueIndex + * @phpstan-param array $keyIndex + * @phpstan-param array> $valueIndex + */ + private static function deduplicateCompound(CompoundTag $tag, array &$keyIndex, array &$valueIndex) : CompoundTag{ + if($tag->count() === 0){ + return $tag; + } + + $newTag = CompoundTag::create(); + foreach($tag as $key => $value){ + $key = $keyIndex[$key] ??= $key; + + if($value instanceof CompoundTag){ + $value = self::deduplicateCompound($value, $keyIndex, $valueIndex); + }elseif($value instanceof ByteTag || $value instanceof IntTag || $value instanceof StringTag){ + $value = $valueIndex[$value->getType()][$value->getValue()] ??= $value; + } + + $newTag->setTag($key, $value); + } + + return $newTag; + } + /** * @return BlockStateData[] * @phpstan-return list @@ -115,8 +146,13 @@ final class BlockStateDictionary{ * @throws NbtDataException */ public static function loadPaletteFromString(string $blockPaletteContents) : array{ + $keyIndex = []; + $valueIndex = []; + return array_map( - fn(TreeRoot $root) => BlockStateData::fromNbt($root->mustGetCompoundTag()), + function(TreeRoot $root) use (&$keyIndex, &$valueIndex) : BlockStateData{ + return BlockStateData::fromNbt(self::deduplicateCompound($root->mustGetCompoundTag(), $keyIndex, $valueIndex)); + }, (new NetworkNbtSerializer())->readMultiple($blockPaletteContents) ); }