From ff0199cdf832b276bd774adb70a89a1e4b2ede5f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 13 Jun 2023 18:02:56 +0100 Subject: [PATCH] Fixed blue candle being missing from the creative inventory this coincidentally fixes mangrove doors being tagged with unwanted blockstate runtime IDs. Their items client-side are not actually blockitems, so the client doesn't expect them to have blockstate IDs attached. This reduces the chaos in the creative inventory slightly (for some reason the client responds to this stuff by putting random creative items in the wrong places), but the mess is still substantial and I don't know what caused the rest of it. closes #5818 technically we shouldn't be breaking BC of internals signatures in a patch release, but it's internals, and that's an unwritten rule anyway. In any case, no one is likely to be affected. --- composer.lock | 12 ++++++------ src/data/bedrock/item/ItemSerializer.php | 1 + src/network/mcpe/convert/ItemTranslator.php | 16 ++++++++++------ src/network/mcpe/convert/TypeConverter.php | 7 ++++--- tools/generate-bedrock-data-from-packets.php | 11 +++++++++-- 5 files changed, 30 insertions(+), 17 deletions(-) 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; }