Protocol changes for 1.16.0

This commit is contained in:
Dylan K. Taylor 2020-06-26 12:46:52 +01:00
parent c616d9bb7c
commit e990c5a0a5
81 changed files with 3026 additions and 184 deletions

View File

@ -113,6 +113,7 @@ use pocketmine\network\mcpe\protocol\BlockPickRequestPacket;
use pocketmine\network\mcpe\protocol\BookEditPacket;
use pocketmine\network\mcpe\protocol\ChunkRadiusUpdatedPacket;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\DisconnectPacket;
use pocketmine\network\mcpe\protocol\InteractPacket;
@ -156,6 +157,8 @@ use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
use pocketmine\network\mcpe\protocol\types\WindowTypes;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\VerifyLoginTask;
@ -225,6 +228,14 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
private const RESOURCE_PACK_CHUNK_SIZE = 128 * 1024; //128KB
//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;
/**
* Validates the given username.
*/
@ -1230,11 +1241,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
$this->spawnPosition = new Position($pos->x, $pos->y, $pos->z, $level);
$pk = new SetSpawnPositionPacket();
$pk->x = $this->spawnPosition->getFloorX();
$pk->y = $this->spawnPosition->getFloorY();
$pk->z = $this->spawnPosition->getFloorZ();
$pk->x = $pk->x2 = $this->spawnPosition->getFloorX();
$pk->y = $pk->y2 = $this->spawnPosition->getFloorY();
$pk->z = $pk->z2 = $this->spawnPosition->getFloorZ();
$pk->dimension = DimensionIds::OVERWORLD;
$pk->spawnType = SetSpawnPositionPacket::TYPE_PLAYER_SPAWN;
$pk->spawnForced = false;
$this->dataPacket($pk);
}
@ -2202,7 +2214,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$pk->pitch = $this->pitch;
$pk->yaw = $this->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 = Player::getClientFriendlyGamemode($this->server->getGamemode());
$pk->difficulty = $this->level->getDifficulty();
$pk->spawnX = $spawnPosition->getFloorX();
@ -2373,22 +2385,15 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$isFinalCraftingPart = false;
foreach($packet->actions as $networkInventoryAction){
if(
$networkInventoryAction->sourceType === NetworkInventoryAction::SOURCE_CONTAINER and
$networkInventoryAction->windowId === ContainerIds::UI and
$networkInventoryAction->inventorySlot === 50 and
!$networkInventoryAction->oldItem->equalsExact($networkInventoryAction->newItem)
){
$isCraftingPart = true;
if(!$networkInventoryAction->oldItem->isNull() and $networkInventoryAction->newItem->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{
$action = $networkInventoryAction->createInventoryAction($this);
@ -2789,6 +2794,20 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case InteractPacket::ACTION_LEAVE_VEHICLE:
case InteractPacket::ACTION_MOUSEOVER:
break; //TODO: handle these
case InteractPacket::ACTION_OPEN_INVENTORY:
if($target === $this){
//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.
$pk = new ContainerOpenPacket();
$pk->windowId = self::HARDCODED_INVENTORY_WINDOW_ID;
$pk->type = WindowTypes::INVENTORY;
$pk->x = $pk->y = $pk->z = 0;
$pk->entityUniqueId = $this->getId();
$this->sendDataPacket($pk);
break;
}
return false;
default:
$this->server->getLogger()->debug("Unhandled/unknown interaction type " . $packet->action . " received from " . $this->getName());
@ -3002,18 +3021,22 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function handleContainerClose(ContainerClosePacket $packet) : bool{
if(!$this->spawned or $packet->windowId === 0){
if(!$this->spawned){
return true;
}
$this->doCloseInventory();
if($packet->windowId >= self::RESERVED_WINDOW_ID_RANGE_START and $packet->windowId <= self::RESERVED_WINDOW_ID_RANGE_END){
$pk = new ContainerClosePacket();
$pk->windowId = $packet->windowId;
$this->sendDataPacket($pk);
return true;
}
if(isset($this->windowIndex[$packet->windowId])){
(new InventoryCloseEvent($this->windowIndex[$packet->windowId], $this))->call();
$this->removeWindow($this->windowIndex[$packet->windowId]);
return true;
}elseif($packet->windowId === 255){
//Closed a fake window
//removeWindow handles sending the appropriate
return true;
}
@ -3983,7 +4006,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
if($forceId === null){
$cnt = $this->windowCnt;
do{
$cnt = max(ContainerIds::FIRST, ($cnt + 1) % ContainerIds::LAST);
$cnt = max(ContainerIds::FIRST, ($cnt + 1) % self::RESERVED_WINDOW_ID_RANGE_START);
if($cnt === $this->windowCnt){ //wraparound, no free slots
throw new \InvalidStateException("No free window IDs found");
}
@ -3991,7 +4014,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$this->windowCnt = $cnt;
}else{
$cnt = $forceId;
if(isset($this->windowIndex[$cnt])){
if(isset($this->windowIndex[$cnt]) or ($cnt >= self::RESERVED_WINDOW_ID_RANGE_START && $cnt <= self::RESERVED_WINDOW_ID_RANGE_END)){
throw new \InvalidArgumentException("Requested force ID $forceId already in use");
}
}

View File

@ -36,7 +36,7 @@ use pocketmine\math\RayTraceResult;
use pocketmine\math\Vector3;
use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\Player;
use pocketmine\plugin\Plugin;
use function array_merge;

View File

@ -25,7 +25,7 @@ namespace pocketmine\block;
use pocketmine\item\Item;
use pocketmine\level\Position;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use function min;
/**

View File

@ -25,6 +25,8 @@ namespace pocketmine\block;
use pocketmine\inventory\CraftingGrid;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\ContainerOpenPacket;
use pocketmine\network\mcpe\protocol\types\WindowTypes;
use pocketmine\Player;
class CraftingTable extends Solid{
@ -50,6 +52,16 @@ class CraftingTable extends Solid{
public function onActivate(Item $item, Player $player = null) : bool{
if($player instanceof Player){
$player->setCraftingGrid(new CraftingGrid($player, CraftingGrid::SIZE_BIG));
//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
$pk = new ContainerOpenPacket();
$pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID;
$pk->type = WindowTypes::WORKBENCH;
$pk->x = $this->getFloorX();
$pk->y = $this->getFloorY();
$pk->z = $this->getFloorZ();
$player->sendDataPacket($pk);
}
return true;

View File

@ -311,12 +311,15 @@ abstract class Entity extends Location implements Metadatable, EntityIds{
public const DATA_FLAG_ROARING = 83;
public const DATA_FLAG_DELAYED_ATTACKING = 84;
public const DATA_FLAG_AVOIDING_MOBS = 85;
public const DATA_FLAG_FACING_TARGET_TO_RANGE_ATTACK = 86;
public const DATA_FLAG_HIDDEN_WHEN_INVISIBLE = 87; //??????????????????
public const DATA_FLAG_IS_IN_UI = 88;
public const DATA_FLAG_STALKING = 89;
public const DATA_FLAG_EMOTING = 90;
public const DATA_FLAG_CELEBRATING = 91;
public const DATA_FLAG_AVOIDING_BLOCK = 86;
public const DATA_FLAG_FACING_TARGET_TO_RANGE_ATTACK = 87;
public const DATA_FLAG_HIDDEN_WHEN_INVISIBLE = 88; //??????????????????
public const DATA_FLAG_IS_IN_UI = 89;
public const DATA_FLAG_STALKING = 90;
public const DATA_FLAG_EMOTING = 91;
public const DATA_FLAG_CELEBRATING = 92;
public const DATA_FLAG_ADMIRING = 93;
public const DATA_FLAG_CELEBRATING_SPECIAL = 94;
public const DATA_PLAYER_FLAG_SLEEP = 1;
public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK

View File

@ -28,7 +28,9 @@ use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\MobArmorEquipmentPacket;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function array_map;
use function array_merge;
class ArmorInventory extends BaseInventory{
@ -109,7 +111,7 @@ class ArmorInventory extends BaseInventory{
$pk2 = new InventorySlotPacket();
$pk2->windowId = $player->getWindowId($this);
$pk2->inventorySlot = $index;
$pk2->item = $this->getItem($index);
$pk2->item = ItemStackWrapper::legacy($this->getItem($index));
$player->dataPacket($pk2);
}else{
$player->dataPacket($pk);
@ -134,7 +136,7 @@ class ArmorInventory extends BaseInventory{
if($player === $this->getHolder()){
$pk2 = new InventoryContentPacket();
$pk2->windowId = $player->getWindowId($this);
$pk2->items = $this->getContents(true);
$pk2->items = array_map([ItemStackWrapper::class, 'legacy'], $this->getContents(true));
$player->dataPacket($pk2);
}else{
$player->dataPacket($pk);

View File

@ -31,7 +31,9 @@ use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\InventorySlotPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use pocketmine\Player;
use function array_map;
use function array_slice;
use function count;
use function max;
@ -433,7 +435,7 @@ abstract class BaseInventory implements Inventory{
}
$pk = new InventoryContentPacket();
$pk->items = $this->getContents(true);
$pk->items = array_map([ItemStackWrapper::class, 'legacy'], $this->getContents(true));
foreach($target as $player){
if(($id = $player->getWindowId($this)) === ContainerIds::NONE){
@ -455,7 +457,7 @@ abstract class BaseInventory implements Inventory{
$pk = new InventorySlotPacket();
$pk->inventorySlot = $index;
$pk->item = $this->getItem($index);
$pk->item = ItemStackWrapper::legacy($this->getItem($index));
foreach($target as $player){
if(($id = $player->getWindowId($this)) === ContainerIds::NONE){

View File

@ -26,10 +26,12 @@ namespace pocketmine\inventory;
use pocketmine\entity\Human;
use pocketmine\event\player\PlayerItemHeldEvent;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\InventoryContentPacket;
use pocketmine\network\mcpe\protocol\CreativeContentPacket;
use pocketmine\network\mcpe\protocol\MobEquipmentPacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\network\mcpe\protocol\types\inventory\CreativeContentEntry;
use pocketmine\Player;
use function array_map;
use function in_array;
use function is_array;
@ -196,16 +198,11 @@ class PlayerInventory extends BaseInventory{
if(!($holder instanceof Player)){
throw new \LogicException("Cannot send creative inventory contents to non-player inventory holder");
}
$pk = new InventoryContentPacket();
$pk->windowId = ContainerIds::CREATIVE;
if(!$holder->isSpectator()){ //fill it for all gamemodes except spectator
foreach(Item::getCreativeItems() as $i => $item){
$pk->items[$i] = clone $item;
}
}
$holder->dataPacket($pk);
$nextEntryId = 1;
$holder->sendDataPacket(CreativeContentPacket::create(array_map(function(Item $item) use (&$nextEntryId) : CreativeContentEntry{
return new CreativeContentEntry($nextEntryId++, clone $item);
}, $holder->isSpectator() ? [] : Item::getCreativeItems()))); //fill it for all gamemodes except spectator
}
/**

View File

@ -27,7 +27,7 @@ use pocketmine\event\inventory\CraftItemEvent;
use pocketmine\inventory\CraftingRecipe;
use pocketmine\item\Item;
use pocketmine\network\mcpe\protocol\ContainerClosePacket;
use pocketmine\network\mcpe\protocol\types\ContainerIds;
use pocketmine\Player;
use function array_pop;
use function count;
use function intdiv;
@ -165,7 +165,7 @@ class CraftingTransaction extends InventoryTransaction{
* transaction goes wrong.
*/
$pk = new ContainerClosePacket();
$pk->windowId = ContainerIds::NONE;
$pk->windowId = Player::HARDCODED_CRAFTING_GRID_WINDOW_ID;
$this->source->dataPacket($pk);
}

View File

@ -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;

View File

@ -72,6 +72,7 @@ use pocketmine\metadata\Metadatable;
use pocketmine\metadata\MetadataValue;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\AddActorPacket;
use pocketmine\network\mcpe\protocol\BatchPacket;
use pocketmine\network\mcpe\protocol\DataPacket;
@ -79,7 +80,6 @@ use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\SetDifficultyPacket;
use pocketmine\network\mcpe\protocol\SetTimePacket;
use pocketmine\network\mcpe\protocol\types\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\Player;
use pocketmine\plugin\Plugin;

View File

@ -471,7 +471,7 @@ class NetworkBinaryStream extends BinaryStream{
/**
* Reads and returns an EntityUniqueID
*/
public function getEntityUniqueId() : int{
final public function getEntityUniqueId() : int{
return $this->getVarLong();
}
@ -485,7 +485,7 @@ class NetworkBinaryStream extends BinaryStream{
/**
* Reads and returns an EntityRuntimeID
*/
public function getEntityRuntimeId() : int{
final public function getEntityRuntimeId() : int{
return $this->getUnsignedVarLong();
}
@ -648,7 +648,8 @@ class NetworkBinaryStream 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);
}
protected function putEntityLink(EntityLink $link) : void{
@ -656,6 +657,7 @@ class NetworkBinaryStream extends BinaryStream{
$this->putEntityUniqueId($link->toEntityUniqueId);
$this->putByte($link->type);
$this->putBool($link->immediate);
$this->putBool($link->causedByRider);
}
protected function getCommandOriginData() : CommandOriginData{
@ -747,4 +749,12 @@ class NetworkBinaryStream extends BinaryStream{
$this->putStructureSettings($structureEditorData->structureSettings);
$this->putVarInt($structureEditorData->structureRedstoneSaveMove);
}
public function readGenericTypeNetworkId() : int{
return $this->getVarInt();
}
public function writeGenericTypeNetworkId(int $id) : void{
$this->putVarInt($id);
}
}

View File

@ -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,9 +62,12 @@ 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\DataPacket;
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;
@ -74,6 +78,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\NetworkSettingsPacket;
use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket;
use pocketmine\network\mcpe\protocol\NpcRequestPacket;
use pocketmine\network\mcpe\protocol\OnScreenTextureAnimationPacket;
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;
abstract class NetworkSession{
@ -666,10 +677,6 @@ abstract class NetworkSession{
return false;
}
public function handleVideoStreamConnect(VideoStreamConnectPacket $packet) : bool{
return false;
}
public function handleAddEntity(AddEntityPacket $packet) : bool{
return false;
}
@ -741,4 +748,52 @@ abstract class NetworkSession{
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;
}
}

View File

@ -53,7 +53,7 @@ class RakLibInterface implements ServerInstance, AdvancedSourceInterface{
* 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;
/** @var Server */
private $server;

View File

@ -0,0 +1,58 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\convert;
use pocketmine\nbt\tag\CompoundTag;
final class R12ToCurrentBlockMapEntry{
/** @var string */
private $id;
/** @var int */
private $meta;
/** @var CompoundTag */
private $blockState;
public function __construct(string $id, int $meta, CompoundTag $blockState){
$this->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";
}
}

View File

@ -21,13 +21,14 @@
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
namespace pocketmine\network\mcpe\convert;
use pocketmine\block\BlockIds;
use pocketmine\nbt\NBT;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function file_get_contents;
use function getmypid;
use function json_decode;
@ -66,9 +67,22 @@ final class RuntimeBlockMapping{
private static function setupLegacyMappings() : void{
$legacyIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/block_id_map.json"), true);
$legacyStateMap = (new NetworkLittleEndianNBTStream())->read(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.nbt"));
if(!($legacyStateMap instanceof ListTag) or $legacyStateMap->getTagType() !== NBT::TAG_Compound){
throw new \RuntimeException("Invalid legacy states mapping table, expected TAG_List<TAG_Compound> root");
/** @var R12ToCurrentBlockMapEntry[] $legacyStateMap */
$legacyStateMap = [];
$legacyStateMapReader = new NetworkBinaryStream(file_get_contents(\pocketmine\RESOURCE_PATH . "vanilla/r12_to_current_block_map.bin"));
$nbtReader = new NetworkLittleEndianNBTStream();
while(!$legacyStateMapReader->feof()){
$id = $legacyStateMapReader->getString();
$meta = $legacyStateMapReader->getLShort();
$offset = $legacyStateMapReader->getOffset();
$state = $nbtReader->read($legacyStateMapReader->getBuffer(), false, $offset);
$legacyStateMapReader->setOffset($offset);
if(!($state instanceof CompoundTag)){
throw new \RuntimeException("Blockstate should be a TAG_Compound");
}
$legacyStateMap[] = new R12ToCurrentBlockMapEntry($id, $meta, $state);
}
/**
@ -78,16 +92,17 @@ final class RuntimeBlockMapping{
foreach(self::$bedrockKnownStates as $k => $state){
$idToStatesMap[$state->getCompoundTag("block")->getString("name")][] = $k;
}
/** @var CompoundTag $pair */
foreach($legacyStateMap as $pair){
$oldState = $pair->getCompoundTag("old");
$id = $legacyIdMap[$oldState->getString("name")];
$data = $oldState->getShort("val");
$id = $legacyIdMap[$pair->getId()] ?? null;
if($id === null){
throw new \RuntimeException("No legacy ID matches " . $pair->getId());
}
$data = $pair->getMeta();
if($data > 15){
//we can't handle metadata with more than 4 bits
continue;
}
$mappedState = $pair->getCompoundTag("new");
$mappedState = $pair->getBlockState();
//TODO HACK: idiotic NBT compare behaviour on 3.x compares keys which are stored by values
$mappedState->setName("block");

View File

@ -87,6 +87,7 @@ class ActorEventPacket extends DataPacket{
public const TREASURE_HUNT = 72;
public const AGENT_SUMMON = 73;
public const CHARGED_CROSSBOW = 74;
public const FALL = 75;
//TODO: add more events

View File

@ -32,6 +32,7 @@ use function get_class;
use function strlen;
use function zlib_decode;
use function zlib_encode;
use const ZLIB_ENCODING_RAW;
#ifndef COMPILE
use pocketmine\utils\Binary;
#endif
@ -71,7 +72,7 @@ class BatchPacket extends DataPacket{
}
protected function encodePayload(){
$this->put(zlib_encode($this->payload, ZLIB_ENCODING_DEFLATE, $this->compressionLevel));
$this->put(zlib_encode($this->payload, ZLIB_ENCODING_RAW, $this->compressionLevel));
}
/**

View File

@ -0,0 +1,66 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->url = $this->getString();
$this->openCodeBuilder = $this->getBool();
}
protected function encodePayload() : void{
$this->putString($this->url);
$this->putBool($this->openCodeBuilder);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleCodeBuilder($this);
}
}

View File

@ -97,6 +97,7 @@ class CraftingDataPacket extends DataPacket{
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
$entry["priority"] = $this->getVarInt();
$entry["net_id"] = $this->readGenericTypeNetworkId();
break;
case self::ENTRY_SHAPED:
@ -118,6 +119,7 @@ class CraftingDataPacket extends DataPacket{
$entry["uuid"] = $this->getUUID()->toString();
$entry["block"] = $this->getString();
$entry["priority"] = $this->getVarInt();
$entry["net_id"] = $this->readGenericTypeNetworkId();
break;
case self::ENTRY_FURNACE:
@ -140,6 +142,7 @@ class CraftingDataPacket extends DataPacket{
break;
case self::ENTRY_MULTI:
$entry["uuid"] = $this->getUUID()->toString();
$entry["net_id"] = $this->readGenericTypeNetworkId();
break;
default:
throw new \UnexpectedValueException("Unhandled recipe type $recipeType!"); //do not continue attempting to decode
@ -148,9 +151,12 @@ class CraftingDataPacket extends DataPacket{
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$input = $this->getVarInt();
$inputMeta = $this->getVarInt();
$ingredient = $this->getVarInt();
$ingredientMeta = $this->getVarInt();
$output = $this->getVarInt();
$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $ingredient, $output);
$outputMeta = $this->getVarInt();
$this->potionTypeRecipes[] = new PotionTypeRecipe($input, $inputMeta, $ingredient, $ingredientMeta, $output, $outputMeta);
}
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$input = $this->getVarInt();
@ -193,6 +199,7 @@ class CraftingDataPacket extends DataPacket{
$stream->put(str_repeat("\x00", 16)); //Null UUID
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
$stream->putVarInt(50); //TODO: priority
$stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network
return CraftingDataPacket::ENTRY_SHAPELESS;
}
@ -217,6 +224,7 @@ class CraftingDataPacket extends DataPacket{
$stream->put(str_repeat("\x00", 16)); //Null UUID
$stream->putString("crafting_table"); //TODO: blocktype (no prefix) (this might require internal API breaks)
$stream->putVarInt(50); //TODO: priority
$stream->writeGenericTypeNetworkId($pos); //TODO: ANOTHER recipe ID, only used on the network
return CraftingDataPacket::ENTRY_SHAPED;
}
@ -272,9 +280,12 @@ class CraftingDataPacket extends DataPacket{
}
$this->putUnsignedVarInt(count($this->potionTypeRecipes));
foreach($this->potionTypeRecipes as $recipe){
$this->putVarInt($recipe->getInputPotionType());
$this->putVarInt($recipe->getInputItemId());
$this->putVarInt($recipe->getInputItemMeta());
$this->putVarInt($recipe->getIngredientItemId());
$this->putVarInt($recipe->getOutputPotionType());
$this->putVarInt($recipe->getIngredientItemMeta());
$this->putVarInt($recipe->getOutputItemId());
$this->putVarInt($recipe->getOutputItemMeta());
}
$this->putUnsignedVarInt(count($this->potionContainerRecipes));
foreach($this->potionContainerRecipes as $recipe){

View File

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->entries = [];
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->entries[] = CreativeContentEntry::read($this);
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->entries));
foreach($this->entries as $entry){
$entry->write($this);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleCreativeContent($this);
}
}

View File

@ -0,0 +1,65 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->entityUniqueId = $this->getEntityUniqueId();
$this->data = $this->getString();
}
protected function encodePayload() : void{
$this->putEntityUniqueId($this->entityUniqueId);
$this->putString($this->data);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleDebugInfo($this);
}
}

View File

@ -32,12 +32,21 @@ class EducationSettingsPacket extends DataPacket{
/** @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{
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() : void{
$this->codeBuilderDefaultUri = $this->getString();
$this->codeBuilderTitle = $this->getString();
$this->canResizeCodeBuilder = $this->getBool();
if($this->getBool()){
$this->codeBuilderOverrideUri = $this->getString();
}else{
$this->codeBuilderOverrideUri = null;
}
$this->hasQuiz = $this->getBool();
}
protected function encodePayload() : void{
$this->putString($this->codeBuilderDefaultUri);
$this->putString($this->codeBuilderTitle);
$this->putBool($this->canResizeCodeBuilder);
$this->putBool($this->codeBuilderOverrideUri !== null);
if($this->codeBuilderOverrideUri !== null){
$this->putString($this->codeBuilderOverrideUri);
}
$this->putBool($this->hasQuiz);
}

View File

@ -0,0 +1,74 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\utils\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() : void{
$this->playerEntityRuntimeId = $this->getEntityRuntimeId();
$this->emoteIds = [];
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->emoteIds[] = $this->getUUID();
}
}
protected function encodePayload() : void{
$this->putEntityRuntimeId($this->playerEntityRuntimeId);
$this->putUnsignedVarInt(count($this->emoteIds));
foreach($this->emoteIds as $emoteId){
$this->putUUID($emoteId);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleEmoteList($this);
}
}

View File

@ -30,14 +30,18 @@ use pocketmine\network\mcpe\NetworkSession;
class HurtArmorPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::HURT_ARMOR_PACKET;
/** @var int */
public $cause;
/** @var int */
public $health;
protected function decodePayload(){
$this->cause = $this->getVarInt();
$this->health = $this->getVarInt();
}
protected function encodePayload(){
$this->putVarInt($this->cause);
$this->putVarInt($this->health);
}

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
use function count;
class InventoryContentPacket extends DataPacket{
@ -34,14 +34,14 @@ class InventoryContentPacket extends DataPacket{
/** @var int */
public $windowId;
/** @var Item[] */
/** @var ItemStackWrapper[] */
public $items = [];
protected function decodePayload(){
$this->windowId = $this->getUnsignedVarInt();
$count = $this->getUnsignedVarInt();
for($i = 0; $i < $count; ++$i){
$this->items[] = $this->getSlot();
$this->items[] = ItemStackWrapper::read($this);
}
}
@ -49,7 +49,7 @@ class InventoryContentPacket extends DataPacket{
$this->putUnsignedVarInt($this->windowId);
$this->putUnsignedVarInt(count($this->items));
foreach($this->items as $item){
$this->putSlot($item);
$item->write($this);
}
}

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\ItemStackWrapper;
class InventorySlotPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::INVENTORY_SLOT_PACKET;
@ -35,19 +35,19 @@ class InventorySlotPacket extends DataPacket{
public $windowId;
/** @var int */
public $inventorySlot;
/** @var Item */
/** @var ItemStackWrapper */
public $item;
protected function decodePayload(){
$this->windowId = $this->getUnsignedVarInt();
$this->inventorySlot = $this->getUnsignedVarInt();
$this->item = $this->getSlot();
$this->item = ItemStackWrapper::read($this);
}
protected function encodePayload(){
$this->putUnsignedVarInt($this->windowId);
$this->putUnsignedVarInt($this->inventorySlot);
$this->putSlot($this->item);
$this->item->write($this);
}
public function handle(NetworkSession $session) : bool{

View File

@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\inventory\InventoryTransactionChangedSlotsHack;
use pocketmine\network\mcpe\protocol\types\NetworkInventoryAction;
use function count;
@ -48,8 +49,15 @@ class InventoryTransactionPacket extends DataPacket{
public const USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0;
public const USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1;
/** @var int */
public $requestId;
/** @var InventoryTransactionChangedSlotsHack[] */
public $requestChangedSlots;
/** @var int */
public $transactionType;
/** @var bool */
public $hasItemStackIds;
/** @var NetworkInventoryAction[] */
public $actions = [];
@ -58,10 +66,20 @@ class InventoryTransactionPacket extends DataPacket{
public $trData;
protected function decodePayload(){
$this->requestId = $this->readGenericTypeNetworkId();
$this->requestChangedSlots = [];
if($this->requestId !== 0){
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->requestChangedSlots[] = InventoryTransactionChangedSlotsHack::read($this);
}
}
$this->transactionType = $this->getUnsignedVarInt();
$this->hasItemStackIds = $this->getBool();
for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){
$this->actions[] = $action = (new NetworkInventoryAction())->read($this);
$this->actions[] = $action = (new NetworkInventoryAction())->read($this, $this->hasItemStackIds);
}
$this->trData = new \stdClass();
@ -101,11 +119,19 @@ class InventoryTransactionPacket extends DataPacket{
}
protected function encodePayload(){
$this->writeGenericTypeNetworkId($this->requestId);
if($this->requestId !== 0){
$this->putUnsignedVarInt(count($this->requestChangedSlots));
foreach($this->requestChangedSlots as $changedSlots){
$changedSlots->write($this);
}
}
$this->putUnsignedVarInt($this->transactionType);
$this->putUnsignedVarInt(count($this->actions));
foreach($this->actions as $action){
$action->write($this);
$action->write($this, $this->hasItemStackIds);
}
switch($this->transactionType){

View File

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->requests = [];
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->requests[] = ItemStackRequest::read($this);
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->requests));
foreach($this->requests as $request){
$request->write($this);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleItemStackRequest($this);
}
}

View File

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->responses = [];
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->responses[] = ItemStackResponse::read($this);
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->responses));
foreach($this->responses as $response){
$response->write($this);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleItemStackResponse($this);
}
}

View File

@ -159,7 +159,6 @@ class PacketPool{
static::registerPacket(new LevelSoundEventPacket());
static::registerPacket(new LevelEventGenericPacket());
static::registerPacket(new LecternUpdatePacket());
static::registerPacket(new VideoStreamConnectPacket());
static::registerPacket(new AddEntityPacket());
static::registerPacket(new RemoveEntityPacket());
static::registerPacket(new ClientCacheStatusPacket());
@ -178,6 +177,18 @@ class PacketPool{
static::registerPacket(new CompletedUsingItemPacket());
static::registerPacket(new NetworkSettingsPacket());
static::registerPacket(new PlayerAuthInputPacket());
static::registerPacket(new CreativeContentPacket());
static::registerPacket(new PlayerEnchantOptionsPacket());
static::registerPacket(new ItemStackRequestPacket());
static::registerPacket(new ItemStackResponsePacket());
static::registerPacket(new PlayerArmorDamagePacket());
static::registerPacket(new CodeBuilderPacket());
static::registerPacket(new UpdatePlayerGameTypePacket());
static::registerPacket(new EmoteListPacket());
static::registerPacket(new PositionTrackingDBServerBroadcastPacket());
static::registerPacket(new PositionTrackingDBClientRequestPacket());
static::registerPacket(new DebugInfoPacket());
static::registerPacket(new PacketViolationWarningPacket());
}
/**

View File

@ -0,0 +1,84 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->type = $this->getVarInt();
$this->severity = $this->getVarInt();
$this->packetId = $this->getVarInt();
$this->message = $this->getString();
}
protected function encodePayload() : void{
$this->putVarInt($this->type);
$this->putVarInt($this->severity);
$this->putVarInt($this->packetId);
$this->putString($this->message);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePacketViolationWarning($this);
}
}

View File

@ -50,7 +50,7 @@ class PlayerActionPacket extends DataPacket{
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;

View File

@ -0,0 +1,108 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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) : ?int{
if(($flags & (1 << $flag)) !== 0){
return $this->getVarInt();
}
return null;
}
protected function decodePayload() : void{
$flags = $this->getByte();
$this->headSlotDamage = $this->maybeReadDamage($flags, self::FLAG_HEAD);
$this->chestSlotDamage = $this->maybeReadDamage($flags, self::FLAG_CHEST);
$this->legsSlotDamage = $this->maybeReadDamage($flags, self::FLAG_LEGS);
$this->feetSlotDamage = $this->maybeReadDamage($flags, self::FLAG_FEET);
}
private function composeFlag(?int $field, int $flag) : int{
return $field !== null ? (1 << $flag) : 0;
}
private function maybeWriteDamage(?int $field) : void{
if($field !== null){
$this->putVarInt($field);
}
}
protected function encodePayload() : void{
$this->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);
$this->maybeWriteDamage($this->chestSlotDamage);
$this->maybeWriteDamage($this->legsSlotDamage);
$this->maybeWriteDamage($this->feetSlotDamage);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePlayerArmorDamage($this);
}
}

View File

@ -0,0 +1,69 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->options = [];
for($i = 0, $len = $this->getUnsignedVarInt(); $i < $len; ++$i){
$this->options[] = EnchantOption::read($this);
}
}
protected function encodePayload() : void{
$this->putUnsignedVarInt(count($this->options));
foreach($this->options as $option){
$option->write($this);
}
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePlayerEnchantOptions($this);
}
}

View File

@ -27,40 +27,38 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->serverUri = $this->getString();
$this->frameSendFrequency = $this->getLFloat();
$this->action = $this->getByte();
$this->resolutionX = $this->getLInt();
$this->resolutionY = $this->getLInt();
$this->trackingId = $this->getVarInt();
}
protected function encodePayload() : void{
$this->putString($this->serverUri);
$this->putLFloat($this->frameSendFrequency);
$this->putByte($this->action);
$this->putLInt($this->resolutionX);
$this->putLInt($this->resolutionY);
$this->putVarInt($this->trackingId);
}
public function handle(NetworkSession $session) : bool{
return $session->handleVideoStreamConnect($this);
public function handle(NetworkSession $handler) : bool{
return $handler->handlePositionTrackingDBClientRequest($this);
}
}

View File

@ -0,0 +1,81 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\network\mcpe\NetworkSession;
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 CompoundTag */
private $nbt;
public static function create(int $action, int $trackingId, CompoundTag $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; }
public function getNbt() : CompoundTag{ return $this->nbt; }
protected function decodePayload() : void{
$this->action = $this->getByte();
$this->trackingId = $this->getVarInt();
$offset = $this->getOffset();
$nbt = (new NetworkLittleEndianNBTStream())->read($this->getBuffer(), false, $offset);
$this->setOffset($offset);
if(!($nbt instanceof CompoundTag)){
throw new \UnexpectedValueException("Expected TAG_Compound");
}
$this->nbt = $nbt;
}
protected function encodePayload() : void{
$this->putByte($this->action);
$this->putVarInt($this->trackingId);
$this->put((new NetworkLittleEndianNBTStream())->write($this->nbt));
}
public function handle(NetworkSession $handler) : bool{
return $handler->handlePositionTrackingDBServerBroadcast($this);
}
}

View File

@ -37,11 +37,11 @@ interface 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;
@ -168,7 +168,7 @@ interface 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;
@ -187,5 +187,17 @@ interface 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;
}

View File

@ -41,19 +41,27 @@ class SetSpawnPositionPacket extends DataPacket{
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;
protected function decodePayload(){
$this->spawnType = $this->getVarInt();
$this->getBlockPosition($this->x, $this->y, $this->z);
$this->spawnForced = $this->getBool();
$this->dimension = $this->getVarInt();
$this->getBlockPosition($this->x2, $this->y2, $this->z2);
}
protected function encodePayload(){
$this->putVarInt($this->spawnType);
$this->putBlockPosition($this->x, $this->y, $this->z);
$this->putBool($this->spawnForced);
$this->putVarInt($this->dimension);
$this->putBlockPosition($this->x2, $this->y2, $this->z2);
}
public function handle(NetworkSession $session) : bool{

View File

@ -28,6 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\ListTag;
use pocketmine\network\mcpe\convert\RuntimeBlockMapping;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\EducationEditionOffer;
@ -35,7 +36,7 @@ use pocketmine\network\mcpe\protocol\types\GameRuleType;
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\RuntimeBlockMapping;
use pocketmine\network\mcpe\protocol\types\SpawnSettings;
use function count;
use function file_get_contents;
use function json_decode;
@ -66,8 +67,8 @@ class StartGamePacket extends DataPacket{
/** @var int */
public $seed;
/** @var int */
public $dimension;
/** @var SpawnSettings */
public $spawnSettings;
/** @var int */
public $generator = GeneratorType::OVERWORLD;
/** @var int */
@ -88,6 +89,8 @@ class StartGamePacket extends DataPacket{
public $eduEditionOffer = EducationEditionOffer::NONE;
/** @var bool */
public $hasEduFeaturesEnabled = false;
/** @var string */
public $eduProductUUID = "";
/** @var float */
public $rainLevel;
/** @var float */
@ -137,9 +140,17 @@ class StartGamePacket extends DataPacket{
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 */
@ -164,6 +175,8 @@ class StartGamePacket extends DataPacket{
* @phpstan-var array<string, int>|null
*/
public $itemTable = null;
/** @var bool */
public $enableNewInventorySystem = false; //TODO
protected function decodePayload(){
$this->entityUniqueId = $this->getEntityUniqueId();
@ -177,7 +190,7 @@ class StartGamePacket extends DataPacket{
//Level settings
$this->seed = $this->getVarInt();
$this->dimension = $this->getVarInt();
$this->spawnSettings = SpawnSettings::read($this);
$this->generator = $this->getVarInt();
$this->worldGamemode = $this->getVarInt();
$this->difficulty = $this->getVarInt();
@ -186,6 +199,7 @@ class StartGamePacket extends DataPacket{
$this->time = $this->getVarInt();
$this->eduEditionOffer = $this->getVarInt();
$this->hasEduFeaturesEnabled = $this->getBool();
$this->eduProductUUID = $this->getString();
$this->rainLevel = $this->getLFloat();
$this->lightningLevel = $this->getLFloat();
$this->hasConfirmedPlatformLockedContent = $this->getBool();
@ -207,8 +221,16 @@ class StartGamePacket extends DataPacket{
$this->isFromWorldTemplate = $this->getBool();
$this->isWorldTemplateOptionLocked = $this->getBool();
$this->onlySpawnV1Villagers = $this->getBool();
$this->vanillaVersion = $this->getString();
$this->limitedWorldWidth = $this->getLInt();
$this->limitedWorldLength = $this->getLInt();
$this->isNewNether = $this->getBool();
if($this->getBool()){
$this->experimentalGameplayOverride = $this->getBool();
}else{
$this->experimentalGameplayOverride = null;
}
$this->levelId = $this->getString();
$this->worldName = $this->getString();
$this->premiumWorldTemplateId = $this->getString();
@ -233,6 +255,7 @@ class StartGamePacket extends DataPacket{
}
$this->multiplayerCorrelationId = $this->getString();
$this->enableNewInventorySystem = $this->getBool();
}
protected function encodePayload(){
@ -247,7 +270,7 @@ class StartGamePacket extends DataPacket{
//Level settings
$this->putVarInt($this->seed);
$this->putVarInt($this->dimension);
$this->spawnSettings->write($this);
$this->putVarInt($this->generator);
$this->putVarInt($this->worldGamemode);
$this->putVarInt($this->difficulty);
@ -256,6 +279,7 @@ class StartGamePacket extends DataPacket{
$this->putVarInt($this->time);
$this->putVarInt($this->eduEditionOffer);
$this->putBool($this->hasEduFeaturesEnabled);
$this->putString($this->eduProductUUID);
$this->putLFloat($this->rainLevel);
$this->putLFloat($this->lightningLevel);
$this->putBool($this->hasConfirmedPlatformLockedContent);
@ -277,8 +301,15 @@ class StartGamePacket extends DataPacket{
$this->putBool($this->isFromWorldTemplate);
$this->putBool($this->isWorldTemplateOptionLocked);
$this->putBool($this->onlySpawnV1Villagers);
$this->putString($this->vanillaVersion);
$this->putLInt($this->limitedWorldWidth);
$this->putLInt($this->limitedWorldLength);
$this->putBool($this->isNewNether);
$this->putBool($this->experimentalGameplayOverride !== null);
if($this->experimentalGameplayOverride !== null){
$this->putBool($this->experimentalGameplayOverride);
}
$this->putString($this->levelId);
$this->putString($this->worldName);
$this->putString($this->premiumWorldTemplateId);
@ -307,6 +338,7 @@ class StartGamePacket extends DataPacket{
}
$this->putString($this->multiplayerCorrelationId);
$this->putBool($this->enableNewInventorySystem);
}
/**

View File

@ -40,7 +40,8 @@ class TextPacket extends DataPacket{
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;
@ -69,6 +70,7 @@ class TextPacket extends DataPacket{
case self::TYPE_RAW:
case self::TYPE_TIP:
case self::TYPE_SYSTEM:
case self::TYPE_JSON_WHISPER:
case self::TYPE_JSON:
$this->message = $this->getString();
break;
@ -100,6 +102,7 @@ class TextPacket extends DataPacket{
case self::TYPE_RAW:
case self::TYPE_TIP:
case self::TYPE_SYSTEM:
case self::TYPE_JSON_WHISPER:
case self::TYPE_JSON:
$this->putString($this->message);
break;

View File

@ -0,0 +1,67 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
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() : void{
$this->gameMode = $this->getVarInt();
$this->playerEntityUniqueId = $this->getEntityUniqueId();
}
protected function encodePayload() : void{
$this->putVarInt($this->gameMode);
$this->putEntityUniqueId($this->playerEntityUniqueId);
}
public function handle(NetworkSession $handler) : bool{
return $handler->handleUpdatePlayerGameType($this);
}
}

View File

@ -31,7 +31,7 @@ interface 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;

View File

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class Enchant{
/** @var int */
private $id;
/** @var int */
private $level;
public function __construct(int $id, int $level){
$this->id = $id;
$this->level = $level;
}
public function getId() : int{ return $this->id; }
public function getLevel() : int{ return $this->level; }
public static function read(NetworkBinaryStream $in) : self{
$id = $in->getByte();
$level = $in->getByte();
return new self($id, $level);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->id);
$out->putByte($this->level);
}
}

View File

@ -0,0 +1,126 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
final class EnchantOption{
/** @var int */
private $cost;
/** @var int */
private $slotFlags;
/** @var Enchant[] */
private $equipActivatedEnchantments;
/** @var Enchant[] */
private $heldActivatedEnchantments;
/** @var Enchant[] */
private $selfActivatedEnchantments;
/** @var string */
private $name;
/** @var int */
private $optionId;
/**
* @param Enchant[] $equipActivatedEnchantments
* @param Enchant[] $heldActivatedEnchantments
* @param Enchant[] $selfActivatedEnchantments
*/
public function __construct(int $cost, int $slotFlags, array $equipActivatedEnchantments, array $heldActivatedEnchantments, array $selfActivatedEnchantments, string $name, int $optionId){
$this->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(NetworkBinaryStream $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(NetworkBinaryStream $out, array $list) : void{
$out->putUnsignedVarInt(count($list));
foreach($list as $item){
$item->write($out);
}
}
public static function read(NetworkBinaryStream $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(NetworkBinaryStream $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);
}
}

View File

@ -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;
}
}

View File

@ -81,11 +81,13 @@ class NetworkInventoryAction{
public $oldItem;
/** @var Item */
public $newItem;
/** @var int|null */
public $newItemStackId = null;
/**
* @return $this
*/
public function read(NetworkBinaryStream $packet){
public function read(NetworkBinaryStream $packet, bool $hasItemStackIds){
$this->sourceType = $packet->getUnsignedVarInt();
switch($this->sourceType){
@ -107,6 +109,9 @@ class NetworkInventoryAction{
$this->inventorySlot = $packet->getUnsignedVarInt();
$this->oldItem = $packet->getSlot();
$this->newItem = $packet->getSlot();
if($hasItemStackIds){
$this->newItemStackId = $packet->readGenericTypeNetworkId();
}
return $this;
}
@ -114,7 +119,7 @@ class NetworkInventoryAction{
/**
* @return void
*/
public function write(NetworkBinaryStream $packet){
public function write(NetworkBinaryStream $packet, bool $hasItemStackIds){
$packet->putUnsignedVarInt($this->sourceType);
switch($this->sourceType){
@ -136,6 +141,12 @@ 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);
}
}
/**

View File

@ -25,27 +25,48 @@ namespace pocketmine\network\mcpe\protocol\types;
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;
}
}

View File

@ -0,0 +1,73 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class SpawnSettings{
public const BIOME_TYPE_DEFAULT = 0;
public const BIOME_TYPE_USER_DEFINED = 1;
/** @var int */
private $biomeType;
/** @var string */
private $biomeName;
/** @var int */
private $dimension;
public function __construct(int $biomeType, string $biomeName, int $dimension){
$this->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(NetworkBinaryStream $in) : self{
$biomeType = $in->getLShort();
$biomeName = $in->getString();
$dimension = $in->getVarInt();
return new self($biomeType, $biomeName, $dimension);
}
public function write(NetworkBinaryStream $out) : void{
$out->putLShort($this->biomeType);
$out->putString($this->biomeName);
$out->putVarInt($this->dimension);
}
}

View File

@ -59,5 +59,8 @@ interface 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;
}

View File

@ -0,0 +1,55 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class CreativeContentEntry{
/** @var int */
private $entryId;
/** @var Item */
private $item;
public function __construct(int $entryId, Item $item){
$this->entryId = $entryId;
$this->item = $item;
}
public function getEntryId() : int{ return $this->entryId; }
public function getItem() : Item{ return $this->item; }
public static function read(NetworkBinaryStream $in) : self{
$entryId = $in->readGenericTypeNetworkId();
$item = $in->getSlot();
return new self($entryId, $item);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->entryId);
$out->putSlot($this->item);
}
}

View File

@ -0,0 +1,65 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
final class InventoryTransactionChangedSlotsHack{
/** @var int */
private $containerId;
/** @var int[] */
private $changedSlotIndexes;
/**
* @param int[] $changedSlotIndexes
*/
public function __construct(int $containerId, array $changedSlotIndexes){
$this->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(NetworkBinaryStream $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(NetworkBinaryStream $out) : void{
$out->putByte($this->containerId);
$out->putUnsignedVarInt(count($this->changedSlotIndexes));
foreach($this->changedSlotIndexes as $index){
$out->putByte($index);
}
}
}

View File

@ -0,0 +1,59 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory;
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class ItemStackWrapper{
/** @var int */
private $stackId;
/** @var Item */
private $itemStack;
public function __construct(int $stackId, Item $itemStack){
$this->stackId = $stackId;
$this->itemStack = $itemStack;
}
public static function legacy(Item $itemStack) : self{
return new self($itemStack->isNull() ? 0 : 1, $itemStack);
}
public function getStackId() : int{ return $this->stackId; }
public function getItemStack() : Item{ return $this->itemStack; }
public static function read(NetworkBinaryStream $in) : self{
$stackId = $in->readGenericTypeNetworkId();
$stack = $in->getSlot();
return new self($stackId, $stack);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->stackId);
$out->putSlot($this->itemStack);
}
}

View File

@ -0,0 +1,59 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Completes a transaction involving a beacon consuming input to produce effects.
*/
final class BeaconPaymentStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $primaryEffectId;
/** @var int */
private $secondaryEffectId;
public function __construct(int $primaryEffectId, int $secondaryEffectId){
$this->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(NetworkBinaryStream $in) : self{
$primary = $in->getVarInt();
$secondary = $in->getVarInt();
return new self($primary, $secondary);
}
public function write(NetworkBinaryStream $out) : void{
$out->putVarInt($this->primaryEffectId);
$out->putVarInt($this->secondaryEffectId);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Tells that the current transaction crafted the specified recipe, using the recipe book. This is effectively the same
* as the regular crafting result action.
*/
final class CraftRecipeAutoStackRequestAction extends ItemStackRequestAction{
use CraftRecipeStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE_AUTO; }
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Tells that the current transaction crafted the specified recipe.
*/
final class CraftRecipeStackRequestAction extends ItemStackRequestAction{
use CraftRecipeStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_RECIPE; }
}

View File

@ -0,0 +1,47 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
trait CraftRecipeStackRequestActionTrait{
/** @var int */
private $recipeId;
final public function __construct(int $recipeId){
$this->recipeId = $recipeId;
}
public function getRecipeId() : int{ return $this->recipeId; }
public static function read(NetworkBinaryStream $in) : self{
$recipeId = $in->readGenericTypeNetworkId();
return new self($recipeId);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->recipeId);
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Sends some (or all) items from the source slot to the magic place where crafting ingredients turn into result items.
*/
final class CraftingConsumeInputStackRequestAction extends ItemStackRequestAction{
use DisappearStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::CRAFTING_CONSUME_INPUT; }
}

View File

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* I have no clear idea what this does. It seems to be the client hinting to the server "hey, put a secondary output in
* X crafting grid slot". This is used for things like buckets.
*/
final class CraftingMarkSecondaryResultStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $craftingGridSlot;
public function __construct(int $craftingGridSlot){
$this->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(NetworkBinaryStream $in) : self{
$slot = $in->getByte();
return new self($slot);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->craftingGridSlot);
}
}

View File

@ -0,0 +1,52 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Creates an item by copying it from the creative inventory. This is treated as a crafting action by vanilla.
*/
final class CreativeCreateStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $creativeItemId;
public function __construct(int $creativeItemId){
$this->creativeItemId = $creativeItemId;
}
public function getCreativeItemId() : int{ return $this->creativeItemId; }
public static function getTypeId() : int{ return ItemStackRequestActionType::CREATIVE_CREATE; }
public static function read(NetworkBinaryStream $in) : self{
$creativeItemId = $in->readGenericTypeNetworkId();
return new self($creativeItemId);
}
public function write(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->creativeItemId);
}
}

View File

@ -0,0 +1,45 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Tells that the current transaction involves crafting an item in a way that isn't supported by the current system.
* At the time of writing, this includes using anvils.
*/
final class DeprecatedCraftingNonImplementedStackRequestAction extends ItemStackRequestAction{
public static function getTypeId() : int{
return ItemStackRequestActionType::CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING;
}
public static function read(NetworkBinaryStream $in) : self{
return new self;
}
public function write(NetworkBinaryStream $out) : void{
//NOOP
}
}

View File

@ -0,0 +1,74 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\item\Item;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
/**
* Not clear what this is needed for, but it is very clearly marked as deprecated, so hopefully it'll go away before I
* have to write a proper description for it.
*/
final class DeprecatedCraftingResultsStackRequestAction extends ItemStackRequestAction{
/** @var Item[] */
private $results;
/** @var int */
private $iterations;
/**
* @param Item[] $results
*/
public function __construct(array $results, int $iterations){
$this->results = $results;
$this->iterations = $iterations;
}
/** @return Item[] */
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(NetworkBinaryStream $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(NetworkBinaryStream $out) : void{
$out->putUnsignedVarInt(count($this->results));
foreach($this->results as $result){
$out->putSlot($result);
}
$out->putByte($this->iterations);
}
}

View File

@ -0,0 +1,34 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Sends some (or all) items from the source slot to /dev/null. This happens when the player clicks items into the
* creative inventory menu in creative mode.
*/
final class DestroyStackRequestAction extends ItemStackRequestAction{
use DisappearStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::DESTROY; }
}

View File

@ -0,0 +1,53 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
trait DisappearStackRequestActionTrait{
/** @var int */
private $count;
/** @var ItemStackRequestSlotInfo */
private $source;
final public function __construct(int $count, ItemStackRequestSlotInfo $source){
$this->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(NetworkBinaryStream $in) : self{
$count = $in->getByte();
$source = ItemStackRequestSlotInfo::read($in);
return new self($count, $source);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->count);
$this->source->write($out);
}
}

View File

@ -0,0 +1,66 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Drops some (or all) items from the source slot into the world as an item entity.
*/
final class DropStackRequestAction extends ItemStackRequestAction{
/** @var int */
private $count;
/** @var ItemStackRequestSlotInfo */
private $source;
/** @var bool */
private $randomly;
public function __construct(int $count, ItemStackRequestSlotInfo $source, bool $randomly){
$this->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(NetworkBinaryStream $in) : self{
$count = $in->getByte();
$source = ItemStackRequestSlotInfo::read($in);
$random = $in->getBool();
return new self($count, $source, $random);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->count);
$this->source->write($out);
$out->putBool($this->randomly);
}
}

View File

@ -0,0 +1,87 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
final class ItemStackRequest{
/** @var int */
private $requestId;
/** @var ItemStackRequestAction[] */
private $actions;
/**
* @param ItemStackRequestAction[] $actions
*/
public function __construct(int $requestId, array $actions){
$this->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(NetworkBinaryStream $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(NetworkBinaryStream $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(NetworkBinaryStream $out) : void{
$out->writeGenericTypeNetworkId($this->requestId);
$out->putUnsignedVarInt(count($this->actions));
foreach($this->actions as $action){
$out->putByte($action::getTypeId());
$action->write($out);
}
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
abstract class ItemStackRequestAction{
abstract public static function getTypeId() : int;
abstract public function write(NetworkBinaryStream $out) : void;
}

View File

@ -0,0 +1,46 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
final class ItemStackRequestActionType{
private function __construct(){
//NOOP
}
public const TAKE = 0;
public const PLACE = 1;
public const SWAP = 2;
public const DROP = 3;
public const DESTROY = 4;
public const CRAFTING_CONSUME_INPUT = 5;
public const CRAFTING_MARK_SECONDARY_RESULT_SLOT = 6;
public const LAB_TABLE_COMBINE = 7;
public const BEACON_PAYMENT = 8;
public const CRAFTING_RECIPE = 9;
public const CRAFTING_RECIPE_AUTO = 10; //recipe book?
public const CREATIVE_CREATE = 11;
public const CRAFTING_NON_IMPLEMENTED_DEPRECATED_ASK_TY_LAING = 12; //anvils aren't fully implemented yet
public const CRAFTING_RESULTS_DEPRECATED_ASK_TY_LAING = 13; //no idea what this is for
}

View File

@ -0,0 +1,61 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class ItemStackRequestSlotInfo{
/** @var int */
private $containerId;
/** @var int */
private $slotId;
/** @var int */
private $stackId;
public function __construct(int $containerId, int $slotId, int $stackId){
$this->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(NetworkBinaryStream $in) : self{
$containerId = $in->getByte();
$slotId = $in->getByte();
$stackId = $in->readGenericTypeNetworkId();
return new self($containerId, $slotId, $stackId);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->containerId);
$out->putByte($this->slotId);
$out->writeGenericTypeNetworkId($this->stackId);
}
}

View File

@ -0,0 +1,43 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Not clear what the point of this is. It's sent when the player uses a lab table, but it's not clear why this action
* is needed.
*/
final class LabTableCombineStackRequestAction extends ItemStackRequestAction{
public static function getTypeId() : int{ return ItemStackRequestActionType::LAB_TABLE_COMBINE; }
public static function read(NetworkBinaryStream $in) : self{
return new self;
}
public function write(NetworkBinaryStream $out) : void{
//NOOP
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Puts some (or all) of the items from the source slot into the destination slot.
*/
final class PlaceStackRequestAction extends ItemStackRequestAction{
use TakeOrPlaceStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::PLACE; }
}

View File

@ -0,0 +1,59 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
/**
* Swaps two stacks. These don't have to be in the same inventory. This action does not modify the stacks themselves.
*/
final class SwapStackRequestAction extends ItemStackRequestAction{
/** @var ItemStackRequestSlotInfo */
private $slot1;
/** @var ItemStackRequestSlotInfo */
private $slot2;
public function __construct(ItemStackRequestSlotInfo $slot1, ItemStackRequestSlotInfo $slot2){
$this->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(NetworkBinaryStream $in) : self{
$slot1 = ItemStackRequestSlotInfo::read($in);
$slot2 = ItemStackRequestSlotInfo::read($in);
return new self($slot1, $slot2);
}
public function write(NetworkBinaryStream $out) : void{
$this->slot1->write($out);
$this->slot2->write($out);
}
}

View File

@ -0,0 +1,61 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
use pocketmine\network\mcpe\NetworkBinaryStream;
trait TakeOrPlaceStackRequestActionTrait{
/** @var int */
private $count;
/** @var ItemStackRequestSlotInfo */
private $source;
/** @var ItemStackRequestSlotInfo */
private $destination;
final public function __construct(int $count, ItemStackRequestSlotInfo $source, ItemStackRequestSlotInfo $destination){
$this->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(NetworkBinaryStream $in) : self{
$count = $in->getByte();
$src = ItemStackRequestSlotInfo::read($in);
$dst = ItemStackRequestSlotInfo::read($in);
return new self($count, $src, $dst);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->count);
$this->source->write($out);
$this->destination->write($out);
}
}

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackrequest;
/**
* Takes some (or all) of the items from the source slot into the destination slot (usually the cursor?).
*/
final class TakeStackRequestAction extends ItemStackRequestAction{
use TakeOrPlaceStackRequestActionTrait;
public static function getTypeId() : int{ return ItemStackRequestActionType::TAKE; }
}

View File

@ -0,0 +1,72 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackresponse;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
final class ItemStackResponse{
/** @var bool */
private $ok;
/** @var int */
private $requestId;
/** @var ItemStackResponseContainerInfo[] */
private $containerInfos;
/**
* @param ItemStackResponseContainerInfo[] $containerInfos
*/
public function __construct(bool $ok, int $requestId, array $containerInfos){
$this->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(NetworkBinaryStream $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(NetworkBinaryStream $out) : void{
$out->putBool($this->ok);
$out->writeGenericTypeNetworkId($this->requestId);
$out->putUnsignedVarInt(count($this->containerInfos));
foreach($this->containerInfos as $containerInfo){
$containerInfo->write($out);
}
}
}

View File

@ -0,0 +1,65 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackresponse;
use pocketmine\network\mcpe\NetworkBinaryStream;
use function count;
final class ItemStackResponseContainerInfo{
/** @var int */
private $containerId;
/** @var ItemStackResponseSlotInfo[] */
private $slots;
/**
* @param ItemStackResponseSlotInfo[] $slots
*/
public function __construct(int $containerId, array $slots){
$this->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(NetworkBinaryStream $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(NetworkBinaryStream $out) : void{
$out->putByte($this->containerId);
$out->putUnsignedVarInt(count($this->slots));
foreach($this->slots as $slot){
$slot->write($out);
}
}
}

View File

@ -0,0 +1,68 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types\inventory\stackresponse;
use pocketmine\network\mcpe\NetworkBinaryStream;
final class ItemStackResponseSlotInfo{
/** @var int */
private $slot;
/** @var int */
private $hotbarSlot;
/** @var int */
private $count;
/** @var int */
private $itemStackId;
public function __construct(int $slot, int $hotbarSlot, int $count, int $itemStackId){
$this->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(NetworkBinaryStream $in) : self{
$slot = $in->getByte();
$hotbarSlot = $in->getByte();
$count = $in->getByte();
$itemStackId = $in->readGenericTypeNetworkId();
return new self($slot, $hotbarSlot, $count, $itemStackId);
}
public function write(NetworkBinaryStream $out) : void{
$out->putByte($this->slot);
$out->putByte($this->hotbarSlot);
$out->putByte($this->count);
$out->writeGenericTypeNetworkId($this->itemStackId);
}
}

@ -1 +1 @@
Subproject commit cc132c80dd9d76a44e4b0a360e85e8e28bba8956
Subproject commit 43edcfde6b9611b7c7d643be52332707cc10cd1b

View File

@ -385,6 +385,16 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php
-
message: "#^Cannot access offset string on mixed\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Offset mixed does not exist on array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\AddActorPacket\\:\\:\\$metadata \\(array\\<int, array\\(int, mixed\\)\\>\\) does not accept array\\<int, mixed\\>\\.$#"
count: 1
@ -455,11 +465,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/StartGamePacket.php
-
message: "#^Cannot access offset string on mixed\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$value of static method pocketmine\\\\permission\\\\Permission\\:\\:getByName\\(\\) expects bool\\|string, mixed given\\.$#"
count: 1

View File

@ -840,6 +840,21 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/VerifyLoginTask.php
-
message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\NBTStream\\:\\:read\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$buffer of class pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream constructor expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#"
count: 1
@ -870,6 +885,11 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/LevelEventGenericPacket.php
-
message: "#^Parameter \\#1 \\$str of method pocketmine\\\\utils\\\\BinaryStream\\:\\:put\\(\\) expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/PositionTrackingDBServerBroadcastPacket.php
-
message: "#^Static property pocketmine\\\\network\\\\mcpe\\\\protocol\\\\StartGamePacket\\:\\:\\$blockTableCache \\(string\\|null\\) does not accept string\\|false\\.$#"
count: 1
@ -895,16 +915,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/LegacySkinAdapter.php
-
message: "#^Parameter \\#1 \\$buffer of method pocketmine\\\\nbt\\\\NBTStream\\:\\:read\\(\\) expects string, string\\|false given\\.$#"
count: 2
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Call to an undefined method object\\:\\:Add\\(\\)\\.$#"
count: 1

View File

@ -1515,6 +1515,21 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/NetworkBinaryStream.php
-
message: "#^Argument of an invalid type array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null supplied for foreach, only iterables are supported\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$that of method pocketmine\\\\nbt\\\\tag\\\\NamedTag\\:\\:equals\\(\\) expects pocketmine\\\\nbt\\\\tag\\\\NamedTag, pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null given\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Method pocketmine\\\\network\\\\mcpe\\\\convert\\\\RuntimeBlockMapping\\:\\:getBedrockKnownStates\\(\\) should return array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\> but returns array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/convert/RuntimeBlockMapping.php
-
message: "#^Parameter \\#1 \\$eid of method pocketmine\\\\network\\\\mcpe\\\\NetworkBinaryStream\\:\\:putEntityUniqueId\\(\\) expects int, int\\|null given\\.$#"
count: 1
@ -1530,41 +1545,6 @@ parameters:
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php
-
message: "#^Argument of an invalid type array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null supplied for foreach, only iterables are supported\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Cannot call method getString\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#"
count: 2
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Cannot call method getShort\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Cannot call method setName\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Offset mixed does not exist on array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Cannot call method equals\\(\\) on pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Method pocketmine\\\\network\\\\mcpe\\\\protocol\\\\types\\\\RuntimeBlockMapping\\:\\:getBedrockKnownStates\\(\\) should return array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\> but returns array\\<pocketmine\\\\nbt\\\\tag\\\\CompoundTag\\>\\|null\\.$#"
count: 1
path: ../../../src/pocketmine/network/mcpe/protocol/types/RuntimeBlockMapping.php
-
message: "#^Cannot call method wakeupSleeper\\(\\) on pocketmine\\\\snooze\\\\SleeperNotifier\\|null\\.$#"
count: 1