diff --git a/composer.lock b/composer.lock index f44963cba..e27182c1c 100644 --- a/composer.lock +++ b/composer.lock @@ -224,16 +224,16 @@ }, { "name": "pocketmine/bedrock-data", - "version": "2.3.0+bedrock-1.20.0", + "version": "2.3.1+bedrock-1.20.0", "source": { "type": "git", "url": "https://github.com/pmmp/BedrockData.git", - "reference": "b3dd3f4b8e3b6759c5d84de6ec85bb20b668c3a9" + "reference": "fb89ccdc039252462d8d068a769635e24151b7e2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/b3dd3f4b8e3b6759c5d84de6ec85bb20b668c3a9", - "reference": "b3dd3f4b8e3b6759c5d84de6ec85bb20b668c3a9", + "url": "https://api.github.com/repos/pmmp/BedrockData/zipball/fb89ccdc039252462d8d068a769635e24151b7e2", + "reference": "fb89ccdc039252462d8d068a769635e24151b7e2", "shasum": "" }, "type": "library", @@ -244,9 +244,9 @@ "description": "Blobs of data generated from Minecraft: Bedrock Edition, used by PocketMine-MP", "support": { "issues": "https://github.com/pmmp/BedrockData/issues", - "source": "https://github.com/pmmp/BedrockData/tree/bedrock-1.20.0" + "source": "https://github.com/pmmp/BedrockData/tree/2.3.1+bedrock-1.20.0" }, - "time": "2023-06-07T19:06:47+00:00" + "time": "2023-06-13T16:42:09+00:00" }, { "name": "pocketmine/bedrock-item-upgrade-schema", diff --git a/src/data/bedrock/item/ItemSerializer.php b/src/data/bedrock/item/ItemSerializer.php index 39aeb7bfb..845d5bc5f 100644 --- a/src/data/bedrock/item/ItemSerializer.php +++ b/src/data/bedrock/item/ItemSerializer.php @@ -177,6 +177,7 @@ final class ItemSerializer{ throw new ItemTypeSerializeException($e->getMessage(), 0, $e); } + //TODO: this really ought to throw if there's no blockitem ID $itemNameId = BlockItemIdMap::getInstance()->lookupItemId($blockStateData->getName()) ?? $blockStateData->getName(); return new Data($itemNameId, 0, $blockStateData); diff --git a/src/network/mcpe/convert/ItemTranslator.php b/src/network/mcpe/convert/ItemTranslator.php index ea7a64d40..2c5ad0607 100644 --- a/src/network/mcpe/convert/ItemTranslator.php +++ b/src/network/mcpe/convert/ItemTranslator.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\convert; +use pocketmine\data\bedrock\item\BlockItemIdMap; use pocketmine\data\bedrock\item\ItemDeserializer; use pocketmine\data\bedrock\item\ItemSerializer; use pocketmine\data\bedrock\item\ItemTypeDeserializeException; @@ -37,18 +38,19 @@ use pocketmine\utils\AssumptionFailedError; * This class handles translation between network item ID+metadata to PocketMine-MP internal ID+metadata and vice versa. */ final class ItemTranslator{ - public const NO_BLOCK_RUNTIME_ID = 0; + public const NO_BLOCK_RUNTIME_ID = 0; //this is technically a valid block runtime ID, but is used to represent "no block" (derp mojang) public function __construct( private ItemTypeDictionary $itemTypeDictionary, private BlockStateDictionary $blockStateDictionary, private ItemSerializer $itemSerializer, - private ItemDeserializer $itemDeserializer + private ItemDeserializer $itemDeserializer, + private BlockItemIdMap $blockItemIdMap ){} /** * @return int[]|null - * @phpstan-return array{int, int, int}|null + * @phpstan-return array{int, int, ?int}|null */ public function toNetworkIdQuiet(Item $item) : ?array{ try{ @@ -60,7 +62,7 @@ final class ItemTranslator{ /** * @return int[] - * @phpstan-return array{int, int, int} + * @phpstan-return array{int, int, ?int} * * @throws ItemTypeSerializeException */ @@ -78,7 +80,7 @@ final class ItemTranslator{ throw new AssumptionFailedError("Unmapped blockstate returned by blockstate serializer: " . $blockStateData->toNbt()); } }else{ - $blockRuntimeId = self::NO_BLOCK_RUNTIME_ID; //this is technically a valid block runtime ID, but is used to represent "no block" (derp mojang) + $blockRuntimeId = null; } return [$numericId, $itemData->getMeta(), $blockRuntimeId]; @@ -106,11 +108,13 @@ final class ItemTranslator{ } $blockStateData = null; - if($networkBlockRuntimeId !== self::NO_BLOCK_RUNTIME_ID){ + if($this->blockItemIdMap->lookupBlockId($stringId) !== null){ $blockStateData = $this->blockStateDictionary->generateDataFromStateId($networkBlockRuntimeId); if($blockStateData === null){ throw new TypeConversionException("Blockstate runtimeID $networkBlockRuntimeId does not correspond to any known blockstate"); } + }elseif($networkBlockRuntimeId !== self::NO_BLOCK_RUNTIME_ID){ + throw new TypeConversionException("Item $stringId is not a blockitem, but runtime ID $networkBlockRuntimeId was provided"); } try{ diff --git a/src/network/mcpe/convert/TypeConverter.php b/src/network/mcpe/convert/TypeConverter.php index e01a5a10f..94f476e9c 100644 --- a/src/network/mcpe/convert/TypeConverter.php +++ b/src/network/mcpe/convert/TypeConverter.php @@ -82,7 +82,8 @@ class TypeConverter{ $this->itemTypeDictionary, $this->blockTranslator->getBlockStateDictionary(), GlobalItemDataHandlers::getSerializer(), - GlobalItemDataHandlers::getDeserializer() + GlobalItemDataHandlers::getDeserializer(), + $this->blockItemIdMap ); $this->skinAdapter = new LegacySkinAdapter(); @@ -147,7 +148,7 @@ class TypeConverter{ }elseif($ingredient instanceof ExactRecipeIngredient){ $item = $ingredient->getItem(); [$id, $meta, $blockRuntimeId] = $this->itemTranslator->toNetworkId($item); - if($blockRuntimeId !== ItemTranslator::NO_BLOCK_RUNTIME_ID){ + if($blockRuntimeId !== null){ $meta = $this->blockTranslator->getBlockStateDictionary()->getMetaFromStateId($blockRuntimeId); if($meta === null){ throw new AssumptionFailedError("Every block state should have an associated meta value"); @@ -230,7 +231,7 @@ class TypeConverter{ $id, $meta, $itemStack->getCount(), - $blockRuntimeId, + $blockRuntimeId ?? ItemTranslator::NO_BLOCK_RUNTIME_ID, $nbt, [], [], diff --git a/tools/generate-bedrock-data-from-packets.php b/tools/generate-bedrock-data-from-packets.php index 989310e25..a8ea6554b 100644 --- a/tools/generate-bedrock-data-from-packets.php +++ b/tools/generate-bedrock-data-from-packets.php @@ -33,6 +33,7 @@ use pocketmine\crafting\json\ShapelessRecipeData; use pocketmine\crafting\json\SmithingTransformRecipeData; use pocketmine\crafting\json\SmithingTrimRecipeData; use pocketmine\data\bedrock\block\BlockStateData; +use pocketmine\data\bedrock\item\BlockItemIdMap; use pocketmine\nbt\LittleEndianNbtSerializer; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; @@ -40,6 +41,7 @@ use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\TreeRoot; use pocketmine\network\mcpe\convert\BlockStateDictionary; use pocketmine\network\mcpe\convert\BlockTranslator; +use pocketmine\network\mcpe\convert\ItemTranslator; use pocketmine\network\mcpe\handler\PacketHandler; use pocketmine\network\mcpe\protocol\AvailableActorIdentifiersPacket; use pocketmine\network\mcpe\protocol\BiomeDefinitionListPacket; @@ -110,6 +112,7 @@ class ParserPacketHandler extends PacketHandler{ public ?ItemTypeDictionary $itemTypeDictionary = null; private BlockTranslator $blockTranslator; + private BlockItemIdMap $blockItemIdMap; public function __construct(private string $bedrockDataPath){ $this->blockTranslator = new BlockTranslator( @@ -119,6 +122,7 @@ class ParserPacketHandler extends PacketHandler{ ), GlobalBlockStateHandlers::getSerializer() ); + $this->blockItemIdMap = BlockItemIdMap::getInstance(); } private static function blockStatePropertiesToString(BlockStateData $blockStateData) : string{ @@ -136,7 +140,8 @@ class ParserPacketHandler extends PacketHandler{ if($this->itemTypeDictionary === null){ throw new PacketHandlingException("Can't process item yet; haven't received item type dictionary"); } - $data = new ItemStackData($this->itemTypeDictionary->fromIntId($itemStack->getId())); + $itemStringId = $this->itemTypeDictionary->fromIntId($itemStack->getId()); + $data = new ItemStackData($itemStringId); if($itemStack->getCount() !== 1){ $data->count = $itemStack->getCount(); @@ -146,7 +151,7 @@ class ParserPacketHandler extends PacketHandler{ if($meta === 32767){ $meta = 0; //kick wildcard magic bullshit } - if($itemStack->getBlockRuntimeId() !== 0){ + if($this->blockItemIdMap->lookupBlockId($itemStringId) !== null){ if($meta !== 0){ throw new PacketHandlingException("Unexpected non-zero blockitem meta"); } @@ -159,6 +164,8 @@ class ParserPacketHandler extends PacketHandler{ if(count($stateProperties) > 0){ $data->block_states = self::blockStatePropertiesToString($blockState); } + }elseif($itemStack->getBlockRuntimeId() !== ItemTranslator::NO_BLOCK_RUNTIME_ID){ + throw new PacketHandlingException("Non-blockitems should have a zero block runtime ID"); }elseif($meta !== 0){ $data->meta = $meta; }