diff --git a/src/network/mcpe/protocol/DataPacket.php b/src/network/mcpe/protocol/DataPacket.php index 390e141c9..051fa9af2 100644 --- a/src/network/mcpe/protocol/DataPacket.php +++ b/src/network/mcpe/protocol/DataPacket.php @@ -39,6 +39,12 @@ abstract class DataPacket implements Packet{ public const NETWORK_ID = 0; + public const PID_MASK = 0x3ff; //10 bits + + private const SUBCLIENT_ID_MASK = 0x03; //2 bits + private const SENDER_SUBCLIENT_ID_SHIFT = 10; + private const RECIPIENT_SUBCLIENT_ID_SHIFT = 12; + /** @var int */ public $senderSubId = 0; /** @var int */ @@ -85,11 +91,15 @@ abstract class DataPacket implements Packet{ * @throws \UnexpectedValueException */ protected function decodeHeader() : void{ - $pid = $this->buf->getUnsignedVarInt(); + $header = $this->buf->getUnsignedVarInt(); + $pid = $header & self::PID_MASK; if($pid !== static::NETWORK_ID){ //TODO: this means a logical error in the code, but how to prevent it from happening? throw new \UnexpectedValueException("Expected " . static::NETWORK_ID . " for packet ID, got $pid"); } + $this->senderSubId = ($header >> self::SENDER_SUBCLIENT_ID_SHIFT) & self::SUBCLIENT_ID_MASK; + $this->recipientSubId = ($header >> self::RECIPIENT_SUBCLIENT_ID_SHIFT) & self::SUBCLIENT_ID_MASK; + } /** @@ -107,7 +117,11 @@ abstract class DataPacket implements Packet{ } protected function encodeHeader() : void{ - $this->buf->putUnsignedVarInt(static::NETWORK_ID); + $this->buf->putUnsignedVarInt( + static::NETWORK_ID | + ($this->senderSubId << self::SENDER_SUBCLIENT_ID_SHIFT) | + ($this->recipientSubId << self::RECIPIENT_SUBCLIENT_ID_SHIFT) + ); } /** diff --git a/src/network/mcpe/protocol/PacketPool.php b/src/network/mcpe/protocol/PacketPool.php index f58f900ef..a619fe645 100644 --- a/src/network/mcpe/protocol/PacketPool.php +++ b/src/network/mcpe/protocol/PacketPool.php @@ -190,7 +190,7 @@ class PacketPool{ */ public static function getPacket(string $buffer) : Packet{ $offset = 0; - $pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset)); + $pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset) & DataPacket::PID_MASK); $pk->getBinaryStream()->setBuffer($buffer, $offset); return $pk; diff --git a/src/network/mcpe/protocol/types/SkinData.php b/src/network/mcpe/protocol/types/SkinData.php index 6ff6dfda8..e7ca29312 100644 --- a/src/network/mcpe/protocol/types/SkinData.php +++ b/src/network/mcpe/protocol/types/SkinData.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types; +use pocketmine\utils\UUID; + class SkinData{ /** @var string */ @@ -47,11 +49,13 @@ class SkinData{ private $personaCapeOnClassic; /** @var string */ private $capeId; + /** @var string */ + private $fullSkinId; /** * @param SkinAnimation[] $animations */ - public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = ""){ + public function __construct(string $skinId, string $resourcePatch, SkinImage $skinImage, array $animations = [], SkinImage $capeImage = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null){ $this->skinId = $skinId; $this->resourcePatch = $resourcePatch; $this->skinImage = $skinImage; @@ -63,6 +67,8 @@ class SkinData{ $this->persona = $persona; $this->personaCapeOnClassic = $personaCapeOnClassic; $this->capeId = $capeId; + //this has to be unique or the client will do stupid things + $this->fullSkinId = $fullSkinId ?? UUID::fromRandom()->toString(); } public function getSkinId() : string{ @@ -112,4 +118,7 @@ class SkinData{ return $this->capeId; } + public function getFullSkinId() : string{ + return $this->fullSkinId; + } } diff --git a/src/network/mcpe/serializer/NetworkBinaryStream.php b/src/network/mcpe/serializer/NetworkBinaryStream.php index 5248a8998..ebc0d9cab 100644 --- a/src/network/mcpe/serializer/NetworkBinaryStream.php +++ b/src/network/mcpe/serializer/NetworkBinaryStream.php @@ -117,7 +117,7 @@ class NetworkBinaryStream extends BinaryStream{ $capeId = $this->getString(); $fullSkinId = $this->getString(); - return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId); + return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId); } public function putSkin(SkinData $skin): void{ @@ -137,9 +137,7 @@ class NetworkBinaryStream extends BinaryStream{ $this->putBool($skin->isPersona()); $this->putBool($skin->isPersonaCapeOnClassic()); $this->putString($skin->getCapeId()); - - //this has to be unique or the client will do stupid things - $this->putString(UUID::fromRandom()->toString()); //full skin ID + $this->putString($skin->getFullSkinId()); } private function getSkinImage() : SkinImage{ diff --git a/tests/phpunit/network/mcpe/protocol/DataPacketTest.php b/tests/phpunit/network/mcpe/protocol/DataPacketTest.php new file mode 100644 index 000000000..5163d36aa --- /dev/null +++ b/tests/phpunit/network/mcpe/protocol/DataPacketTest.php @@ -0,0 +1,42 @@ +senderSubId = 3; + $pk->recipientSubId = 2; + $pk->encode(); + + $pk2 = new TestPacket(); + $pk2->getBinaryStream()->setBuffer($pk->getBinaryStream()->getBuffer()); + $pk2->decode(); + self::assertSame($pk2->senderSubId, 3); + self::assertSame($pk2->recipientSubId, 2); + } +} diff --git a/tests/phpunit/network/mcpe/protocol/TestPacket.php b/tests/phpunit/network/mcpe/protocol/TestPacket.php new file mode 100644 index 000000000..86e82f2d0 --- /dev/null +++ b/tests/phpunit/network/mcpe/protocol/TestPacket.php @@ -0,0 +1,42 @@ +