From 986077e03cc2d0caf43fee3e2566009d2089e0c2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 15 Jun 2018 19:24:23 +0100 Subject: [PATCH] Protocol changes for 1.6.0.1 --- src/pocketmine/Player.php | 6 -- src/pocketmine/block/BlockFactory.php | 4 +- .../network/mcpe/NetworkSession.php | 15 ++++ .../network/mcpe/RakLibInterface.php | 2 +- .../network/mcpe/protocol/DataPacket.php | 7 -- .../network/mcpe/protocol/LoginPacket.php | 7 -- .../protocol/NetworkStackLatencyPacket.php | 47 +++++++++++++ .../network/mcpe/protocol/PacketPool.php | 3 + .../mcpe/protocol/PlayStatusPacket.php | 14 ---- .../network/mcpe/protocol/ProtocolInfo.php | 11 +-- .../protocol/SetScoreboardIdentityPacket.php | 69 +++++++++++++++++++ .../network/mcpe/protocol/StartGamePacket.php | 23 +++++++ .../mcpe/protocol/UpdateSoftEnumPacket.php | 64 +++++++++++++++++ .../types/ScoreboardIdentityPacketEntry.php | 34 +++++++++ src/pocketmine/resources/runtimeid_table.json | 2 +- 15 files changed, 266 insertions(+), 42 deletions(-) create mode 100644 src/pocketmine/network/mcpe/protocol/NetworkStackLatencyPacket.php create mode 100644 src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php create mode 100644 src/pocketmine/network/mcpe/protocol/UpdateSoftEnumPacket.php create mode 100644 src/pocketmine/network/mcpe/protocol/types/ScoreboardIdentityPacketEntry.php diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index b6ba9dd98..695ddf907 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -193,9 +193,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ */ protected $sessionAdapter; - /** @var int */ - protected $protocol = -1; - /** @var string */ protected $ip; /** @var int */ @@ -1839,8 +1836,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ return false; } - $this->protocol = $packet->protocol; - if($packet->protocol !== ProtocolInfo::CURRENT_PROTOCOL){ if($packet->protocol < ProtocolInfo::CURRENT_PROTOCOL){ $this->sendPlayStatus(PlayStatusPacket::LOGIN_FAILED_CLIENT, true); @@ -1923,7 +1918,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ public function sendPlayStatus(int $status, bool $immediate = false){ $pk = new PlayStatusPacket(); $pk->status = $status; - $pk->protocol = $this->protocol; $this->sendDataPacket($pk, false, $immediate); } diff --git a/src/pocketmine/block/BlockFactory.php b/src/pocketmine/block/BlockFactory.php index 4774b4c58..b5dee4f42 100644 --- a/src/pocketmine/block/BlockFactory.php +++ b/src/pocketmine/block/BlockFactory.php @@ -421,8 +421,8 @@ class BlockFactory{ public static function registerStaticRuntimeIdMappings() : void{ /** @var mixed[] $runtimeIdMap */ $runtimeIdMap = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true); - foreach($runtimeIdMap as $obj){ - self::registerMapping($obj["runtimeID"], $obj["id"], $obj["data"]); + foreach($runtimeIdMap as $k => $obj){ + self::registerMapping($k, $obj["id"], $obj["data"]); } } diff --git a/src/pocketmine/network/mcpe/NetworkSession.php b/src/pocketmine/network/mcpe/NetworkSession.php index 67265e947..33fa61d90 100644 --- a/src/pocketmine/network/mcpe/NetworkSession.php +++ b/src/pocketmine/network/mcpe/NetworkSession.php @@ -79,6 +79,7 @@ use pocketmine\network\mcpe\protocol\ModalFormResponsePacket; use pocketmine\network\mcpe\protocol\MoveEntityAbsolutePacket; use pocketmine\network\mcpe\protocol\MoveEntityDeltaPacket; use pocketmine\network\mcpe\protocol\MovePlayerPacket; +use pocketmine\network\mcpe\protocol\NetworkStackLatencyPacket; use pocketmine\network\mcpe\protocol\NpcRequestPacket; use pocketmine\network\mcpe\protocol\PhotoTransferPacket; use pocketmine\network\mcpe\protocol\PlaySoundPacket; @@ -115,6 +116,7 @@ use pocketmine\network\mcpe\protocol\SetLastHurtByPacket; use pocketmine\network\mcpe\protocol\SetLocalPlayerAsInitializedPacket; use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket; use pocketmine\network\mcpe\protocol\SetScorePacket; +use pocketmine\network\mcpe\protocol\SetScoreboardIdentityPacket; use pocketmine\network\mcpe\protocol\SetSpawnPositionPacket; use pocketmine\network\mcpe\protocol\SetTimePacket; use pocketmine\network\mcpe\protocol\SetTitlePacket; @@ -134,6 +136,7 @@ use pocketmine\network\mcpe\protocol\UpdateAttributesPacket; use pocketmine\network\mcpe\protocol\UpdateBlockPacket; use pocketmine\network\mcpe\protocol\UpdateBlockSyncedPacket; use pocketmine\network\mcpe\protocol\UpdateEquipPacket; +use pocketmine\network\mcpe\protocol\UpdateSoftEnumPacket; use pocketmine\network\mcpe\protocol\UpdateTradePacket; use pocketmine\network\mcpe\protocol\WSConnectPacket; @@ -585,7 +588,19 @@ abstract class NetworkSession{ return false; } + public function handleSetScoreboardIdentity(SetScoreboardIdentityPacket $packet) : bool{ + return false; + } + public function handleSetLocalPlayerAsInitialized(SetLocalPlayerAsInitializedPacket $packet) : bool{ return false; } + + public function handleUpdateSoftEnum(UpdateSoftEnumPacket $packet) : bool{ + return false; + } + + public function handleNetworkStackLatency(NetworkStackLatencyPacket $packet) : bool{ + return false; + } } diff --git a/src/pocketmine/network/mcpe/RakLibInterface.php b/src/pocketmine/network/mcpe/RakLibInterface.php index 797d015c8..db7537726 100644 --- a/src/pocketmine/network/mcpe/RakLibInterface.php +++ b/src/pocketmine/network/mcpe/RakLibInterface.php @@ -46,7 +46,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 = 8; + private const MCPE_RAKNET_PROTOCOL_VERSION = 9; /** @var Server */ private $server; diff --git a/src/pocketmine/network/mcpe/protocol/DataPacket.php b/src/pocketmine/network/mcpe/protocol/DataPacket.php index c1b983177..87c715296 100644 --- a/src/pocketmine/network/mcpe/protocol/DataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/DataPacket.php @@ -74,10 +74,6 @@ abstract class DataPacket extends NetworkBinaryStream{ protected function decodeHeader(){ $pid = $this->getUnsignedVarInt(); assert($pid === static::NETWORK_ID); - - $this->senderSubId = $this->getByte(); - $this->recipientSubId = $this->getByte(); - assert($this->senderSubId === 0 and $this->recipientSubId === 0, "Got unexpected non-zero split-screen bytes (byte1: $this->senderSubId, byte2: $this->recipientSubId"); } /** @@ -96,9 +92,6 @@ abstract class DataPacket extends NetworkBinaryStream{ protected function encodeHeader(){ $this->putUnsignedVarInt(static::NETWORK_ID); - - $this->putByte($this->senderSubId); - $this->putByte($this->recipientSubId); } /** diff --git a/src/pocketmine/network/mcpe/protocol/LoginPacket.php b/src/pocketmine/network/mcpe/protocol/LoginPacket.php index 67c70fc12..04746709f 100644 --- a/src/pocketmine/network/mcpe/protocol/LoginPacket.php +++ b/src/pocketmine/network/mcpe/protocol/LoginPacket.php @@ -79,13 +79,6 @@ class LoginPacket extends DataPacket{ protected function decodePayload(){ $this->protocol = $this->getInt(); - if($this->protocol !== ProtocolInfo::CURRENT_PROTOCOL){ - if($this->protocol > 0xffff){ //guess MCPE <= 1.1 - $this->offset -= 6; - $this->protocol = $this->getInt(); - } - } - try{ $this->decodeConnectionRequest(); }catch(\Throwable $e){ diff --git a/src/pocketmine/network/mcpe/protocol/NetworkStackLatencyPacket.php b/src/pocketmine/network/mcpe/protocol/NetworkStackLatencyPacket.php new file mode 100644 index 000000000..ace6a90d7 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/NetworkStackLatencyPacket.php @@ -0,0 +1,47 @@ + + +use pocketmine\network\mcpe\NetworkSession; + +class NetworkStackLatencyPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::NETWORK_STACK_LATENCY_PACKET; + + /** @var int */ + public $timestamp; + + protected function decodePayload(){ + $this->timestamp = $this->getLLong(); + } + + protected function encodePayload(){ + $this->putLLong($this->timestamp); + } + + public function handle(NetworkSession $session) : bool{ + return $session->handleNetworkStackLatency($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/PacketPool.php b/src/pocketmine/network/mcpe/protocol/PacketPool.php index ac550f720..814d082a6 100644 --- a/src/pocketmine/network/mcpe/protocol/PacketPool.php +++ b/src/pocketmine/network/mcpe/protocol/PacketPool.php @@ -142,7 +142,10 @@ class PacketPool{ static::registerPacket(new LabTablePacket()); static::registerPacket(new UpdateBlockSyncedPacket()); static::registerPacket(new MoveEntityDeltaPacket()); + static::registerPacket(new SetScoreboardIdentityPacket()); static::registerPacket(new SetLocalPlayerAsInitializedPacket()); + static::registerPacket(new UpdateSoftEnumPacket()); + static::registerPacket(new NetworkStackLatencyPacket()); static::registerPacket(new BatchPacket()); } diff --git a/src/pocketmine/network/mcpe/protocol/PlayStatusPacket.php b/src/pocketmine/network/mcpe/protocol/PlayStatusPacket.php index 0dd128cbf..97e65ffb3 100644 --- a/src/pocketmine/network/mcpe/protocol/PlayStatusPacket.php +++ b/src/pocketmine/network/mcpe/protocol/PlayStatusPacket.php @@ -43,12 +43,6 @@ class PlayStatusPacket extends DataPacket{ /** @var int */ public $status; - /** - * @var int - * Used to determine how to write the packet when we disconnect incompatible clients. - */ - public $protocol = ProtocolInfo::CURRENT_PROTOCOL; - protected function decodePayload(){ $this->status = $this->getInt(); } @@ -57,14 +51,6 @@ class PlayStatusPacket extends DataPacket{ return true; } - protected function encodeHeader(){ - if($this->protocol < 130){ //MCPE <= 1.1 - $this->putByte(static::NETWORK_ID); - }else{ - parent::encodeHeader(); - } - } - protected function encodePayload(){ $this->putInt($this->status); } diff --git a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php index 6aa8957b2..8b3f3fa89 100644 --- a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php +++ b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php @@ -39,15 +39,15 @@ interface ProtocolInfo{ /** * Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 274; + public const CURRENT_PROTOCOL = 280; /** * Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.5.0'; + public const MINECRAFT_VERSION = 'v1.6.0.1 beta'; /** * Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.5.0'; + public const MINECRAFT_VERSION_NETWORK = '1.6.0.1'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; @@ -160,6 +160,9 @@ interface ProtocolInfo{ public const LAB_TABLE_PACKET = 0x6d; public const UPDATE_BLOCK_SYNCED_PACKET = 0x6e; public const MOVE_ENTITY_DELTA_PACKET = 0x6f; - public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x70; + public const SET_SCOREBOARD_IDENTITY_PACKET = 0x70; + public const SET_LOCAL_PLAYER_AS_INITIALIZED_PACKET = 0x71; + public const UPDATE_SOFT_ENUM_PACKET = 0x72; + public const NETWORK_STACK_LATENCY_PACKET = 0x73; } diff --git a/src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php b/src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php new file mode 100644 index 000000000..91cd54612 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/SetScoreboardIdentityPacket.php @@ -0,0 +1,69 @@ + + +use pocketmine\network\mcpe\NetworkSession; +use pocketmine\network\mcpe\protocol\types\ScoreboardIdentityPacketEntry; + +class SetScoreboardIdentityPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::SET_SCOREBOARD_IDENTITY_PACKET; + + public const TYPE_REGISTER_IDENTITY = 0; + public const TYPE_CLEAR_IDENTITY = 1; + + /** @var int */ + public $type; + /** @var ScoreboardIdentityPacketEntry[] */ + public $entries = []; + + protected function decodePayload(){ + $this->type = $this->getByte(); + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $entry = new ScoreboardIdentityPacketEntry(); + $entry->scoreboardId = $this->getVarLong(); + if($this->type === self::TYPE_REGISTER_IDENTITY){ + $entry->uuid = $this->getUUID(); + } + + $this->entries[] = $entry; + } + } + + protected function encodePayload(){ + $this->putByte($this->type); + $this->putUnsignedVarInt(count($this->entries)); + foreach($this->entries as $entry){ + $this->putVarLong($entry->scoreboardId); + if($this->type === self::TYPE_REGISTER_IDENTITY){ + $this->putUUID($entry->uuid); + } + } + } + + public function handle(NetworkSession $session) : bool{ + return $session->handleSetScoreboardIdentity($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php index 0cea9e24e..43a7614c7 100644 --- a/src/pocketmine/network/mcpe/protocol/StartGamePacket.php +++ b/src/pocketmine/network/mcpe/protocol/StartGamePacket.php @@ -27,12 +27,16 @@ namespace pocketmine\network\mcpe\protocol; use pocketmine\math\Vector3; +use pocketmine\network\mcpe\NetworkBinaryStream; use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; class StartGamePacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::START_GAME_PACKET; + /** @var string|null */ + private static $runtimeIdTable; + /** @var int */ public $entityUniqueId; /** @var int */ @@ -175,6 +179,12 @@ class StartGamePacket extends DataPacket{ $this->currentTick = $this->getLLong(); $this->enchantmentSeed = $this->getVarInt(); + + $count = $this->getUnsignedVarInt(); + for($i = 0; $i < $count; ++$i){ + $this->getString(); + $this->getLShort(); + } } protected function encodePayload(){ @@ -226,6 +236,19 @@ class StartGamePacket extends DataPacket{ $this->putLLong($this->currentTick); $this->putVarInt($this->enchantmentSeed); + + if(self::$runtimeIdTable === null){ + //this is a really nasty hack, but it'll do for now + $stream = new NetworkBinaryStream(); + $data = json_decode(file_get_contents(\pocketmine\RESOURCE_PATH . "runtimeid_table.json"), true); + $stream->putUnsignedVarInt(count($data)); + foreach($data as $v){ + $stream->putString($v["name"]); + $stream->putLShort($v["data"]); + } + self::$runtimeIdTable = $stream->buffer; + } + $this->put(self::$runtimeIdTable); } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/UpdateSoftEnumPacket.php b/src/pocketmine/network/mcpe/protocol/UpdateSoftEnumPacket.php new file mode 100644 index 000000000..8fffe55d6 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/UpdateSoftEnumPacket.php @@ -0,0 +1,64 @@ + + +use pocketmine\network\mcpe\NetworkSession; + +class UpdateSoftEnumPacket extends DataPacket{ + public const NETWORK_ID = ProtocolInfo::UPDATE_SOFT_ENUM_PACKET; + + public const TYPE_ADD = 0; + public const TYPE_REMOVE = 1; + public const TYPE_SET = 2; + + /** @var string */ + public $enumName; + /** @var string[] */ + public $values = []; + /** @var int */ + public $type; + + protected function decodePayload(){ + $this->enumName = $this->getString(); + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $this->values[] = $this->getString(); + } + $this->type = $this->getByte(); + } + + protected function encodePayload(){ + $this->putString($this->enumName); + $this->putUnsignedVarInt(count($this->values)); + foreach($this->values as $v){ + $this->putString($v); + } + $this->putByte($this->type); + } + + public function handle(NetworkSession $session) : bool{ + return $session->handleUpdateSoftEnum($this); + } +} diff --git a/src/pocketmine/network/mcpe/protocol/types/ScoreboardIdentityPacketEntry.php b/src/pocketmine/network/mcpe/protocol/types/ScoreboardIdentityPacketEntry.php new file mode 100644 index 000000000..416e2434d --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/ScoreboardIdentityPacketEntry.php @@ -0,0 +1,34 @@ +