diff --git a/resources/vanilla b/resources/vanilla index cc132c80d..43edcfde6 160000 --- a/resources/vanilla +++ b/resources/vanilla @@ -1 +1 @@ -Subproject commit cc132c80dd9d76a44e4b0a360e85e8e28bba8956 +Subproject commit 43edcfde6b9611b7c7d643be52332707cc10cd1b diff --git a/src/block/BlockFactory.php b/src/block/BlockFactory.php index 1abdc0652..7306fd088 100644 --- a/src/block/BlockFactory.php +++ b/src/block/BlockFactory.php @@ -85,11 +85,11 @@ class BlockFactory{ public $blastResistance; public function __construct(){ - $this->fullList = new \SplFixedArray(8192); + $this->fullList = new \SplFixedArray(16384); - $this->lightFilter = \SplFixedArray::fromArray(array_fill(0, 8192, 1)); - $this->diffusesSkyLight = \SplFixedArray::fromArray(array_fill(0, 8192, false)); - $this->blastResistance = \SplFixedArray::fromArray(array_fill(0, 8192, 0.0)); + $this->lightFilter = \SplFixedArray::fromArray(array_fill(0, 16384, 1)); + $this->diffusesSkyLight = \SplFixedArray::fromArray(array_fill(0, 16384, false)); + $this->blastResistance = \SplFixedArray::fromArray(array_fill(0, 16384, 0.0)); $this->register(new ActivatorRail(new BID(Ids::ACTIVATOR_RAIL), "Activator Rail")); $this->register(new Air(new BID(Ids::AIR), "Air")); diff --git a/src/crafting/CraftingManager.php b/src/crafting/CraftingManager.php index 701d23164..63af6fc26 100644 --- a/src/crafting/CraftingManager.php +++ b/src/crafting/CraftingManager.php @@ -86,7 +86,8 @@ class CraftingManager{ }, $recipe->getResults()), $nullUUID, "crafting_table", - 50 + 50, + $counter ); } } @@ -108,7 +109,8 @@ class CraftingManager{ }, $recipe->getResults()), $nullUUID, "crafting_table", - 50 + 50, + $counter ); } } diff --git a/src/item/enchantment/Enchantment.php b/src/item/enchantment/Enchantment.php index 313a88d84..50ac2d406 100644 --- a/src/item/enchantment/Enchantment.php +++ b/src/item/enchantment/Enchantment.php @@ -69,6 +69,7 @@ class Enchantment{ public const MULTISHOT = 33; public const PIERCING = 34; public const QUICK_CHARGE = 35; + public const SOUL_SPEED = 36; public const RARITY_COMMON = 10; public const RARITY_UNCOMMON = 5; diff --git a/src/network/mcpe/InventoryManager.php b/src/network/mcpe/InventoryManager.php index a6e33268b..1b288a189 100644 --- a/src/network/mcpe/InventoryManager.php +++ b/src/network/mcpe/InventoryManager.php @@ -38,11 +38,13 @@ use pocketmine\network\mcpe\convert\TypeConverter; use pocketmine\network\mcpe\protocol\ContainerClosePacket; use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\ContainerSetDataPacket; +use pocketmine\network\mcpe\protocol\CreativeContentPacket; use pocketmine\network\mcpe\protocol\InventoryContentPacket; use pocketmine\network\mcpe\protocol\InventorySlotPacket; use pocketmine\network\mcpe\protocol\MobEquipmentPacket; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; -use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; +use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry; +use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; use pocketmine\player\Player; use function array_map; @@ -51,6 +53,14 @@ use function max; class InventoryManager{ + //TODO: HACK! + //these IDs are used for 1.16 to restore 1.14ish crafting & inventory behaviour; since they don't seem to have any + //effect on the behaviour of inventory transactions I don't currently plan to integrate these into the main system. + private const RESERVED_WINDOW_ID_RANGE_START = ContainerIds::LAST - 10; + private const RESERVED_WINDOW_ID_RANGE_END = ContainerIds::LAST; + public const HARDCODED_CRAFTING_GRID_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 1; + public const HARDCODED_INVENTORY_WINDOW_ID = self::RESERVED_WINDOW_ID_RANGE_START + 2; + /** @var Player */ private $player; /** @var NetworkSession */ @@ -107,7 +117,7 @@ class InventoryManager{ public function onCurrentWindowChange(Inventory $inventory) : void{ $this->onCurrentWindowRemove(); - $this->add($this->lastInventoryNetworkId = max(ContainerIds::FIRST, ($this->lastInventoryNetworkId + 1) % ContainerIds::LAST), $inventory); + $this->add($this->lastInventoryNetworkId = max(ContainerIds::FIRST, ($this->lastInventoryNetworkId + 1) % self::RESERVED_WINDOW_ID_RANGE_START), $inventory); $pk = $this->createContainerOpen($this->lastInventoryNetworkId, $inventory); if($pk !== null){ @@ -148,6 +158,10 @@ class InventoryManager{ } public function onClientRemoveWindow(int $id) : void{ + if($id >= self::RESERVED_WINDOW_ID_RANGE_START && $id <= self::RESERVED_WINDOW_ID_RANGE_END){ + //TODO: HACK! crafting grid & main inventory currently use these fake IDs + return; + } if($id === $this->lastInventoryNetworkId){ $this->remove($id); $this->player->removeCurrentWindow(); @@ -162,7 +176,7 @@ class InventoryManager{ $currentItem = $inventory->getItem($slot); $clientSideItem = $this->initiatedSlotChanges[$windowId][$slot] ?? null; if($clientSideItem === null or !$clientSideItem->equalsExact($currentItem)){ - $this->session->sendDataPacket(InventorySlotPacket::create($windowId, $slot, TypeConverter::getInstance()->coreItemStackToNet($currentItem))); + $this->session->sendDataPacket(InventorySlotPacket::create($windowId, $slot, ItemStackWrapper::legacy(TypeConverter::getInstance()->coreItemStackToNet($currentItem)))); } unset($this->initiatedSlotChanges[$windowId][$slot]); } @@ -173,8 +187,8 @@ class InventoryManager{ if($windowId !== null){ unset($this->initiatedSlotChanges[$windowId]); $typeConverter = TypeConverter::getInstance(); - $this->session->sendDataPacket(InventoryContentPacket::create($windowId, array_map(function(Item $itemStack) use ($typeConverter) : ItemStack{ - return $typeConverter->coreItemStackToNet($itemStack); + $this->session->sendDataPacket(InventoryContentPacket::create($windowId, array_map(function(Item $itemStack) use ($typeConverter) : ItemStackWrapper{ + return ItemStackWrapper::legacy($typeConverter->coreItemStackToNet($itemStack)); }, $inventory->getContents(true)))); } } @@ -210,6 +224,9 @@ class InventoryManager{ } } - $this->session->sendDataPacket(InventoryContentPacket::create(ContainerIds::CREATIVE, $items)); + $nextEntryId = 1; + $this->session->sendDataPacket(CreativeContentPacket::create(array_map(function(Item $item) use($typeConverter, &$nextEntryId) : CreativeContentEntry{ + return new CreativeContentEntry($nextEntryId++, $typeConverter->coreItemStackToNet($item)); + }, $this->player->isSpectator() ? [] : CreativeInventory::getInstance()->getAll()))); } } diff --git a/src/network/mcpe/NetworkSession.php b/src/network/mcpe/NetworkSession.php index cd057666f..b078922a4 100644 --- a/src/network/mcpe/NetworkSession.php +++ b/src/network/mcpe/NetworkSession.php @@ -85,6 +85,7 @@ use pocketmine\network\mcpe\protocol\TransferPacket; use pocketmine\network\mcpe\protocol\types\command\CommandData; use pocketmine\network\mcpe\protocol\types\command\CommandEnum; use pocketmine\network\mcpe\protocol\types\command\CommandParameter; +use pocketmine\network\mcpe\protocol\types\DimensionIds; use pocketmine\network\mcpe\protocol\types\entity\Attribute as NetworkAttribute; use pocketmine\network\mcpe\protocol\types\entity\MetadataProperty; use pocketmine\network\mcpe\protocol\types\inventory\ContainerIds; @@ -684,7 +685,8 @@ class NetworkSession{ } public function syncPlayerSpawnPoint(Position $newSpawn) : void{ - $this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ(), false)); //TODO: spawn forced + [$x, $y, $z] = [$newSpawn->getFloorX(), $newSpawn->getFloorY(), $newSpawn->getFloorZ()]; + $this->sendDataPacket(SetSpawnPositionPacket::playerSpawn($x, $y, $z, DimensionIds::OVERWORLD, $x, $y, $z)); } public function syncGameMode(GameMode $mode, bool $isRollback = false) : void{ diff --git a/src/network/mcpe/compression/ZlibCompressor.php b/src/network/mcpe/compression/ZlibCompressor.php index dfb56e065..61115f22d 100644 --- a/src/network/mcpe/compression/ZlibCompressor.php +++ b/src/network/mcpe/compression/ZlibCompressor.php @@ -27,7 +27,7 @@ use pocketmine\utils\SingletonTrait; use function strlen; use function zlib_decode; use function zlib_encode; -use const ZLIB_ENCODING_DEFLATE; +use const ZLIB_ENCODING_RAW; final class ZlibCompressor implements Compressor{ use SingletonTrait; @@ -72,6 +72,6 @@ final class ZlibCompressor implements Compressor{ } public function compress(string $payload) : string{ - return zlib_encode($payload, ZLIB_ENCODING_DEFLATE, $this->willCompress($payload) ? $this->level : 0); + return zlib_encode($payload, ZLIB_ENCODING_RAW, $this->willCompress($payload) ? $this->level : 0); } } diff --git a/src/network/mcpe/convert/R12ToCurrentBlockMapEntry.php b/src/network/mcpe/convert/R12ToCurrentBlockMapEntry.php new file mode 100644 index 000000000..1244d2745 --- /dev/null +++ b/src/network/mcpe/convert/R12ToCurrentBlockMapEntry.php @@ -0,0 +1,58 @@ +id = $id; + $this->meta = $meta; + $this->blockState = $blockState; + } + + public function getId() : string{ + return $this->id; + } + + public function getMeta() : int{ + return $this->meta; + } + + public function getBlockState() : CompoundTag{ + return $this->blockState; + } + + public function __toString(){ + return "id=$this->id, meta=$this->meta, nbt=$this->blockState"; + } +} diff --git a/src/network/mcpe/convert/RuntimeBlockMapping.php b/src/network/mcpe/convert/RuntimeBlockMapping.php index 9c4b08536..805d6bb79 100644 --- a/src/network/mcpe/convert/RuntimeBlockMapping.php +++ b/src/network/mcpe/convert/RuntimeBlockMapping.php @@ -29,6 +29,7 @@ use pocketmine\nbt\NBT; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\ListTag; use pocketmine\network\mcpe\protocol\serializer\NetworkNbtSerializer; +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; use pocketmine\network\mcpe\protocol\types\CacheableNbt; use pocketmine\utils\SingletonTrait; use function file_get_contents; @@ -70,9 +71,18 @@ final class RuntimeBlockMapping{ private function setupLegacyMappings() : void{ $legacyIdMap = LegacyBlockIdToStringIdMap::getInstance(); - $legacyStateMap = (new NetworkNbtSerializer())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"))->getTag(); - if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){ - throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List root"); + /** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */ + $legacyStateMap = []; + $legacyStateMapReader = new PacketSerializer(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.bin")); + $nbtReader = new NetworkNbtSerializer(); + while(!$legacyStateMapReader->feof()){ + $id = $legacyStateMapReader->getString(); + $meta = $legacyStateMapReader->getLShort(); + + $offset = $legacyStateMapReader->getOffset(); + $state = $nbtReader->read($legacyStateMapReader->getBuffer(), $offset)->mustGetCompoundTag(); + $legacyStateMapReader->setOffset($offset); + $legacyStateMap[] = new R12ToCurrentBlockMapEntry($id, $meta, $state); } /** @@ -82,19 +92,17 @@ final class RuntimeBlockMapping{ foreach($this->bedrockKnownStates as $k => $state){ $idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k; } - /** @var CompoundTag $pair */ foreach($legacyStateMap as $pair){ - $oldState = $pair->getCompoundTag("old"); - $id = $legacyIdMap->stringToLegacy($oldState->getString("name")); + $id = $legacyIdMap->stringToLegacy($pair->getId()) ?? null; if($id === null){ - throw new \RuntimeException("State does not have a legacy ID"); + throw new \RuntimeException("No legacy ID matches " . $pair->getId()); } - $data = $oldState->getShort("val"); + $data = $pair->getMeta(); if($data > 15){ //we can't handle metadata with more than 4 bits continue; } - $mappedState = $pair->getCompoundTag("new"); + $mappedState = $pair->getBlockState(); $mappedName = $mappedState->getString("name"); if(!isset($idToStatesMap[$mappedName])){ throw new \RuntimeException("Mapped new state does not appear in network table"); diff --git a/src/network/mcpe/handler/InGamePacketHandler.php b/src/network/mcpe/handler/InGamePacketHandler.php index ba185d241..9bd0c9996 100644 --- a/src/network/mcpe/handler/InGamePacketHandler.php +++ b/src/network/mcpe/handler/InGamePacketHandler.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\handler; +use pocketmine\block\BlockLegacyIds; use pocketmine\block\ItemFrame; use pocketmine\block\Sign; use pocketmine\block\utils\SignText; @@ -42,6 +43,7 @@ use pocketmine\nbt\tag\StringTag; use pocketmine\network\BadPacketException; use pocketmine\network\mcpe\convert\SkinAdapterSingleton; use pocketmine\network\mcpe\convert\TypeConverter; +use pocketmine\network\mcpe\InventoryManager; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\ActorFallPacket; @@ -55,6 +57,7 @@ use pocketmine\network\mcpe\protocol\BossEventPacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket; use pocketmine\network\mcpe\protocol\ContainerClosePacket; +use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; use pocketmine\network\mcpe\protocol\InteractPacket; use pocketmine\network\mcpe\protocol\InventoryTransactionPacket; @@ -86,6 +89,7 @@ use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; +use pocketmine\network\mcpe\protocol\types\inventory\WindowTypes; use pocketmine\player\Player; use pocketmine\utils\AssumptionFailedError; use function array_push; @@ -205,25 +209,16 @@ class InGamePacketHandler extends PacketHandler{ $isFinalCraftingPart = false; $converter = TypeConverter::getInstance(); foreach($data->getActions() as $networkInventoryAction){ - $old = $converter->netItemStackToCore($networkInventoryAction->oldItem); - $new = $converter->netItemStackToCore($networkInventoryAction->newItem); if( - $networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and - $networkInventoryAction->windowId === ContainerIds::UI and - $networkInventoryAction->inventorySlot === 50 and - !$old->equalsExact($new) - ){ - $isCraftingPart = true; - if(!$old->isNull() and $new->isNull()){ - $isFinalCraftingPart = true; - } - }elseif( $networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_TODO and ( $networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT or $networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_USE_INGREDIENT ) ){ $isCraftingPart = true; + if($networkInventoryAction->windowId === NetworkInventoryAction::SOURCE_TYPE_CRAFTING_RESULT){ + $isFinalCraftingPart = true; + } } try{ @@ -262,7 +257,7 @@ class InGamePacketHandler extends PacketHandler{ * So people don't whine about messy desync issues when someone cancels CraftItemEvent, or when a crafting * transaction goes wrong. */ - $this->session->sendDataPacket(ContainerClosePacket::create(ContainerIds::NONE)); + $this->session->sendDataPacket(ContainerClosePacket::create(InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID)); return false; }finally{ @@ -318,6 +313,14 @@ class InGamePacketHandler extends PacketHandler{ $blockPos = $data->getBlockPos(); if(!$this->player->interactBlock($blockPos, $data->getFace(), $clickPos)){ $this->onFailedBlockAction($blockPos, $data->getFace()); + }elseif($this->player->getWorld()->getBlock($blockPos)->getId() === BlockLegacyIds::CRAFTING_TABLE){ + //TODO: HACK! crafting grid doesn't fit very well into the current PM container system, so this hack + //allows it to carry on working approximately the same way as it did in 1.14 + $this->session->sendDataPacket(ContainerOpenPacket::blockInvVec3( + InventoryManager::HARDCODED_CRAFTING_GRID_WINDOW_ID, + WindowTypes::WORKBENCH, + $blockPos + )); } return true; case UseItemTransactionData::ACTION_BREAK_BLOCK: @@ -417,6 +420,21 @@ class InGamePacketHandler extends PacketHandler{ //TODO: implement handling for this where it matters return true; } + $target = $this->player->getWorld()->getEntity($packet->target); + if($target === null){ + return false; + } + if($packet->action === InteractPacket::ACTION_OPEN_INVENTORY && $target === $this->player){ + //TODO: HACK! this restores 1.14ish behaviour, but this should be able to be listened to and + //controlled by plugins. However, the player is always a subscriber to their own inventory so it + //doesn't integrate well with the regular container system right now. + $this->session->sendDataPacket(ContainerOpenPacket::entityInv( + InventoryManager::HARDCODED_INVENTORY_WINDOW_ID, + WindowTypes::INVENTORY, + $this->player->getId() + )); + return true; + } return false; //TODO } @@ -506,13 +524,9 @@ class InGamePacketHandler extends PacketHandler{ public function handleContainerClose(ContainerClosePacket $packet) : bool{ $this->player->doCloseInventory(); - if($packet->windowId === 255){ - //Closed a fake window - return true; - } - $this->session->getInvManager()->onClientRemoveWindow($packet->windowId); + $this->session->sendDataPacket(ContainerClosePacket::create($packet->windowId)); return true; } @@ -738,7 +752,8 @@ class InGamePacketHandler extends PacketHandler{ $inQuotes = true; }else{ $backslashes = 0; - for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){} + for(; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){ + } if(($backslashes % 2) === 0){ //unescaped quote $inQuotes = false; } diff --git a/src/network/mcpe/handler/PacketHandler.php b/src/network/mcpe/handler/PacketHandler.php index 067968284..56896688e 100644 --- a/src/network/mcpe/handler/PacketHandler.php +++ b/src/network/mcpe/handler/PacketHandler.php @@ -52,6 +52,7 @@ use pocketmine\network\mcpe\protocol\ClientCacheBlobStatusPacket; use pocketmine\network\mcpe\protocol\ClientCacheMissResponsePacket; use pocketmine\network\mcpe\protocol\ClientCacheStatusPacket; use pocketmine\network\mcpe\protocol\ClientToServerHandshakePacket; +use pocketmine\network\mcpe\protocol\CodeBuilderPacket; use pocketmine\network\mcpe\protocol\CommandBlockUpdatePacket; use pocketmine\network\mcpe\protocol\CommandOutputPacket; use pocketmine\network\mcpe\protocol\CommandRequestPacket; @@ -61,8 +62,11 @@ use pocketmine\network\mcpe\protocol\ContainerOpenPacket; use pocketmine\network\mcpe\protocol\ContainerSetDataPacket; use pocketmine\network\mcpe\protocol\CraftingDataPacket; use pocketmine\network\mcpe\protocol\CraftingEventPacket; +use pocketmine\network\mcpe\protocol\CreativeContentPacket; +use pocketmine\network\mcpe\protocol\DebugInfoPacket; use pocketmine\network\mcpe\protocol\DisconnectPacket; use pocketmine\network\mcpe\protocol\EducationSettingsPacket; +use pocketmine\network\mcpe\protocol\EmoteListPacket; use pocketmine\network\mcpe\protocol\EmotePacket; use pocketmine\network\mcpe\protocol\EventPacket; use pocketmine\network\mcpe\protocol\GameRulesChangedPacket; @@ -73,6 +77,8 @@ use pocketmine\network\mcpe\protocol\InventoryContentPacket; use pocketmine\network\mcpe\protocol\InventorySlotPacket; use pocketmine\network\mcpe\protocol\InventoryTransactionPacket; use pocketmine\network\mcpe\protocol\ItemFrameDropItemPacket; +use pocketmine\network\mcpe\protocol\ItemStackRequestPacket; +use pocketmine\network\mcpe\protocol\ItemStackResponsePacket; use pocketmine\network\mcpe\protocol\LabTablePacket; use pocketmine\network\mcpe\protocol\LecternUpdatePacket; use pocketmine\network\mcpe\protocol\LevelChunkPacket; @@ -99,15 +105,20 @@ use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket; use pocketmine\network\mcpe\protocol\NpcRequestPacket; use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket; use pocketmine\network\mcpe\protocol\PacketHandlerInterface; +use pocketmine\network\mcpe\protocol\PacketViolationWarningPacket; use pocketmine\network\mcpe\protocol\PhotoTransferPacket; use pocketmine\network\mcpe\protocol\PlayerActionPacket; +use pocketmine\network\mcpe\protocol\PlayerArmorDamagePacket; use pocketmine\network\mcpe\protocol\PlayerAuthInputPacket; +use pocketmine\network\mcpe\protocol\PlayerEnchantOptionsPacket; use pocketmine\network\mcpe\protocol\PlayerHotbarPacket; use pocketmine\network\mcpe\protocol\PlayerInputPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; use pocketmine\network\mcpe\protocol\PlaySoundPacket; use pocketmine\network\mcpe\protocol\PlayStatusPacket; +use pocketmine\network\mcpe\protocol\PositionTrackingDBClientRequestPacket; +use pocketmine\network\mcpe\protocol\PositionTrackingDBServerBroadcastPacket; use pocketmine\network\mcpe\protocol\PurchaseReceiptPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket; use pocketmine\network\mcpe\protocol\RemoveEntityPacket; @@ -163,9 +174,9 @@ use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\network\mcpe\protocol\UpdateBlockPropertiesPacket; use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket; use pocketmine\network\mcpe\protocol\UpdateEquipPacket; +use pocketmine\network\mcpe\protocol\UpdatePlayerGameTypePacket; use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket; use pocketmine\network\mcpe\protocol\UpdateTradePacket; -use pocketmine\network\mcpe\protocol\VideoStreamConnectPacket; /** * Handlers are attached to sessions to handle packets received from their associated clients. A handler @@ -671,10 +682,6 @@ abstract class PacketHandler implements PacketHandlerInterface{ return false; } - public function handleVideoStreamConnect(VideoStreamConnectPacket $packet) : bool{ - return false; - } - public function handleAddEntity(AddEntityPacket $packet) : bool{ return false; } @@ -746,4 +753,52 @@ abstract class PacketHandler implements PacketHandlerInterface{ public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool{ return false; } + + public function handleCreativeContent(CreativeContentPacket $packet) : bool{ + return false; + } + + public function handlePlayerEnchantOptions(PlayerEnchantOptionsPacket $packet) : bool{ + return false; + } + + public function handleItemStackRequest(ItemStackRequestPacket $packet) : bool{ + return false; + } + + public function handleItemStackResponse(ItemStackResponsePacket $packet) : bool{ + return false; + } + + public function handlePlayerArmorDamage(PlayerArmorDamagePacket $packet) : bool{ + return false; + } + + public function handleCodeBuilder(CodeBuilderPacket $packet) : bool{ + return false; + } + + public function handleUpdatePlayerGameType(UpdatePlayerGameTypePacket $packet) : bool{ + return false; + } + + public function handleEmoteList(EmoteListPacket $packet) : bool{ + return false; + } + + public function handlePositionTrackingDBServerBroadcast(PositionTrackingDBServerBroadcastPacket $packet) : bool{ + return false; + } + + public function handlePositionTrackingDBClientRequest(PositionTrackingDBClientRequestPacket $packet) : bool{ + return false; + } + + public function handleDebugInfo(DebugInfoPacket $packet) : bool{ + return false; + } + + public function handlePacketViolationWarning(PacketViolationWarningPacket $packet) : bool{ + return false; + } } diff --git a/src/network/mcpe/handler/PreSpawnPacketHandler.php b/src/network/mcpe/handler/PreSpawnPacketHandler.php index c4ee4c022..4371dc853 100644 --- a/src/network/mcpe/handler/PreSpawnPacketHandler.php +++ b/src/network/mcpe/handler/PreSpawnPacketHandler.php @@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\RequestChunkRadiusPacket; use pocketmine\network\mcpe\protocol\StartGamePacket; use pocketmine\network\mcpe\protocol\types\BoolGameRule; use pocketmine\network\mcpe\protocol\types\DimensionIds; +use pocketmine\network\mcpe\protocol\types\SpawnSettings; use pocketmine\network\mcpe\StaticPacketCache; use pocketmine\player\Player; use pocketmine\Server; @@ -65,7 +66,7 @@ class PreSpawnPacketHandler extends PacketHandler{ $pk->pitch = $location->pitch; $pk->yaw = $location->yaw; $pk->seed = -1; - $pk->dimension = DimensionIds::OVERWORLD; //TODO: implement this properly + $pk->spawnSettings = new SpawnSettings(SpawnSettings::BIOME_TYPE_DEFAULT, "", DimensionIds::OVERWORLD); //TODO: implement this properly $pk->worldGamemode = TypeConverter::getInstance()->coreGameModeToProtocol($this->server->getGamemode()); $pk->difficulty = $location->getWorldNonNull()->getDifficulty(); $pk->spawnX = $spawnPosition->getFloorX(); diff --git a/src/network/mcpe/protocol/ActorEventPacket.php b/src/network/mcpe/protocol/ActorEventPacket.php index 7e6226231..a6cc893ab 100644 --- a/src/network/mcpe/protocol/ActorEventPacket.php +++ b/src/network/mcpe/protocol/ActorEventPacket.php @@ -87,6 +87,7 @@ class ActorEventPacket extends DataPacket implements ClientboundPacket, Serverbo public const TREASURE_HUNT = 72; public const AGENT_SUMMON = 73; public const CHARGED_CROSSBOW = 74; + public const FALL = 75; //TODO: add more events diff --git a/src/network/mcpe/protocol/CodeBuilderPacket.php b/src/network/mcpe/protocol/CodeBuilderPacket.php new file mode 100644 index 000000000..5bd0f60a9 --- /dev/null +++ b/src/network/mcpe/protocol/CodeBuilderPacket.php @@ -0,0 +1,66 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; + +class CodeBuilderPacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::CODE_BUILDER_PACKET; + + /** @var string */ + private $url; + /** @var bool */ + private $openCodeBuilder; + + public static function create(string $url, bool $openCodeBuilder) : self{ + $result = new self; + $result->url = $url; + $result->openCodeBuilder = $openCodeBuilder; + return $result; + } + + public function getUrl() : string{ + return $this->url; + } + + public function openCodeBuilder() : bool{ + return $this->openCodeBuilder; + } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->url = $in->getString(); + $this->openCodeBuilder = $in->getBool(); + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putString($this->url); + $out->putBool($this->openCodeBuilder); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleCodeBuilder($this); + } +} diff --git a/src/network/mcpe/protocol/CraftingDataPacket.php b/src/network/mcpe/protocol/CraftingDataPacket.php index 393e89358..692c1b352 100644 --- a/src/network/mcpe/protocol/CraftingDataPacket.php +++ b/src/network/mcpe/protocol/CraftingDataPacket.php @@ -83,10 +83,13 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{ } } for($i = 0, $count = $in->getUnsignedVarInt(); $i < $count; ++$i){ - $input = $in->getVarInt(); - $ingredient = $in->getVarInt(); - $output = $in->getVarInt(); - $this->potionTypeRecipes[] = new PotionTypeRecipe($input, $ingredient, $output); + $inputId = $in->getVarInt(); + $inputMeta = $in->getVarInt(); + $ingredientId = $in->getVarInt(); + $ingredientMeta = $in->getVarInt(); + $outputId = $in->getVarInt(); + $outputMeta = $in->getVarInt(); + $this->potionTypeRecipes[] = new PotionTypeRecipe($inputId, $inputMeta, $ingredientId, $ingredientMeta, $outputId, $outputMeta); } for($i = 0, $count = $in->getUnsignedVarInt(); $i < $count; ++$i){ $input = $in->getVarInt(); @@ -105,9 +108,12 @@ class CraftingDataPacket extends DataPacket implements ClientboundPacket{ } $out->putUnsignedVarInt(count($this->potionTypeRecipes)); foreach($this->potionTypeRecipes as $recipe){ - $out->putVarInt($recipe->getInputPotionType()); + $out->putVarInt($recipe->getInputItemId()); + $out->putVarInt($recipe->getInputItemMeta()); $out->putVarInt($recipe->getIngredientItemId()); - $out->putVarInt($recipe->getOutputPotionType()); + $out->putVarInt($recipe->getIngredientItemMeta()); + $out->putVarInt($recipe->getOutputItemId()); + $out->putVarInt($recipe->getOutputItemMeta()); } $out->putUnsignedVarInt(count($this->potionContainerRecipes)); foreach($this->potionContainerRecipes as $recipe){ diff --git a/src/network/mcpe/protocol/CreativeContentPacket.php b/src/network/mcpe/protocol/CreativeContentPacket.php new file mode 100644 index 000000000..2c7f0d522 --- /dev/null +++ b/src/network/mcpe/protocol/CreativeContentPacket.php @@ -0,0 +1,67 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry; +use function count; + +class CreativeContentPacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::CREATIVE_CONTENT_PACKET; + + /** @var CreativeContentEntry[] */ + private $entries; + + /** + * @param CreativeContentEntry[] $entries + */ + public static function create(array $entries) : self{ + $result = new self; + $result->entries = $entries; + return $result; + } + + /** @return CreativeContentEntry[] */ + public function getEntries() : array{ return $this->entries; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->entries = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->entries[] = CreativeContentEntry::read($in); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putUnsignedVarInt(count($this->entries)); + foreach($this->entries as $entry){ + $entry->write($out); + } + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleCreativeContent($this); + } +} diff --git a/src/network/mcpe/protocol/DebugInfoPacket.php b/src/network/mcpe/protocol/DebugInfoPacket.php new file mode 100644 index 000000000..c6cadb463 --- /dev/null +++ b/src/network/mcpe/protocol/DebugInfoPacket.php @@ -0,0 +1,65 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; + +class DebugInfoPacket extends DataPacket implements ClientboundPacket, ServerboundPacket{ + public const NETWORK_ID = ProtocolInfo::DEBUG_INFO_PACKET; + + /** @var int */ + private $entityUniqueId; + /** @var string */ + private $data; + + public static function create(int $entityUniqueId, string $data) : self{ + $result = new self; + $result->entityUniqueId = $entityUniqueId; + $result->data = $data; + return $result; + } + + /** + * TODO: we can't call this getEntityRuntimeId() because of base class collision (crap architecture, thanks Shoghi) + */ + public function getEntityUniqueIdField() : int{ return $this->entityUniqueId; } + + public function getData() : string{ return $this->data; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->entityUniqueId = $in->getEntityUniqueId(); + $this->data = $in->getString(); + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putEntityUniqueId($this->entityUniqueId); + $out->putString($this->data); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleDebugInfo($this); + } +} diff --git a/src/network/mcpe/protocol/EducationSettingsPacket.php b/src/network/mcpe/protocol/EducationSettingsPacket.php index 40198ad84..f8f6b6bb9 100644 --- a/src/network/mcpe/protocol/EducationSettingsPacket.php +++ b/src/network/mcpe/protocol/EducationSettingsPacket.php @@ -32,12 +32,21 @@ class EducationSettingsPacket extends DataPacket implements ClientboundPacket{ /** @var string */ private $codeBuilderDefaultUri; + /** @var string */ + private $codeBuilderTitle; + /** @var bool */ + private $canResizeCodeBuilder; + /** @var string|null */ + private $codeBuilderOverrideUri; /** @var bool */ private $hasQuiz; - public static function create(string $codeBuilderDefaultUri, bool $hasQuiz) : self{ + public static function create(string $codeBuilderDefaultUri, string $codeBuilderTitle, bool $canResizeCodeBuilder, ?string $codeBuilderOverrideUri, bool $hasQuiz) : self{ $result = new self; $result->codeBuilderDefaultUri = $codeBuilderDefaultUri; + $result->codeBuilderTitle = $codeBuilderTitle; + $result->canResizeCodeBuilder = $canResizeCodeBuilder; + $result->codeBuilderOverrideUri = $codeBuilderOverrideUri; $result->hasQuiz = $hasQuiz; return $result; } @@ -46,17 +55,42 @@ class EducationSettingsPacket extends DataPacket implements ClientboundPacket{ return $this->codeBuilderDefaultUri; } + public function getCodeBuilderTitle() : string{ + return $this->codeBuilderTitle; + } + + public function canResizeCodeBuilder() : bool{ + return $this->canResizeCodeBuilder; + } + + public function getCodeBuilderOverrideUri() : ?string{ + return $this->codeBuilderOverrideUri; + } + public function getHasQuiz() : bool{ return $this->hasQuiz; } protected function decodePayload(PacketSerializer $in) : void{ $this->codeBuilderDefaultUri = $in->getString(); + $this->codeBuilderTitle = $in->getString(); + $this->canResizeCodeBuilder = $in->getBool(); + if($in->getBool()){ + $this->codeBuilderOverrideUri = $in->getString(); + }else{ + $this->codeBuilderOverrideUri = null; + } $this->hasQuiz = $in->getBool(); } protected function encodePayload(PacketSerializer $out) : void{ $out->putString($this->codeBuilderDefaultUri); + $out->putString($this->codeBuilderTitle); + $out->putBool($this->canResizeCodeBuilder); + $out->putBool($this->codeBuilderOverrideUri !== null); + if($this->codeBuilderOverrideUri !== null){ + $out->putString($this->codeBuilderOverrideUri); + } $out->putBool($this->hasQuiz); } diff --git a/src/network/mcpe/protocol/EmoteListPacket.php b/src/network/mcpe/protocol/EmoteListPacket.php new file mode 100644 index 000000000..107261127 --- /dev/null +++ b/src/network/mcpe/protocol/EmoteListPacket.php @@ -0,0 +1,74 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\uuid\UUID; +use function count; + +class EmoteListPacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::EMOTE_LIST_PACKET; + + /** @var int */ + private $playerEntityRuntimeId; + /** @var UUID[] */ + private $emoteIds; + + /** + * @param UUID[] $emoteIds + */ + public static function create(int $playerEntityRuntimeId, array $emoteIds) : self{ + $result = new self; + $result->playerEntityRuntimeId = $playerEntityRuntimeId; + $result->emoteIds = $emoteIds; + return $result; + } + + public function getPlayerEntityRuntimeId() : int{ return $this->playerEntityRuntimeId; } + + /** @return UUID[] */ + public function getEmoteIds() : array{ return $this->emoteIds; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->playerEntityRuntimeId = $in->getEntityRuntimeId(); + $this->emoteIds = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->emoteIds[] = $in->getUUID(); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putEntityRuntimeId($this->playerEntityRuntimeId); + $out->putUnsignedVarInt(count($this->emoteIds)); + foreach($this->emoteIds as $emoteId){ + $out->putUUID($emoteId); + } + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleEmoteList($this); + } +} diff --git a/src/network/mcpe/protocol/HurtArmorPacket.php b/src/network/mcpe/protocol/HurtArmorPacket.php index e01d908b6..661fbb105 100644 --- a/src/network/mcpe/protocol/HurtArmorPacket.php +++ b/src/network/mcpe/protocol/HurtArmorPacket.php @@ -30,14 +30,18 @@ use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; class HurtArmorPacket extends DataPacket implements ClientboundPacket{ public const NETWORK_ID = ProtocolInfo::HURT_ARMOR_PACKET; + /** @var int */ + public $cause; /** @var int */ public $health; protected function decodePayload(PacketSerializer $in) : void{ + $this->cause = $in->getVarInt(); $this->health = $in->getVarInt(); } protected function encodePayload(PacketSerializer $out) : void{ + $out->putVarInt($this->cause); $out->putVarInt($this->health); } diff --git a/src/network/mcpe/protocol/InventoryContentPacket.php b/src/network/mcpe/protocol/InventoryContentPacket.php index 67a576d69..435f8ac15 100644 --- a/src/network/mcpe/protocol/InventoryContentPacket.php +++ b/src/network/mcpe/protocol/InventoryContentPacket.php @@ -26,7 +26,7 @@ namespace pocketmine\network\mcpe\protocol; #include use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; -use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; +use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; use function count; class InventoryContentPacket extends DataPacket implements ClientboundPacket{ @@ -34,11 +34,11 @@ class InventoryContentPacket extends DataPacket implements ClientboundPacket{ /** @var int */ public $windowId; - /** @var ItemStack[] */ + /** @var ItemStackWrapper[] */ public $items = []; /** - * @param ItemStack[] $items + * @param ItemStackWrapper[] $items * * @return InventoryContentPacket */ @@ -53,7 +53,7 @@ class InventoryContentPacket extends DataPacket implements ClientboundPacket{ $this->windowId = $in->getUnsignedVarInt(); $count = $in->getUnsignedVarInt(); for($i = 0; $i < $count; ++$i){ - $this->items[] = $in->getSlot(); + $this->items[] = ItemStackWrapper::read($in); } } @@ -61,7 +61,7 @@ class InventoryContentPacket extends DataPacket implements ClientboundPacket{ $out->putUnsignedVarInt($this->windowId); $out->putUnsignedVarInt(count($this->items)); foreach($this->items as $item){ - $out->putSlot($item); + $item->write($out); } } diff --git a/src/network/mcpe/protocol/InventorySlotPacket.php b/src/network/mcpe/protocol/InventorySlotPacket.php index 86b071d0f..59708dd79 100644 --- a/src/network/mcpe/protocol/InventorySlotPacket.php +++ b/src/network/mcpe/protocol/InventorySlotPacket.php @@ -26,7 +26,7 @@ namespace pocketmine\network\mcpe\protocol; #include use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; -use pocketmine\network\mcpe\protocol\types\inventory\ItemStack; +use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper; class InventorySlotPacket extends DataPacket implements ClientboundPacket{ public const NETWORK_ID = ProtocolInfo::INVENTORY_SLOT_PACKET; @@ -35,10 +35,10 @@ class InventorySlotPacket extends DataPacket implements ClientboundPacket{ public $windowId; /** @var int */ public $inventorySlot; - /** @var ItemStack */ + /** @var ItemStackWrapper */ public $item; - public static function create(int $windowId, int $slot, ItemStack $item) : self{ + public static function create(int $windowId, int $slot, ItemStackWrapper $item) : self{ $result = new self; $result->inventorySlot = $slot; $result->item = $item; @@ -50,13 +50,13 @@ class InventorySlotPacket extends DataPacket implements ClientboundPacket{ protected function decodePayload(PacketSerializer $in) : void{ $this->windowId = $in->getUnsignedVarInt(); $this->inventorySlot = $in->getUnsignedVarInt(); - $this->item = $in->getSlot(); + $this->item = ItemStackWrapper::read($in); } protected function encodePayload(PacketSerializer $out) : void{ $out->putUnsignedVarInt($this->windowId); $out->putUnsignedVarInt($this->inventorySlot); - $out->putSlot($this->item); + $this->item->write($out); } public function handle(PacketHandlerInterface $handler) : bool{ diff --git a/src/network/mcpe/protocol/InventoryTransactionPacket.php b/src/network/mcpe/protocol/InventoryTransactionPacket.php index 3959f0542..020af1c5f 100644 --- a/src/network/mcpe/protocol/InventoryTransactionPacket.php +++ b/src/network/mcpe/protocol/InventoryTransactionPacket.php @@ -26,12 +26,14 @@ namespace pocketmine\network\mcpe\protocol; #include use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\inventory\InventoryTransactionChangedSlotsHack; use pocketmine\network\mcpe\protocol\types\inventory\MismatchTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\NormalTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\ReleaseItemTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\TransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemOnEntityTransactionData; use pocketmine\network\mcpe\protocol\types\inventory\UseItemTransactionData; +use function count; /** * This packet effectively crams multiple packets into one. @@ -45,12 +47,28 @@ class InventoryTransactionPacket extends DataPacket implements ClientboundPacket public const TYPE_USE_ITEM_ON_ENTITY = 3; public const TYPE_RELEASE_ITEM = 4; + /** @var int */ + public $requestId; + /** @var InventoryTransactionChangedSlotsHack[] */ + public $requestChangedSlots; + /** @var bool */ + public $hasItemStackIds; /** @var TransactionData */ public $trData; protected function decodePayload(PacketSerializer $in) : void{ + $this->requestId = $in->readGenericTypeNetworkId(); + $this->requestChangedSlots = []; + if($this->requestId !== 0){ + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($in); + } + } + $transactionType = $in->getUnsignedVarInt(); + $this->hasItemStackIds = $in->getBool(); + switch($transactionType){ case self::TYPE_NORMAL: $this->trData = new NormalTransactionData(); @@ -71,12 +89,23 @@ class InventoryTransactionPacket extends DataPacket implements ClientboundPacket throw new PacketDecodeException("Unknown transaction type $transactionType"); } - $this->trData->decode($in); + $this->trData->decode($in, $this->hasItemStackIds); } protected function encodePayload(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->requestId); + if($this->requestId !== 0){ + $out->putUnsignedVarInt(count($this->requestChangedSlots)); + foreach($this->requestChangedSlots as $changedSlots){ + $changedSlots->write($out); + } + } + $out->putUnsignedVarInt($this->trData->getTypeId()); - $this->trData->encode($out); + + $out->putBool($this->hasItemStackIds); + + $this->trData->encode($out, $this->hasItemStackIds); } public function handle(PacketHandlerInterface $handler) : bool{ diff --git a/src/network/mcpe/protocol/ItemStackRequestPacket.php b/src/network/mcpe/protocol/ItemStackRequestPacket.php new file mode 100644 index 000000000..8a9a6e541 --- /dev/null +++ b/src/network/mcpe/protocol/ItemStackRequestPacket.php @@ -0,0 +1,67 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\inventory\stackrequest\ItemStackRequest; +use function count; + +class ItemStackRequestPacket extends DataPacket implements ServerboundPacket{ + public const NETWORK_ID = ProtocolInfo::ITEM_STACK_REQUEST_PACKET; + + /** @var ItemStackRequest[] */ + private $requests; + + /** + * @param ItemStackRequest[] $requests + */ + public static function create(array $requests) : self{ + $result = new self; + $result->requests = $requests; + return $result; + } + + /** @return ItemStackRequest[] */ + public function getRequests() : array{ return $this->requests; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->requests = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->requests[] = ItemStackRequest::read($in); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putUnsignedVarInt(count($this->requests)); + foreach($this->requests as $request){ + $request->write($out); + } + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleItemStackRequest($this); + } +} diff --git a/src/network/mcpe/protocol/ItemStackResponsePacket.php b/src/network/mcpe/protocol/ItemStackResponsePacket.php new file mode 100644 index 000000000..07a54517d --- /dev/null +++ b/src/network/mcpe/protocol/ItemStackResponsePacket.php @@ -0,0 +1,67 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\inventory\stackresponse\ItemStackResponse; +use function count; + +class ItemStackResponsePacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::ITEM_STACK_RESPONSE_PACKET; + + /** @var ItemStackResponse[] */ + private $responses; + + /** + * @param ItemStackResponse[] $responses + */ + public static function create(array $responses) : self{ + $result = new self; + $result->responses = $responses; + return $result; + } + + /** @return ItemStackResponse[] */ + public function getResponses() : array{ return $this->responses; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->responses = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->responses[] = ItemStackResponse::read($in); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putUnsignedVarInt(count($this->responses)); + foreach($this->responses as $response){ + $response->write($out); + } + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleItemStackResponse($this); + } +} diff --git a/src/network/mcpe/protocol/PacketHandlerInterface.php b/src/network/mcpe/protocol/PacketHandlerInterface.php index 730824d37..3aa5a840b 100644 --- a/src/network/mcpe/protocol/PacketHandlerInterface.php +++ b/src/network/mcpe/protocol/PacketHandlerInterface.php @@ -273,8 +273,6 @@ interface PacketHandlerInterface{ public function handleLecternUpdate(LecternUpdatePacket $packet) : bool; - public function handleVideoStreamConnect(VideoStreamConnectPacket $packet) : bool; - public function handleAddEntity(AddEntityPacket $packet) : bool; public function handleRemoveEntity(RemoveEntityPacket $packet) : bool; @@ -310,4 +308,28 @@ interface PacketHandlerInterface{ public function handleNetworkSettings(NetworkSettingsPacket $packet) : bool; public function handlePlayerAuthInput(PlayerAuthInputPacket $packet) : bool; -} \ No newline at end of file + + public function handleCreativeContent(CreativeContentPacket $packet) : bool; + + public function handlePlayerEnchantOptions(PlayerEnchantOptionsPacket $packet) : bool; + + public function handleItemStackRequest(ItemStackRequestPacket $packet) : bool; + + public function handleItemStackResponse(ItemStackResponsePacket $packet) : bool; + + public function handlePlayerArmorDamage(PlayerArmorDamagePacket $packet) : bool; + + public function handleCodeBuilder(CodeBuilderPacket $packet) : bool; + + public function handleUpdatePlayerGameType(UpdatePlayerGameTypePacket $packet) : bool; + + public function handleEmoteList(EmoteListPacket $packet) : bool; + + public function handlePositionTrackingDBServerBroadcast(PositionTrackingDBServerBroadcastPacket $packet) : bool; + + public function handlePositionTrackingDBClientRequest(PositionTrackingDBClientRequestPacket $packet) : bool; + + public function handleDebugInfo(DebugInfoPacket $packet) : bool; + + public function handlePacketViolationWarning(PacketViolationWarningPacket $packet) : bool; +} diff --git a/src/network/mcpe/protocol/PacketPool.php b/src/network/mcpe/protocol/PacketPool.php index 14abe765f..493a26415 100644 --- a/src/network/mcpe/protocol/PacketPool.php +++ b/src/network/mcpe/protocol/PacketPool.php @@ -166,7 +166,6 @@ class PacketPool{ $this->registerPacket(new LevelSoundEventPacket()); $this->registerPacket(new LevelEventGenericPacket()); $this->registerPacket(new LecternUpdatePacket()); - $this->registerPacket(new VideoStreamConnectPacket()); $this->registerPacket(new AddEntityPacket()); $this->registerPacket(new RemoveEntityPacket()); $this->registerPacket(new ClientCacheStatusPacket()); @@ -185,6 +184,18 @@ class PacketPool{ $this->registerPacket(new CompletedUsingItemPacket()); $this->registerPacket(new NetworkSettingsPacket()); $this->registerPacket(new PlayerAuthInputPacket()); + $this->registerPacket(new CreativeContentPacket()); + $this->registerPacket(new PlayerEnchantOptionsPacket()); + $this->registerPacket(new ItemStackRequestPacket()); + $this->registerPacket(new ItemStackResponsePacket()); + $this->registerPacket(new PlayerArmorDamagePacket()); + $this->registerPacket(new CodeBuilderPacket()); + $this->registerPacket(new UpdatePlayerGameTypePacket()); + $this->registerPacket(new EmoteListPacket()); + $this->registerPacket(new PositionTrackingDBServerBroadcastPacket()); + $this->registerPacket(new PositionTrackingDBClientRequestPacket()); + $this->registerPacket(new DebugInfoPacket()); + $this->registerPacket(new PacketViolationWarningPacket()); } public function registerPacket(Packet $packet) : void{ diff --git a/src/network/mcpe/protocol/PacketViolationWarningPacket.php b/src/network/mcpe/protocol/PacketViolationWarningPacket.php new file mode 100644 index 000000000..c100647ce --- /dev/null +++ b/src/network/mcpe/protocol/PacketViolationWarningPacket.php @@ -0,0 +1,84 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; + +class PacketViolationWarningPacket extends DataPacket implements ServerboundPacket{ + public const NETWORK_ID = ProtocolInfo::PACKET_VIOLATION_WARNING_PACKET; + + public const TYPE_MALFORMED = 0; + + public const SEVERITY_WARNING = 0; + public const SEVERITY_FINAL_WARNING = 1; + public const SEVERITY_TERMINATING_CONNECTION = 2; + + /** @var int */ + private $type; + /** @var int */ + private $severity; + /** @var int */ + private $packetId; + /** @var string */ + private $message; + + public static function create(int $type, int $severity, int $packetId, string $message) : self{ + $result = new self; + + $result->type = $type; + $result->severity = $severity; + $result->packetId = $packetId; + $result->message = $message; + + return $result; + } + + public function getType() : int{ return $this->type; } + + public function getSeverity() : int{ return $this->severity; } + + public function getPacketId() : int{ return $this->packetId; } + + public function getMessage() : string{ return $this->message; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->type = $in->getVarInt(); + $this->severity = $in->getVarInt(); + $this->packetId = $in->getVarInt(); + $this->message = $in->getString(); + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putVarInt($this->type); + $out->putVarInt($this->severity); + $out->putVarInt($this->packetId); + $out->putString($this->message); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handlePacketViolationWarning($this); + } +} diff --git a/src/network/mcpe/protocol/PlayerActionPacket.php b/src/network/mcpe/protocol/PlayerActionPacket.php index d34a10c67..081510908 100644 --- a/src/network/mcpe/protocol/PlayerActionPacket.php +++ b/src/network/mcpe/protocol/PlayerActionPacket.php @@ -50,7 +50,7 @@ class PlayerActionPacket extends DataPacket implements ServerboundPacket{ public const ACTION_BUILD_DENIED = 17; public const ACTION_CONTINUE_BREAK = 18; public const ACTION_CHANGE_SKIN = 19; - public const ACTION_SET_ENCHANTMENT_SEED = 20; + public const ACTION_SET_ENCHANTMENT_SEED = 20; //no longer used public const ACTION_START_SWIMMING = 21; public const ACTION_STOP_SWIMMING = 22; public const ACTION_START_SPIN_ATTACK = 23; diff --git a/src/network/mcpe/protocol/PlayerArmorDamagePacket.php b/src/network/mcpe/protocol/PlayerArmorDamagePacket.php new file mode 100644 index 000000000..748084c61 --- /dev/null +++ b/src/network/mcpe/protocol/PlayerArmorDamagePacket.php @@ -0,0 +1,108 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; + +class PlayerArmorDamagePacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::PLAYER_ARMOR_DAMAGE_PACKET; + + private const FLAG_HEAD = 0; + private const FLAG_CHEST = 1; + private const FLAG_LEGS = 2; + private const FLAG_FEET = 3; + + /** @var int|null */ + private $headSlotDamage; + /** @var int|null */ + private $chestSlotDamage; + /** @var int|null */ + private $legsSlotDamage; + /** @var int|null */ + private $feetSlotDamage; + + public static function create(?int $headSlotDamage, ?int $chestSlotDamage, ?int $legsSlotDamage, ?int $feetSlotDamage) : self{ + $result = new self; + $result->headSlotDamage = $headSlotDamage; + $result->chestSlotDamage = $chestSlotDamage; + $result->legsSlotDamage = $legsSlotDamage; + $result->feetSlotDamage = $feetSlotDamage; + + return $result; + } + + public function getHeadSlotDamage() : ?int{ return $this->headSlotDamage; } + + public function getChestSlotDamage() : ?int{ return $this->chestSlotDamage; } + + public function getLegsSlotDamage() : ?int{ return $this->legsSlotDamage; } + + public function getFeetSlotDamage() : ?int{ return $this->feetSlotDamage; } + + private function maybeReadDamage(int $flags, int $flag, PacketSerializer $in) : ?int{ + if(($flags & (1 << $flag)) !== 0){ + return $in->getVarInt(); + } + return null; + } + + protected function decodePayload(PacketSerializer $in) : void{ + $flags = $in->getByte(); + + $this->headSlotDamage = $this->maybeReadDamage($flags, self::FLAG_HEAD, $in); + $this->chestSlotDamage = $this->maybeReadDamage($flags, self::FLAG_CHEST, $in); + $this->legsSlotDamage = $this->maybeReadDamage($flags, self::FLAG_LEGS, $in); + $this->feetSlotDamage = $this->maybeReadDamage($flags, self::FLAG_FEET, $in); + } + + private function composeFlag(?int $field, int $flag) : int{ + return $field !== null ? (1 << $flag) : 0; + } + + private function maybeWriteDamage(?int $field, PacketSerializer $out) : void{ + if($field !== null){ + $out->putVarInt($field); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putByte( + $this->composeFlag($this->headSlotDamage, self::FLAG_HEAD) | + $this->composeFlag($this->chestSlotDamage, self::FLAG_CHEST) | + $this->composeFlag($this->legsSlotDamage, self::FLAG_LEGS) | + $this->composeFlag($this->feetSlotDamage, self::FLAG_FEET) + ); + + $this->maybeWriteDamage($this->headSlotDamage, $out); + $this->maybeWriteDamage($this->chestSlotDamage, $out); + $this->maybeWriteDamage($this->legsSlotDamage, $out); + $this->maybeWriteDamage($this->feetSlotDamage, $out); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handlePlayerArmorDamage($this); + } +} diff --git a/src/network/mcpe/protocol/PlayerEnchantOptionsPacket.php b/src/network/mcpe/protocol/PlayerEnchantOptionsPacket.php new file mode 100644 index 000000000..d7efbd7c4 --- /dev/null +++ b/src/network/mcpe/protocol/PlayerEnchantOptionsPacket.php @@ -0,0 +1,69 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\EnchantOption; +use function count; + +class PlayerEnchantOptionsPacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::PLAYER_ENCHANT_OPTIONS_PACKET; + + /** @var EnchantOption[] */ + private $options; + + /** + * @param EnchantOption[] $options + */ + public static function create(array $options) : self{ + $result = new self; + $result->options = $options; + return $result; + } + + /** + * @return EnchantOption[] + */ + public function getOptions() : array{ return $this->options; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->options = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $this->options[] = EnchantOption::read($in); + } + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putUnsignedVarInt(count($this->options)); + foreach($this->options as $option){ + $option->write($out); + } + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handlePlayerEnchantOptions($this); + } +} diff --git a/src/network/mcpe/protocol/VideoStreamConnectPacket.php b/src/network/mcpe/protocol/PositionTrackingDBClientRequestPacket.php similarity index 60% rename from src/network/mcpe/protocol/VideoStreamConnectPacket.php rename to src/network/mcpe/protocol/PositionTrackingDBClientRequestPacket.php index 06954c94a..f5a6a13f7 100644 --- a/src/network/mcpe/protocol/VideoStreamConnectPacket.php +++ b/src/network/mcpe/protocol/PositionTrackingDBClientRequestPacket.php @@ -27,40 +27,38 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; -class VideoStreamConnectPacket extends DataPacket implements ClientboundPacket{ - public const NETWORK_ID = ProtocolInfo::VIDEO_STREAM_CONNECT_PACKET; +class PositionTrackingDBClientRequestPacket extends DataPacket implements ServerboundPacket{ + public const NETWORK_ID = ProtocolInfo::POSITION_TRACKING_D_B_CLIENT_REQUEST_PACKET; - public const ACTION_CONNECT = 0; - public const ACTION_DISCONNECT = 1; + public const ACTION_QUERY = 0; - /** @var string */ - public $serverUri; - /** @var float */ - public $frameSendFrequency; /** @var int */ - public $action; + private $action; /** @var int */ - public $resolutionX; - /** @var int */ - public $resolutionY; + private $trackingId; + + public static function create(int $action, int $trackingId) : self{ + $result = new self; + $result->action = $action; + $result->trackingId = $trackingId; + return $result; + } + + public function getAction() : int{ return $this->action; } + + public function getTrackingId() : int{ return $this->trackingId; } protected function decodePayload(PacketSerializer $in) : void{ - $this->serverUri = $in->getString(); - $this->frameSendFrequency = $in->getLFloat(); $this->action = $in->getByte(); - $this->resolutionX = $in->getLInt(); - $this->resolutionY = $in->getLInt(); + $this->trackingId = $in->getVarInt(); } protected function encodePayload(PacketSerializer $out) : void{ - $out->putString($this->serverUri); - $out->putLFloat($this->frameSendFrequency); $out->putByte($this->action); - $out->putLInt($this->resolutionX); - $out->putLInt($this->resolutionY); + $out->putVarInt($this->trackingId); } public function handle(PacketHandlerInterface $handler) : bool{ - return $handler->handleVideoStreamConnect($this); + return $handler->handlePositionTrackingDBClientRequest($this); } } diff --git a/src/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php b/src/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php new file mode 100644 index 000000000..7045643bc --- /dev/null +++ b/src/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php @@ -0,0 +1,81 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\CacheableNbt; + +class PositionTrackingDBServerBroadcastPacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::POSITION_TRACKING_D_B_SERVER_BROADCAST_PACKET; + + public const ACTION_UPDATE = 0; + public const ACTION_DESTROY = 1; + public const ACTION_NOT_FOUND = 2; + + /** @var int */ + private $action; + /** @var int */ + private $trackingId; + /** + * @var CacheableNbt + * @phpstan-var CacheableNbt<\pocketmine\nbt\tag\CompoundTag> + */ + private $nbt; + + /** + * @phpstan-param CacheableNbt<\pocketmine\nbt\tag\CompoundTag> $nbt + */ + public static function create(int $action, int $trackingId, CacheableNbt $nbt) : self{ + $result = new self; + $result->action = $action; + $result->trackingId = $trackingId; + $result->nbt = $nbt; + return $result; + } + + public function getAction() : int{ return $this->action; } + + public function getTrackingId() : int{ return $this->trackingId; } + + /** @phpstan-return CacheableNbt<\pocketmine\nbt\tag\CompoundTag> */ + public function getNbt() : CacheableNbt{ return $this->nbt; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->action = $in->getByte(); + $this->trackingId = $in->getVarInt(); + $this->nbt = new CacheableNbt($in->getNbtCompoundRoot()); + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putByte($this->action); + $out->putVarInt($this->trackingId); + $out->put($this->nbt->getEncodedNbt()); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handlePositionTrackingDBServerBroadcast($this); + } +} diff --git a/src/network/mcpe/protocol/ProtocolInfo.php b/src/network/mcpe/protocol/ProtocolInfo.php index f01e3e4ae..f815628db 100644 --- a/src/network/mcpe/protocol/ProtocolInfo.php +++ b/src/network/mcpe/protocol/ProtocolInfo.php @@ -41,11 +41,11 @@ final class ProtocolInfo{ */ /** Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 390; + public const CURRENT_PROTOCOL = 407; /** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.14.60'; + public const MINECRAFT_VERSION = 'v1.16.0.67 beta'; /** Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.14.60'; + public const MINECRAFT_VERSION_NETWORK = '1.16.0.67'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; @@ -172,7 +172,7 @@ final class ProtocolInfo{ public const LEVEL_SOUND_EVENT_PACKET = 0x7b; public const LEVEL_EVENT_GENERIC_PACKET = 0x7c; public const LECTERN_UPDATE_PACKET = 0x7d; - public const VIDEO_STREAM_CONNECT_PACKET = 0x7e; + public const ADD_ENTITY_PACKET = 0x7f; public const REMOVE_ENTITY_PACKET = 0x80; public const CLIENT_CACHE_STATUS_PACKET = 0x81; @@ -191,5 +191,17 @@ final class ProtocolInfo{ public const COMPLETED_USING_ITEM_PACKET = 0x8e; public const NETWORK_SETTINGS_PACKET = 0x8f; public const PLAYER_AUTH_INPUT_PACKET = 0x90; + public const CREATIVE_CONTENT_PACKET = 0x91; + public const PLAYER_ENCHANT_OPTIONS_PACKET = 0x92; + public const ITEM_STACK_REQUEST_PACKET = 0x93; + public const ITEM_STACK_RESPONSE_PACKET = 0x94; + public const PLAYER_ARMOR_DAMAGE_PACKET = 0x95; + public const CODE_BUILDER_PACKET = 0x96; + public const UPDATE_PLAYER_GAME_TYPE_PACKET = 0x97; + public const EMOTE_LIST_PACKET = 0x98; + public const POSITION_TRACKING_D_B_SERVER_BROADCAST_PACKET = 0x99; + public const POSITION_TRACKING_D_B_CLIENT_REQUEST_PACKET = 0x9a; + public const DEBUG_INFO_PACKET = 0x9b; + public const PACKET_VIOLATION_WARNING_PACKET = 0x9c; } diff --git a/src/network/mcpe/protocol/SetSpawnPositionPacket.php b/src/network/mcpe/protocol/SetSpawnPositionPacket.php index d8c0c6044..a1cffc88f 100644 --- a/src/network/mcpe/protocol/SetSpawnPositionPacket.php +++ b/src/network/mcpe/protocol/SetSpawnPositionPacket.php @@ -41,34 +41,45 @@ class SetSpawnPositionPacket extends DataPacket implements ClientboundPacket{ public $y; /** @var int */ public $z; - /** @var bool */ - public $spawnForced; + /** @var int */ + public $dimension; + /** @var int */ + public $x2; + /** @var int */ + public $y2; + /** @var int */ + public $z2; - public static function playerSpawn(int $x, int $y, int $z, bool $forced) : self{ + public static function playerSpawn(int $x, int $y, int $z, int $dimension, int $x2, int $y2, int $z2) : self{ $result = new self; $result->spawnType = self::TYPE_PLAYER_SPAWN; [$result->x, $result->y, $result->z] = [$x, $y, $z]; - $result->spawnForced = $forced; + [$result->x2, $result->y2, $result->z2] = [$x2, $y2, $z2]; + $result->dimension = $dimension; return $result; } - public static function worldSpawn(int $x, int $y, int $z) : self{ + public static function worldSpawn(int $x, int $y, int $z, int $dimension) : self{ $result = new self; $result->spawnType = self::TYPE_WORLD_SPAWN; [$result->x, $result->y, $result->z] = [$x, $y, $z]; + [$result->x2, $result->y2, $result->z2] = [$x, $y, $z]; + $result->dimension = $dimension; return $result; } protected function decodePayload(PacketSerializer $in) : void{ $this->spawnType = $in->getVarInt(); $in->getBlockPosition($this->x, $this->y, $this->z); - $this->spawnForced = $in->getBool(); + $this->dimension = $in->getVarInt(); + $in->getBlockPosition($this->x2, $this->y2, $this->z2); } protected function encodePayload(PacketSerializer $out) : void{ $out->putVarInt($this->spawnType); $out->putBlockPosition($this->x, $this->y, $this->z); - $out->putBool($this->spawnForced); + $out->putVarInt($this->dimension); + $out->putBlockPosition($this->x2, $this->y2, $this->z2); } public function handle(PacketHandlerInterface $handler) : bool{ diff --git a/src/network/mcpe/protocol/StartGamePacket.php b/src/network/mcpe/protocol/StartGamePacket.php index 809214dbb..6babff17c 100644 --- a/src/network/mcpe/protocol/StartGamePacket.php +++ b/src/network/mcpe/protocol/StartGamePacket.php @@ -34,6 +34,7 @@ use pocketmine\network\mcpe\protocol\types\GameRule; use pocketmine\network\mcpe\protocol\types\GeneratorType; use pocketmine\network\mcpe\protocol\types\MultiplayerGameVisibility; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; +use pocketmine\network\mcpe\protocol\types\SpawnSettings; use function count; class StartGamePacket extends DataPacket implements ClientboundPacket{ @@ -56,8 +57,8 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ /** @var int */ public $seed; - /** @var int */ - public $dimension; + /** @var SpawnSettings */ + public $spawnSettings; /** @var int */ public $generator = GeneratorType::OVERWORLD; /** @var int */ @@ -78,6 +79,8 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ public $eduEditionOffer = EducationEditionOffer::NONE; /** @var bool */ public $hasEduFeaturesEnabled = false; + /** @var string */ + public $eduProductUUID = ""; /** @var float */ public $rainLevel; /** @var float */ @@ -125,9 +128,17 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ public $isWorldTemplateOptionLocked = false; /** @var bool */ public $onlySpawnV1Villagers = false; - /** @var string */ public $vanillaVersion = ProtocolInfo::MINECRAFT_VERSION_NETWORK; + /** @var int */ + public $limitedWorldWidth = 0; + /** @var int */ + public $limitedWorldLength = 0; + /** @var bool */ + public $isNewNether = true; + /** @var bool|null */ + public $experimentalGameplayOverride = null; + /** @var string */ public $levelId = ""; //base64 string, usually the same as world folder name in vanilla /** @var string */ @@ -144,6 +155,8 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ public $enchantmentSeed = 0; /** @var string */ public $multiplayerCorrelationId = ""; //TODO: this should be filled with a UUID of some sort + /** @var bool */ + public $enableNewInventorySystem = false; //TODO /** * @var CacheableNbt @@ -168,7 +181,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ //Level settings $this->seed = $in->getVarInt(); - $this->dimension = $in->getVarInt(); + $this->spawnSettings = SpawnSettings::read($in); $this->generator = $in->getVarInt(); $this->worldGamemode = $in->getVarInt(); $this->difficulty = $in->getVarInt(); @@ -177,6 +190,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $this->time = $in->getVarInt(); $this->eduEditionOffer = $in->getVarInt(); $this->hasEduFeaturesEnabled = $in->getBool(); + $this->eduProductUUID = $in->getString(); $this->rainLevel = $in->getLFloat(); $this->lightningLevel = $in->getLFloat(); $this->hasConfirmedPlatformLockedContent = $in->getBool(); @@ -198,8 +212,16 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $this->isFromWorldTemplate = $in->getBool(); $this->isWorldTemplateOptionLocked = $in->getBool(); $this->onlySpawnV1Villagers = $in->getBool(); - $this->vanillaVersion = $in->getString(); + $this->limitedWorldWidth = $in->getLInt(); + $this->limitedWorldLength = $in->getLInt(); + $this->isNewNether = $in->getBool(); + if($in->getBool()){ + $this->experimentalGameplayOverride = $in->getBool(); + }else{ + $this->experimentalGameplayOverride = null; + } + $this->levelId = $in->getString(); $this->worldName = $in->getString(); $this->premiumWorldTemplateId = $in->getString(); @@ -224,6 +246,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ } $this->multiplayerCorrelationId = $in->getString(); + $this->enableNewInventorySystem = $in->getBool(); } protected function encodePayload(PacketSerializer $out) : void{ @@ -238,7 +261,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ //Level settings $out->putVarInt($this->seed); - $out->putVarInt($this->dimension); + $this->spawnSettings->write($out); $out->putVarInt($this->generator); $out->putVarInt($this->worldGamemode); $out->putVarInt($this->difficulty); @@ -247,6 +270,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $out->putVarInt($this->time); $out->putVarInt($this->eduEditionOffer); $out->putBool($this->hasEduFeaturesEnabled); + $out->putString($this->eduProductUUID); $out->putLFloat($this->rainLevel); $out->putLFloat($this->lightningLevel); $out->putBool($this->hasConfirmedPlatformLockedContent); @@ -268,8 +292,15 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $out->putBool($this->isFromWorldTemplate); $out->putBool($this->isWorldTemplateOptionLocked); $out->putBool($this->onlySpawnV1Villagers); - $out->putString($this->vanillaVersion); + $out->putLInt($this->limitedWorldWidth); + $out->putLInt($this->limitedWorldLength); + $out->putBool($this->isNewNether); + $out->putBool($this->experimentalGameplayOverride !== null); + if($this->experimentalGameplayOverride !== null){ + $out->putBool($this->experimentalGameplayOverride); + } + $out->putString($this->levelId); $out->putString($this->worldName); $out->putString($this->premiumWorldTemplateId); @@ -284,6 +315,7 @@ class StartGamePacket extends DataPacket implements ClientboundPacket{ $out->put(self::serializeItemTable($this->itemTable)); $out->putString($this->multiplayerCorrelationId); + $out->putBool($this->enableNewInventorySystem); } /** diff --git a/src/network/mcpe/protocol/TextPacket.php b/src/network/mcpe/protocol/TextPacket.php index ed10825f0..1928e40ca 100644 --- a/src/network/mcpe/protocol/TextPacket.php +++ b/src/network/mcpe/protocol/TextPacket.php @@ -40,7 +40,8 @@ class TextPacket extends DataPacket implements ClientboundPacket, ServerboundPac public const TYPE_SYSTEM = 6; public const TYPE_WHISPER = 7; public const TYPE_ANNOUNCEMENT = 8; - public const TYPE_JSON = 9; + public const TYPE_JSON_WHISPER = 9; + public const TYPE_JSON = 10; /** @var int */ public $type; @@ -127,6 +128,7 @@ class TextPacket extends DataPacket implements ClientboundPacket, ServerboundPac case self::TYPE_RAW: case self::TYPE_TIP: case self::TYPE_SYSTEM: + case self::TYPE_JSON_WHISPER: case self::TYPE_JSON: $this->message = $in->getString(); break; @@ -158,6 +160,7 @@ class TextPacket extends DataPacket implements ClientboundPacket, ServerboundPac case self::TYPE_RAW: case self::TYPE_TIP: case self::TYPE_SYSTEM: + case self::TYPE_JSON_WHISPER: case self::TYPE_JSON: $out->putString($this->message); break; diff --git a/src/network/mcpe/protocol/UpdatePlayerGameTypePacket.php b/src/network/mcpe/protocol/UpdatePlayerGameTypePacket.php new file mode 100644 index 000000000..a190de79f --- /dev/null +++ b/src/network/mcpe/protocol/UpdatePlayerGameTypePacket.php @@ -0,0 +1,67 @@ + + +use pocketmine\network\mcpe\protocol\serializer\PacketSerializer; +use pocketmine\network\mcpe\protocol\types\GameMode; + +class UpdatePlayerGameTypePacket extends DataPacket implements ClientboundPacket{ + public const NETWORK_ID = ProtocolInfo::UPDATE_PLAYER_GAME_TYPE_PACKET; + + /** + * @var int + * @see GameMode + */ + private $gameMode; + + /** @var int */ + private $playerEntityUniqueId; + + public static function create(int $gameMode, int $playerEntityUniqueId) : self{ + $result = new self; + $result->gameMode = $gameMode; + $result->playerEntityUniqueId = $playerEntityUniqueId; + return $result; + } + + public function getGameMode() : int{ return $this->gameMode; } + + public function getPlayerEntityUniqueId() : int{ return $this->playerEntityUniqueId; } + + protected function decodePayload(PacketSerializer $in) : void{ + $this->gameMode = $in->getVarInt(); + $this->playerEntityUniqueId = $in->getEntityUniqueId(); + } + + protected function encodePayload(PacketSerializer $out) : void{ + $out->putVarInt($this->gameMode); + $out->putEntityUniqueId($this->playerEntityUniqueId); + } + + public function handle(PacketHandlerInterface $handler) : bool{ + return $handler->handleUpdatePlayerGameType($this); + } +} diff --git a/src/network/mcpe/protocol/serializer/PacketSerializer.php b/src/network/mcpe/protocol/serializer/PacketSerializer.php index 6138b45df..1efd9fecb 100644 --- a/src/network/mcpe/protocol/serializer/PacketSerializer.php +++ b/src/network/mcpe/protocol/serializer/PacketSerializer.php @@ -412,7 +412,7 @@ class PacketSerializer extends BinaryStream{ * * @throws BinaryDataException */ - public function getEntityUniqueId() : int{ + final public function getEntityUniqueId() : int{ return $this->getVarLong(); } @@ -428,7 +428,7 @@ class PacketSerializer extends BinaryStream{ * * @throws BinaryDataException */ - public function getEntityRuntimeId() : int{ + final public function getEntityRuntimeId() : int{ return $this->getUnsignedVarLong(); } @@ -591,7 +591,8 @@ class PacketSerializer extends BinaryStream{ $toEntityUniqueId = $this->getEntityUniqueId(); $type = $this->getByte(); $immediate = $this->getBool(); - return new EntityLink($fromEntityUniqueId, $toEntityUniqueId, $type, $immediate); + $causedByRider = $this->getBool(); + return new EntityLink($fromEntityUniqueId, $toEntityUniqueId, $type, $immediate, $causedByRider); } public function putEntityLink(EntityLink $link) : void{ @@ -599,6 +600,7 @@ class PacketSerializer extends BinaryStream{ $this->putEntityUniqueId($link->toEntityUniqueId); $this->putByte($link->type); $this->putBool($link->immediate); + $this->putBool($link->causedByRider); } /** @@ -712,4 +714,12 @@ class PacketSerializer extends BinaryStream{ throw PacketDecodeException::wrap($e, "Expected TAG_Compound NBT root"); } } + + public function readGenericTypeNetworkId() : int{ + return $this->getVarInt(); + } + + public function writeGenericTypeNetworkId(int $id) : void{ + $this->putVarInt($id); + } } diff --git a/src/network/mcpe/protocol/types/Enchant.php b/src/network/mcpe/protocol/types/Enchant.php new file mode 100644 index 000000000..451e81e2a --- /dev/null +++ b/src/network/mcpe/protocol/types/Enchant.php @@ -0,0 +1,53 @@ +id = $id; + $this->level = $level; + } + + public function getId() : int{ return $this->id; } + + public function getLevel() : int{ return $this->level; } + + public static function read(PacketSerializer $in) : self{ + $id = $in->getByte(); + $level = $in->getByte(); + return new self($id, $level); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->id); + $out->putByte($this->level); + } +} diff --git a/src/network/mcpe/protocol/types/EnchantOption.php b/src/network/mcpe/protocol/types/EnchantOption.php new file mode 100644 index 000000000..f3aa8b7f0 --- /dev/null +++ b/src/network/mcpe/protocol/types/EnchantOption.php @@ -0,0 +1,126 @@ +cost = $cost; + $this->slotFlags = $slotFlags; + $this->equipActivatedEnchantments = $equipActivatedEnchantments; + $this->heldActivatedEnchantments = $heldActivatedEnchantments; + $this->selfActivatedEnchantments = $selfActivatedEnchantments; + $this->name = $name; + $this->optionId = $optionId; + } + + public function getCost() : int{ return $this->cost; } + + public function getSlotFlags() : int{ return $this->slotFlags; } + + /** @return Enchant[] */ + public function getEquipActivatedEnchantments() : array{ return $this->equipActivatedEnchantments; } + + /** @return Enchant[] */ + public function getHeldActivatedEnchantments() : array{ return $this->heldActivatedEnchantments; } + + /** @return Enchant[] */ + public function getSelfActivatedEnchantments() : array{ return $this->selfActivatedEnchantments; } + + public function getName() : string{ return $this->name; } + + public function getOptionId() : int{ return $this->optionId; } + + /** + * @return Enchant[] + */ + private static function readEnchantList(PacketSerializer $in) : array{ + $result = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $result[] = Enchant::read($in); + } + return $result; + } + + /** + * @param Enchant[] $list + */ + private static function writeEnchantList(PacketSerializer $out, array $list) : void{ + $out->putUnsignedVarInt(count($list)); + foreach($list as $item){ + $item->write($out); + } + } + + public static function read(PacketSerializer $in) : self{ + $cost = $in->getUnsignedVarInt(); + + $slotFlags = $in->getLInt(); + $equipActivatedEnchants = self::readEnchantList($in); + $heldActivatedEnchants = self::readEnchantList($in); + $selfActivatedEnchants = self::readEnchantList($in); + + $name = $in->getString(); + $optionId = $in->readGenericTypeNetworkId(); + + return new self($cost, $slotFlags, $equipActivatedEnchants, $heldActivatedEnchants, $selfActivatedEnchants, $name, $optionId); + } + + public function write(PacketSerializer $out) : void{ + $out->putUnsignedVarInt($this->cost); + + $out->putLInt($this->slotFlags); + self::writeEnchantList($out, $this->equipActivatedEnchantments); + self::writeEnchantList($out, $this->heldActivatedEnchantments); + self::writeEnchantList($out, $this->selfActivatedEnchantments); + + $out->putString($this->name); + $out->writeGenericTypeNetworkId($this->optionId); + } +} diff --git a/src/network/mcpe/protocol/types/SpawnSettings.php b/src/network/mcpe/protocol/types/SpawnSettings.php new file mode 100644 index 000000000..a2a2fb498 --- /dev/null +++ b/src/network/mcpe/protocol/types/SpawnSettings.php @@ -0,0 +1,73 @@ +biomeType = $biomeType; + $this->biomeName = $biomeName; + $this->dimension = $dimension; + } + + public function getBiomeType() : int{ + return $this->biomeType; + } + + public function getBiomeName() : string{ + return $this->biomeName; + } + + /** + * @see DimensionIds + */ + public function getDimension() : int{ + return $this->dimension; + } + + public static function read(PacketSerializer $in) : self{ + $biomeType = $in->getLShort(); + $biomeName = $in->getString(); + $dimension = $in->getVarInt(); + + return new self($biomeType, $biomeName, $dimension); + } + + public function write(PacketSerializer $out) : void{ + $out->putLShort($this->biomeType); + $out->putString($this->biomeName); + $out->putVarInt($this->dimension); + } +} diff --git a/src/network/mcpe/protocol/types/entity/EntityLink.php b/src/network/mcpe/protocol/types/entity/EntityLink.php index c0cec4583..b807f2c4a 100644 --- a/src/network/mcpe/protocol/types/entity/EntityLink.php +++ b/src/network/mcpe/protocol/types/entity/EntityLink.php @@ -37,11 +37,14 @@ class EntityLink{ public $type; /** @var bool */ public $immediate; //for dismounting on mount death + /** @var bool */ + public $causedByRider; - public function __construct(int $fromEntityUniqueId, int $toEntityUniqueId, int $type, bool $immediate){ + public function __construct(int $fromEntityUniqueId, int $toEntityUniqueId, int $type, bool $immediate, bool $causedByRider){ $this->fromEntityUniqueId = $fromEntityUniqueId; $this->toEntityUniqueId = $toEntityUniqueId; $this->type = $type; $this->immediate = $immediate; + $this->causedByRider = $causedByRider; } } diff --git a/src/network/mcpe/protocol/types/entity/EntityMetadataFlags.php b/src/network/mcpe/protocol/types/entity/EntityMetadataFlags.php index 717fc598e..5a27fdcd6 100644 --- a/src/network/mcpe/protocol/types/entity/EntityMetadataFlags.php +++ b/src/network/mcpe/protocol/types/entity/EntityMetadataFlags.php @@ -114,10 +114,13 @@ final class EntityMetadataFlags{ public const ROARING = 83; public const DELAYED_ATTACKING = 84; public const AVOIDING_MOBS = 85; - public const FACING_TARGET_TO_RANGE_ATTACK = 86; - public const HIDDEN_WHEN_INVISIBLE = 87; //?????????????????? - public const IS_IN_UI = 88; - public const STALKING = 89; - public const EMOTING = 90; - public const CELEBRATING = 91; + public const AVOIDING_BLOCK = 86; + public const FACING_TARGET_TO_RANGE_ATTACK = 87; + public const HIDDEN_WHEN_INVISIBLE = 88; //?????????????????? + public const IS_IN_UI = 89; + public const STALKING = 90; + public const EMOTING = 91; + public const CELEBRATING = 92; + public const ADMIRING = 93; + public const CELEBRATING_SPECIAL = 94; } diff --git a/src/network/mcpe/protocol/types/inventory/ContainerIds.php b/src/network/mcpe/protocol/types/inventory/ContainerIds.php index 7b4372419..2a4501dc2 100644 --- a/src/network/mcpe/protocol/types/inventory/ContainerIds.php +++ b/src/network/mcpe/protocol/types/inventory/ContainerIds.php @@ -35,7 +35,7 @@ final class ContainerIds{ public const LAST = 100; public const OFFHAND = 119; public const ARMOR = 120; - public const CREATIVE = 121; + public const HOTBAR = 122; public const FIXED_INVENTORY = 123; public const UI = 124; diff --git a/src/network/mcpe/protocol/types/inventory/CreativeContentEntry.php b/src/network/mcpe/protocol/types/inventory/CreativeContentEntry.php new file mode 100644 index 000000000..3204bed14 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/CreativeContentEntry.php @@ -0,0 +1,54 @@ +entryId = $entryId; + $this->item = $item; + } + + public function getEntryId() : int{ return $this->entryId; } + + public function getItem() : ItemStack{ return $this->item; } + + public static function read(PacketSerializer $in) : self{ + $entryId = $in->readGenericTypeNetworkId(); + $item = $in->getSlot(); + return new self($entryId, $item); + } + + public function write(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->entryId); + $out->putSlot($this->item); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/InventoryTransactionChangedSlotsHack.php b/src/network/mcpe/protocol/types/inventory/InventoryTransactionChangedSlotsHack.php new file mode 100644 index 000000000..456666501 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/InventoryTransactionChangedSlotsHack.php @@ -0,0 +1,65 @@ +containerId = $containerId; + $this->changedSlotIndexes = $changedSlotIndexes; + } + + public function getContainerId() : int{ return $this->containerId; } + + /** @return int[] */ + public function getChangedSlotIndexes() : array{ return $this->changedSlotIndexes; } + + public static function read(PacketSerializer $in) : self{ + $containerId = $in->getByte(); + $changedSlots = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $changedSlots[] = $in->getByte(); + } + return new self($containerId, $changedSlots); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->containerId); + $out->putUnsignedVarInt(count($this->changedSlotIndexes)); + foreach($this->changedSlotIndexes as $index){ + $out->putByte($index); + } + } +} diff --git a/src/network/mcpe/protocol/types/inventory/ItemStackWrapper.php b/src/network/mcpe/protocol/types/inventory/ItemStackWrapper.php new file mode 100644 index 000000000..8524bdf36 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/ItemStackWrapper.php @@ -0,0 +1,59 @@ +stackId = $stackId; + $this->itemStack = $itemStack; + } + + public static function legacy(ItemStack $itemStack) : self{ + return new self($itemStack->getId() === 0 ? 0 : 1, $itemStack); + } + + public function getStackId() : int{ return $this->stackId; } + + public function getItemStack() : ItemStack{ return $this->itemStack; } + + public static function read(PacketSerializer $in) : self{ + $stackId = $in->readGenericTypeNetworkId(); + $stack = $in->getSlot(); + return new self($stackId, $stack); + } + + public function write(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->stackId); + $out->putSlot($this->itemStack); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/NetworkInventoryAction.php b/src/network/mcpe/protocol/types/inventory/NetworkInventoryAction.php index 58abac5d1..37b63ee3d 100644 --- a/src/network/mcpe/protocol/types/inventory/NetworkInventoryAction.php +++ b/src/network/mcpe/protocol/types/inventory/NetworkInventoryAction.php @@ -76,6 +76,8 @@ class NetworkInventoryAction{ public $oldItem; /** @var ItemStack */ public $newItem; + /** @var int|null */ + public $newItemStackId = null; /** * @return $this @@ -83,7 +85,7 @@ class NetworkInventoryAction{ * @throws BinaryDataException * @throws PacketDecodeException */ - public function read(PacketSerializer $packet) : NetworkInventoryAction{ + public function read(PacketSerializer $packet, bool $hasItemStackIds) : NetworkInventoryAction{ $this->sourceType = $packet->getUnsignedVarInt(); switch($this->sourceType){ @@ -105,6 +107,9 @@ class NetworkInventoryAction{ $this->inventorySlot = $packet->getUnsignedVarInt(); $this->oldItem = $packet->getSlot(); $this->newItem = $packet->getSlot(); + if($hasItemStackIds){ + $this->newItemStackId = $packet->readGenericTypeNetworkId(); + } return $this; } @@ -112,7 +117,7 @@ class NetworkInventoryAction{ /** * @throws \InvalidArgumentException */ - public function write(PacketSerializer $packet) : void{ + public function write(PacketSerializer $packet, bool $hasItemStackIds) : void{ $packet->putUnsignedVarInt($this->sourceType); switch($this->sourceType){ @@ -134,5 +139,11 @@ class NetworkInventoryAction{ $packet->putUnsignedVarInt($this->inventorySlot); $packet->putSlot($this->oldItem); $packet->putSlot($this->newItem); + if($hasItemStackIds){ + if($this->newItemStackId === null){ + throw new \InvalidStateException("Item stack ID for newItem must be provided"); + } + $packet->writeGenericTypeNetworkId($this->newItemStackId); + } } } diff --git a/src/network/mcpe/protocol/types/inventory/TransactionData.php b/src/network/mcpe/protocol/types/inventory/TransactionData.php index ea10fce25..426ddbe34 100644 --- a/src/network/mcpe/protocol/types/inventory/TransactionData.php +++ b/src/network/mcpe/protocol/types/inventory/TransactionData.php @@ -45,10 +45,10 @@ abstract class TransactionData{ * @throws BinaryDataException * @throws PacketDecodeException */ - final public function decode(PacketSerializer $stream) : void{ + final public function decode(PacketSerializer $stream, bool $hasItemStackIds) : void{ $actionCount = $stream->getUnsignedVarInt(); for($i = 0; $i < $actionCount; ++$i){ - $this->actions[] = (new NetworkInventoryAction())->read($stream); + $this->actions[] = (new NetworkInventoryAction())->read($stream, $hasItemStackIds); } $this->decodeData($stream); } @@ -59,10 +59,10 @@ abstract class TransactionData{ */ abstract protected function decodeData(PacketSerializer $stream) : void; - final public function encode(PacketSerializer $stream) : void{ + final public function encode(PacketSerializer $stream, bool $hasItemStackIds) : void{ $stream->putUnsignedVarInt(count($this->actions)); foreach($this->actions as $action){ - $action->write($stream); + $action->write($stream, $hasItemStackIds); } $this->encodeData($stream); } diff --git a/src/network/mcpe/protocol/types/inventory/WindowTypes.php b/src/network/mcpe/protocol/types/inventory/WindowTypes.php index 2eb712463..c20f80601 100644 --- a/src/network/mcpe/protocol/types/inventory/WindowTypes.php +++ b/src/network/mcpe/protocol/types/inventory/WindowTypes.php @@ -63,5 +63,8 @@ final class WindowTypes{ public const SMOKER = 28; public const STONECUTTER = 29; public const CARTOGRAPHY = 30; + public const HUD = 31; + public const JIGSAW_EDITOR = 32; + public const SMITHING_TABLE = 33; } diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/BeaconPaymentStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/BeaconPaymentStackRequestAction.php new file mode 100644 index 000000000..19cf0e05d --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/BeaconPaymentStackRequestAction.php @@ -0,0 +1,59 @@ +primaryEffectId = $primaryEffectId; + $this->secondaryEffectId = $secondaryEffectId; + } + + public function getPrimaryEffectId() : int{ return $this->primaryEffectId; } + + public function getSecondaryEffectId() : int{ return $this->secondaryEffectId; } + + public static function getTypeId() : int{ return ItemStackRequestActionType::BEACON_PAYMENT; } + + public static function read(PacketSerializer $in) : self{ + $primary = $in->getVarInt(); + $secondary = $in->getVarInt(); + return new self($primary, $secondary); + } + + public function write(PacketSerializer $out) : void{ + $out->putVarInt($this->primaryEffectId); + $out->putVarInt($this->secondaryEffectId); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php new file mode 100644 index 000000000..d5f10ee1f --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/CraftRecipeAutoStackRequestAction.php @@ -0,0 +1,34 @@ +recipeId = $recipeId; + } + + public function getRecipeId() : int{ return $this->recipeId; } + + public static function read(PacketSerializer $in) : self{ + $recipeId = $in->readGenericTypeNetworkId(); + return new self($recipeId); + } + + public function write(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->recipeId); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/CraftingConsumeInputStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/CraftingConsumeInputStackRequestAction.php new file mode 100644 index 000000000..26f85f7a7 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/CraftingConsumeInputStackRequestAction.php @@ -0,0 +1,33 @@ +craftingGridSlot = $craftingGridSlot; + } + + public function getCraftingGridSlot() : int{ return $this->craftingGridSlot; } + + public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_MARK_SECONDARY_RESULT_SLOT; } + + public static function read(PacketSerializer $in) : self{ + $slot = $in->getByte(); + return new self($slot); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->craftingGridSlot); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/CreativeCreateStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/CreativeCreateStackRequestAction.php new file mode 100644 index 000000000..e84975afa --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/CreativeCreateStackRequestAction.php @@ -0,0 +1,52 @@ +creativeItemId = $creativeItemId; + } + + public function getCreativeItemId() : int{ return $this->creativeItemId; } + + public static function getTypeId() : int{ return ItemStackRequestActionType::CREATIVE_CREATE; } + + public static function read(PacketSerializer $in) : self{ + $creativeItemId = $in->readGenericTypeNetworkId(); + return new self($creativeItemId); + } + + public function write(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->creativeItemId); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/DeprecatedCraftingNonImplementedStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/DeprecatedCraftingNonImplementedStackRequestAction.php new file mode 100644 index 000000000..5ec79617a --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/DeprecatedCraftingNonImplementedStackRequestAction.php @@ -0,0 +1,45 @@ +results = $results; + $this->iterations = $iterations; + } + + /** @return ItemStack[] */ + public function getResults() : array{ return $this->results; } + + public function getIterations() : int{ return $this->iterations; } + + public static function getTypeId() : int{ + return ItemStackRequestActionType::CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING; + } + + public static function read(PacketSerializer $in) : self{ + $results = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $results[] = $in->getSlot(); + } + $iterations = $in->getByte(); + return new self($results, $iterations); + } + + public function write(PacketSerializer $out) : void{ + $out->putUnsignedVarInt(count($this->results)); + foreach($this->results as $result){ + $out->putSlot($result); + } + $out->putByte($this->iterations); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/DestroyStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/DestroyStackRequestAction.php new file mode 100644 index 000000000..36f55e9a4 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/DestroyStackRequestAction.php @@ -0,0 +1,34 @@ +count = $count; + $this->source = $source; + } + + final public function getCount() : int{ return $this->count; } + + final public function getSource() : ItemStackRequestSlotInfo{ return $this->source; } + + public static function read(PacketSerializer $in) : self{ + $count = $in->getByte(); + $source = ItemStackRequestSlotInfo::read($in); + return new self($count, $source); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->count); + $this->source->write($out); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/DropStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/DropStackRequestAction.php new file mode 100644 index 000000000..6a4857805 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/DropStackRequestAction.php @@ -0,0 +1,66 @@ +count = $count; + $this->source = $source; + $this->randomly = $randomly; + } + + public function getCount() : int{ return $this->count; } + + public function getSource() : ItemStackRequestSlotInfo{ return $this->source; } + + public function isRandomly() : bool{ return $this->randomly; } + + public static function getTypeId() : int{ return ItemStackRequestActionType::DROP; } + + public static function read(PacketSerializer $in) : self{ + $count = $in->getByte(); + $source = ItemStackRequestSlotInfo::read($in); + $random = $in->getBool(); + return new self($count, $source, $random); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->count); + $this->source->write($out); + $out->putBool($this->randomly); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequest.php b/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequest.php new file mode 100644 index 000000000..8dc61ab95 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequest.php @@ -0,0 +1,87 @@ +requestId = $requestId; + $this->actions = $actions; + } + + public function getRequestId() : int{ return $this->requestId; } + + /** @return ItemStackRequestAction[] */ + public function getActions() : array{ return $this->actions; } + + private static function readAction(PacketSerializer $in, int $typeId) : ItemStackRequestAction{ + switch($typeId){ + case TakeStackRequestAction::getTypeId(): return TakeStackRequestAction::read($in); + case PlaceStackRequestAction::getTypeId(): return PlaceStackRequestAction::read($in); + case SwapStackRequestAction::getTypeId(): return SwapStackRequestAction::read($in); + case DropStackRequestAction::getTypeId(): return DropStackRequestAction::read($in); + case DestroyStackRequestAction::getTypeId(): return DestroyStackRequestAction::read($in); + case CraftingConsumeInputStackRequestAction::getTypeId(): return CraftingConsumeInputStackRequestAction::read($in); + case CraftingMarkSecondaryResultStackRequestAction::getTypeId(): return CraftingMarkSecondaryResultStackRequestAction::read($in); + case LabTableCombineStackRequestAction::getTypeId(): return LabTableCombineStackRequestAction::read($in); + case BeaconPaymentStackRequestAction::getTypeId(): return BeaconPaymentStackRequestAction::read($in); + case CraftRecipeStackRequestAction::getTypeId(): return CraftRecipeStackRequestAction::read($in); + case CraftRecipeAutoStackRequestAction::getTypeId(): return CraftRecipeAutoStackRequestAction::read($in); + case CreativeCreateStackRequestAction::getTypeId(): return CreativeCreateStackRequestAction::read($in); + case DeprecatedCraftingNonImplementedStackRequestAction::getTypeId(): return DeprecatedCraftingNonImplementedStackRequestAction::read($in); + case DeprecatedCraftingResultsStackRequestAction::getTypeId(): return DeprecatedCraftingResultsStackRequestAction::read($in); + } + throw new \UnexpectedValueException("Unhandled item stack request action type $typeId"); + } + + public static function read(PacketSerializer $in) : self{ + $requestId = $in->readGenericTypeNetworkId(); + $actions = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $typeId = $in->getByte(); + $actions[] = self::readAction($in, $typeId); + } + return new self($requestId, $actions); + } + + public function write(PacketSerializer $out) : void{ + $out->writeGenericTypeNetworkId($this->requestId); + $out->putUnsignedVarInt(count($this->actions)); + foreach($this->actions as $action){ + $out->putByte($action::getTypeId()); + $action->write($out); + } + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequestAction.php new file mode 100644 index 000000000..bd56a0797 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/ItemStackRequestAction.php @@ -0,0 +1,33 @@ +containerId = $containerId; + $this->slotId = $slotId; + $this->stackId = $stackId; + } + + public function getContainerId() : int{ return $this->containerId; } + + public function getSlotId() : int{ return $this->slotId; } + + public function getStackId() : int{ return $this->stackId; } + + public static function read(PacketSerializer $in) : self{ + $containerId = $in->getByte(); + $slotId = $in->getByte(); + $stackId = $in->readGenericTypeNetworkId(); + return new self($containerId, $slotId, $stackId); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->containerId); + $out->putByte($this->slotId); + $out->writeGenericTypeNetworkId($this->stackId); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/LabTableCombineStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/LabTableCombineStackRequestAction.php new file mode 100644 index 000000000..8ea896a82 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/LabTableCombineStackRequestAction.php @@ -0,0 +1,43 @@ +slot1 = $slot1; + $this->slot2 = $slot2; + } + + public function getSlot1() : ItemStackRequestSlotInfo{ return $this->slot1; } + + public function getSlot2() : ItemStackRequestSlotInfo{ return $this->slot2; } + + public static function getTypeId() : int{ return ItemStackRequestActionType::SWAP; } + + public static function read(PacketSerializer $in) : self{ + $slot1 = ItemStackRequestSlotInfo::read($in); + $slot2 = ItemStackRequestSlotInfo::read($in); + return new self($slot1, $slot2); + } + + public function write(PacketSerializer $out) : void{ + $this->slot1->write($out); + $this->slot2->write($out); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/TakeOrPlaceStackRequestActionTrait.php b/src/network/mcpe/protocol/types/inventory/stackrequest/TakeOrPlaceStackRequestActionTrait.php new file mode 100644 index 000000000..2866c641d --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/TakeOrPlaceStackRequestActionTrait.php @@ -0,0 +1,61 @@ +count = $count; + $this->source = $source; + $this->destination = $destination; + } + + final public function getCount() : int{ return $this->count; } + + final public function getSource() : ItemStackRequestSlotInfo{ return $this->source; } + + final public function getDestination() : ItemStackRequestSlotInfo{ return $this->destination; } + + public static function read(PacketSerializer $in) : self{ + $count = $in->getByte(); + $src = ItemStackRequestSlotInfo::read($in); + $dst = ItemStackRequestSlotInfo::read($in); + return new self($count, $src, $dst); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->count); + $this->source->write($out); + $this->destination->write($out); + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackrequest/TakeStackRequestAction.php b/src/network/mcpe/protocol/types/inventory/stackrequest/TakeStackRequestAction.php new file mode 100644 index 000000000..f2946def2 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackrequest/TakeStackRequestAction.php @@ -0,0 +1,33 @@ +ok = $ok; + $this->requestId = $requestId; + $this->containerInfos = $containerInfos; + } + + public function isOk() : bool{ return $this->ok; } + + public function getRequestId() : int{ return $this->requestId; } + + /** @return ItemStackResponseContainerInfo[] */ + public function getContainerInfos() : array{ return $this->containerInfos; } + + public static function read(PacketSerializer $in) : self{ + $ok = $in->getBool(); + $requestId = $in->readGenericTypeNetworkId(); + $containerInfos = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $containerInfos[] = ItemStackResponseContainerInfo::read($in); + } + return new self($ok, $requestId, $containerInfos); + } + + public function write(PacketSerializer $out) : void{ + $out->putBool($this->ok); + $out->writeGenericTypeNetworkId($this->requestId); + $out->putUnsignedVarInt(count($this->containerInfos)); + foreach($this->containerInfos as $containerInfo){ + $containerInfo->write($out); + } + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseContainerInfo.php b/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseContainerInfo.php new file mode 100644 index 000000000..3678c84d8 --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseContainerInfo.php @@ -0,0 +1,65 @@ +containerId = $containerId; + $this->slots = $slots; + } + + public function getContainerId() : int{ return $this->containerId; } + + /** @return ItemStackResponseSlotInfo[] */ + public function getSlots() : array{ return $this->slots; } + + public static function read(PacketSerializer $in) : self{ + $containerId = $in->getByte(); + $slots = []; + for($i = 0, $len = $in->getUnsignedVarInt(); $i < $len; ++$i){ + $slots[] = ItemStackResponseSlotInfo::read($in); + } + return new self($containerId, $slots); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->containerId); + $out->putUnsignedVarInt(count($this->slots)); + foreach($this->slots as $slot){ + $slot->write($out); + } + } +} diff --git a/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseSlotInfo.php b/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseSlotInfo.php new file mode 100644 index 000000000..516d0bfcb --- /dev/null +++ b/src/network/mcpe/protocol/types/inventory/stackresponse/ItemStackResponseSlotInfo.php @@ -0,0 +1,68 @@ +slot = $slot; + $this->hotbarSlot = $hotbarSlot; + $this->count = $count; + $this->itemStackId = $itemStackId; + } + + public function getSlot() : int{ return $this->slot; } + + public function getHotbarSlot() : int{ return $this->hotbarSlot; } + + public function getCount() : int{ return $this->count; } + + public function getItemStackId() : int{ return $this->itemStackId; } + + public static function read(PacketSerializer $in) : self{ + $slot = $in->getByte(); + $hotbarSlot = $in->getByte(); + $count = $in->getByte(); + $itemStackId = $in->readGenericTypeNetworkId(); + return new self($slot, $hotbarSlot, $count, $itemStackId); + } + + public function write(PacketSerializer $out) : void{ + $out->putByte($this->slot); + $out->putByte($this->hotbarSlot); + $out->putByte($this->count); + $out->writeGenericTypeNetworkId($this->itemStackId); + } +} diff --git a/src/network/mcpe/protocol/types/recipe/MultiRecipe.php b/src/network/mcpe/protocol/types/recipe/MultiRecipe.php index bac528c70..af07d63c0 100644 --- a/src/network/mcpe/protocol/types/recipe/MultiRecipe.php +++ b/src/network/mcpe/protocol/types/recipe/MultiRecipe.php @@ -43,21 +43,31 @@ final class MultiRecipe extends RecipeWithTypeId{ /** @var UUID */ private $recipeId; + /** @var int */ + private $recipeNetId; - public function __construct(int $typeId, UUID $recipeId){ + public function __construct(int $typeId, UUID $recipeId, int $recipeNetId){ parent::__construct($typeId); $this->recipeId = $recipeId; + $this->recipeNetId = $recipeNetId; } public function getRecipeId() : UUID{ return $this->recipeId; } + public function getRecipeNetId() : int{ + return $this->recipeNetId; + } + public static function decode(int $typeId, PacketSerializer $in) : self{ - return new self($typeId, $in->getUUID()); + $uuid = $in->getUUID(); + $recipeNetId = $in->readGenericTypeNetworkId(); + return new self($typeId, $uuid, $recipeNetId); } public function encode(PacketSerializer $out) : void{ $out->putUUID($this->recipeId); + $out->writeGenericTypeNetworkId($this->recipeNetId); } } diff --git a/src/network/mcpe/protocol/types/recipe/PotionTypeRecipe.php b/src/network/mcpe/protocol/types/recipe/PotionTypeRecipe.php index 2da7bf07a..31628ac4c 100644 --- a/src/network/mcpe/protocol/types/recipe/PotionTypeRecipe.php +++ b/src/network/mcpe/protocol/types/recipe/PotionTypeRecipe.php @@ -25,27 +25,48 @@ namespace pocketmine\network\mcpe\protocol\types\recipe; class PotionTypeRecipe{ /** @var int */ - private $inputPotionType; + private $inputItemId; + /** @var int */ + private $inputItemMeta; /** @var int */ private $ingredientItemId; /** @var int */ - private $outputPotionType; + private $ingredientItemMeta; + /** @var int */ + private $outputItemId; + /** @var int */ + private $outputItemMeta; - public function __construct(int $inputPotionType, int $ingredientItemId, int $outputPotionType){ - $this->inputPotionType = $inputPotionType; + public function __construct(int $inputItemId, int $inputItemMeta, int $ingredientItemId, int $ingredientItemMeta, int $outputItemId, int $outputItemMeta){ + $this->inputItemId = $inputItemId; + $this->inputItemMeta = $inputItemMeta; $this->ingredientItemId = $ingredientItemId; - $this->outputPotionType = $outputPotionType; + $this->ingredientItemMeta = $ingredientItemMeta; + $this->outputItemId = $outputItemId; + $this->outputItemMeta = $outputItemMeta; } - public function getInputPotionType() : int{ - return $this->inputPotionType; + public function getInputItemId() : int{ + return $this->inputItemId; + } + + public function getInputItemMeta() : int{ + return $this->inputItemMeta; } public function getIngredientItemId() : int{ return $this->ingredientItemId; } - public function getOutputPotionType() : int{ - return $this->outputPotionType; + public function getIngredientItemMeta() : int{ + return $this->ingredientItemMeta; + } + + public function getOutputItemId() : int{ + return $this->outputItemId; + } + + public function getOutputItemMeta() : int{ + return $this->outputItemMeta; } } diff --git a/src/network/mcpe/protocol/types/recipe/ShapedRecipe.php b/src/network/mcpe/protocol/types/recipe/ShapedRecipe.php index 195e54e6c..e21ba9163 100644 --- a/src/network/mcpe/protocol/types/recipe/ShapedRecipe.php +++ b/src/network/mcpe/protocol/types/recipe/ShapedRecipe.php @@ -42,12 +42,14 @@ final class ShapedRecipe extends RecipeWithTypeId{ private $blockName; /** @var int */ private $priority; + /** @var int */ + private $recipeNetId; /** * @param RecipeIngredient[][] $input * @param ItemStack[] $output */ - public function __construct(int $typeId, string $recipeId, array $input, array $output, UUID $uuid, string $blockType, int $priority){ + public function __construct(int $typeId, string $recipeId, array $input, array $output, UUID $uuid, string $blockType, int $priority, int $recipeNetId){ parent::__construct($typeId); $rows = count($input); if($rows < 1 or $rows > 3){ @@ -67,6 +69,7 @@ final class ShapedRecipe extends RecipeWithTypeId{ $this->blockName = $blockType; $this->priority = $priority; $this->uuid = $uuid; + $this->recipeNetId = $recipeNetId; } public function getRecipeId() : string{ @@ -107,6 +110,10 @@ final class ShapedRecipe extends RecipeWithTypeId{ return $this->priority; } + public function getRecipeNetId() : int{ + return $this->recipeNetId; + } + public static function decode(int $recipeType, PacketSerializer $in) : self{ $recipeId = $in->getString(); $width = $in->getVarInt(); @@ -125,8 +132,9 @@ final class ShapedRecipe extends RecipeWithTypeId{ $uuid = $in->getUUID(); $block = $in->getString(); $priority = $in->getVarInt(); + $recipeNetId = $in->readGenericTypeNetworkId(); - return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority); + return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority, $recipeNetId); } public function encode(PacketSerializer $out) : void{ @@ -147,5 +155,6 @@ final class ShapedRecipe extends RecipeWithTypeId{ $out->putUUID($this->uuid); $out->putString($this->blockName); $out->putVarInt($this->priority); + $out->writeGenericTypeNetworkId($this->recipeNetId); } } diff --git a/src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php b/src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php index 92ada07b1..58903e468 100644 --- a/src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php +++ b/src/network/mcpe/protocol/types/recipe/ShapelessRecipe.php @@ -42,12 +42,14 @@ final class ShapelessRecipe extends RecipeWithTypeId{ private $blockName; /** @var int */ private $priority; + /** @var int */ + private $recipeNetId; /** * @param RecipeIngredient[] $inputs * @param ItemStack[] $outputs */ - public function __construct(int $typeId, string $recipeId, array $inputs, array $outputs, UUID $uuid, string $blockName, int $priority){ + public function __construct(int $typeId, string $recipeId, array $inputs, array $outputs, UUID $uuid, string $blockName, int $priority, int $recipeNetId){ parent::__construct($typeId); $this->recipeId = $recipeId; $this->inputs = $inputs; @@ -55,6 +57,7 @@ final class ShapelessRecipe extends RecipeWithTypeId{ $this->uuid = $uuid; $this->blockName = $blockName; $this->priority = $priority; + $this->recipeNetId = $recipeNetId; } public function getRecipeId() : string{ @@ -87,6 +90,10 @@ final class ShapelessRecipe extends RecipeWithTypeId{ return $this->priority; } + public function getRecipeNetId() : int{ + return $this->recipeNetId; + } + public static function decode(int $recipeType, PacketSerializer $in) : self{ $recipeId = $in->getString(); $input = []; @@ -100,8 +107,9 @@ final class ShapelessRecipe extends RecipeWithTypeId{ $uuid = $in->getUUID(); $block = $in->getString(); $priority = $in->getVarInt(); + $recipeNetId = $in->readGenericTypeNetworkId(); - return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority); + return new self($recipeType, $recipeId, $input, $output, $uuid, $block, $priority, $recipeNetId); } public function encode(PacketSerializer $out) : void{ @@ -119,5 +127,6 @@ final class ShapelessRecipe extends RecipeWithTypeId{ $out->putUUID($this->uuid); $out->putString($this->blockName); $out->putVarInt($this->priority); + $out->writeGenericTypeNetworkId($this->recipeNetId); } } diff --git a/src/network/mcpe/raklib/RakLibInterface.php b/src/network/mcpe/raklib/RakLibInterface.php index 2e1de979e..70f754b20 100644 --- a/src/network/mcpe/raklib/RakLibInterface.php +++ b/src/network/mcpe/raklib/RakLibInterface.php @@ -55,7 +55,7 @@ class RakLibInterface implements ServerEventListener, AdvancedNetworkInterface{ * Sometimes this gets changed when the MCPE-layer protocol gets broken to the point where old and new can't * communicate. It's important that we check this to avoid catastrophes. */ - private const MCPE_RAKNET_PROTOCOL_VERSION = 9; + private const MCPE_RAKNET_PROTOCOL_VERSION = 10; private const MCPE_RAKNET_PACKET_ID = "\xfe"; diff --git a/tests/phpstan/configs/l7-baseline.neon b/tests/phpstan/configs/l7-baseline.neon index 833bc8190..b32e55fa7 100644 --- a/tests/phpstan/configs/l7-baseline.neon +++ b/tests/phpstan/configs/l7-baseline.neon @@ -627,7 +627,12 @@ parameters: - message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\BaseNbtSerializer\\:\\:read\\(\\) expects string, string\\|false given\\.$#" - count: 2 + count: 1 + path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php + + - + message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\protocol\\\\serializer\\\\PacketSerializer constructor expects string, string\\|false given\\.$#" + count: 1 path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php - diff --git a/tests/phpstan/configs/l8-baseline.neon b/tests/phpstan/configs/l8-baseline.neon index acd42152e..9dc31452c 100644 --- a/tests/phpstan/configs/l8-baseline.neon +++ b/tests/phpstan/configs/l8-baseline.neon @@ -442,16 +442,11 @@ parameters: - message: "#^Cannot call method getString\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" - count: 3 - path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php - - - - message: "#^Cannot call method getShort\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" count: 1 path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php - - message: "#^Cannot call method equals\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#" + message: "#^Parameter \\#1 \\$that of method pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\:\\:equals\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\Tag, pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null given\\.$#" count: 1 path: ../../../src/network/mcpe/convert/RuntimeBlockMapping.php