diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 2b5043100..ed6c7a679 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -146,6 +146,8 @@ use pocketmine\network\mcpe\protocol\types\CommandEnum; use pocketmine\network\mcpe\protocol\types\CommandParameter; use pocketmine\network\mcpe\protocol\types\ContainerIds; use pocketmine\network\mcpe\protocol\types\DimensionIds; +use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor; +use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece; use pocketmine\network\mcpe\protocol\types\PlayerPermissions; use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton; use pocketmine\network\mcpe\protocol\types\SkinAnimation; @@ -1859,6 +1861,16 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]); } + $personaPieces = []; + foreach($packet->clientData["PersonaPieces"] as $piece){ + $personaPiece[] = new PersonaSkinPiece($piece["PieceId"], $piece["PieceType"], $piece["PackId"], $piece["IsDefault"], $piece["ProductId"]); + } + + $pieceTintColors = []; + foreach($packet->clientData["PieceTintColors"] as $tintColor){ + $pieceTintColors[] = new PersonaPieceTintColor($tintColor["PieceType"], $tintColor["Colors"]); + } + $skinData = new SkinData( $packet->clientData["SkinId"], base64_decode($packet->clientData["SkinResourcePatch"] ?? "", true), @@ -1870,7 +1882,13 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $packet->clientData["PremiumSkin"] ?? false, $packet->clientData["PersonaSkin"] ?? false, $packet->clientData["CapeOnClassicSkin"] ?? false, - $packet->clientData["CapeId"] ?? "" + $packet->clientData["CapeId"] ?? "", + null, + $packet->clientData["ArmSize"] ?? SkinData::ARM_SIZE_WIDE, + $packet->clientData["SkinColor"] ?? "", + $personaPieces, + $pieceTintColors, + true ); $skin = SkinAdapterSingleton::get()->fromSkinData($skinData); diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index 8ca86b0c4..9d9b121ef 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -37,6 +37,8 @@ use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\network\mcpe\protocol\types\CommandOriginData; use pocketmine\network\mcpe\protocol\types\EntityLink; +use pocketmine\network\mcpe\protocol\types\PersonaPieceTintColor; +use pocketmine\network\mcpe\protocol\types\PersonaSkinPiece; use pocketmine\network\mcpe\protocol\types\SkinAnimation; use pocketmine\network\mcpe\protocol\types\SkinData; use pocketmine\network\mcpe\protocol\types\SkinImage; @@ -99,8 +101,35 @@ class NetworkBinaryStream extends BinaryStream{ $capeOnClassic = $this->getBool(); $capeId = $this->getString(); $fullSkinId = $this->getString(); + $armSize = $this->getString(); + $skinColor = $this->getString(); + $personaPieceCount = $this->getLInt(); + $personaPieces = []; + for($i = 0; $i < $personaPieceCount; ++$i){ + $personaPieces[] = new PersonaSkinPiece( + $pieceId = $this->getString(), + $pieceType = $this->getString(), + $packId = $this->getString(), + $isDefaultPiece = $this->getBool(), + $productId = $this->getString() + ); + } + $pieceTintColorCount = $this->getLInt(); + $pieceTintColors = []; + for($i = 0; $i < $pieceTintColorCount; ++$i){ + $pieceType = $this->getString(); + $colorCount = $this->getLInt(); + $colors = []; + for($j = 0; $j < $colorCount; ++$j){ + $colors[] = $this->getString(); + } + $pieceTintColors[] = new PersonaPieceTintColor( + $pieceType, + $colors + ); + } - return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId); + return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId, $armSize, $skinColor, $personaPieces, $pieceTintColors); } /** @@ -124,6 +153,24 @@ class NetworkBinaryStream extends BinaryStream{ $this->putBool($skin->isPersonaCapeOnClassic()); $this->putString($skin->getCapeId()); $this->putString($skin->getFullSkinId()); + $this->putString($skin->getArmSize()); + $this->putString($skin->getSkinColor()); + $this->putLInt(count($skin->getPersonaPieces())); + foreach($skin->getPersonaPieces() as $piece){ + $this->putString($piece->getPieceId()); + $this->putString($piece->getPieceType()); + $this->putString($piece->getPackId()); + $this->putBool($piece->isDefaultPiece()); + $this->putString($piece->getProductId()); + } + $this->putLInt(count($skin->getPieceTintColors())); + foreach($skin->getPieceTintColors() as $tint){ + $this->putString($tint->getPieceType()); + $this->putLInt(count($tint->getColors())); + foreach($tint->getColors() as $color){ + $this->putString($color); + } + } } private function getSkinImage() : SkinImage{ diff --git a/src/pocketmine/network/mcpe/protocol/PlayerListPacket.php b/src/pocketmine/network/mcpe/protocol/PlayerListPacket.php index de15f2825..44646bf52 100644 --- a/src/pocketmine/network/mcpe/protocol/PlayerListPacket.php +++ b/src/pocketmine/network/mcpe/protocol/PlayerListPacket.php @@ -67,6 +67,11 @@ class PlayerListPacket extends DataPacket{ $this->entries[$i] = $entry; } + if($this->type === self::TYPE_ADD){ + for($i = 0; $i < $count; ++$i){ + $this->entries[$i]->skinData->setVerified($this->getBool()); + } + } } protected function encodePayload(){ @@ -87,6 +92,11 @@ class PlayerListPacket extends DataPacket{ $this->putUUID($entry->uuid); } } + if($this->type === self::TYPE_ADD){ + foreach($this->entries as $entry){ + $this->putBool($entry->skinData->isVerified()); + } + } } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php b/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php index f197386b4..661f73e03 100644 --- a/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php +++ b/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php @@ -46,6 +46,7 @@ class PlayerSkinPacket extends DataPacket{ $this->skin = $this->getSkin(); $this->newSkinName = $this->getString(); $this->oldSkinName = $this->getString(); + $this->skin->setVerified($this->getBool()); } protected function encodePayload(){ @@ -53,6 +54,7 @@ class PlayerSkinPacket extends DataPacket{ $this->putSkin($this->skin); $this->putString($this->newSkinName); $this->putString($this->oldSkinName); + $this->putBool($this->skin->isVerified()); } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php index 8d08df6c3..a020149b8 100644 --- a/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php +++ b/src/pocketmine/network/mcpe/protocol/ProtocolInfo.php @@ -37,11 +37,11 @@ interface ProtocolInfo{ */ /** Actual Minecraft: PE protocol version */ - public const CURRENT_PROTOCOL = 389; + public const CURRENT_PROTOCOL = 390; /** Current Minecraft PE version reported by the server. This is usually the earliest currently supported version. */ - public const MINECRAFT_VERSION = 'v1.14.0'; + public const MINECRAFT_VERSION = 'v1.14.60'; /** Version number sent to clients in ping responses. */ - public const MINECRAFT_VERSION_NETWORK = '1.14.0'; + public const MINECRAFT_VERSION_NETWORK = '1.14.60'; public const LOGIN_PACKET = 0x01; public const PLAY_STATUS_PACKET = 0x02; diff --git a/src/pocketmine/network/mcpe/protocol/types/PersonaPieceTintColor.php b/src/pocketmine/network/mcpe/protocol/types/PersonaPieceTintColor.php new file mode 100644 index 000000000..05231d3f1 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/PersonaPieceTintColor.php @@ -0,0 +1,55 @@ +pieceType = $pieceType; + $this->colors = $colors; + } + + public function getPieceType() : string{ + return $this->pieceType; + } + + /** + * @return string[] + */ + public function getColors() : array{ + return $this->colors; + } +} diff --git a/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php b/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php new file mode 100644 index 000000000..bb22a1350 --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/PersonaSkinPiece.php @@ -0,0 +1,77 @@ +pieceId = $pieceId; + $this->pieceType = $pieceType; + $this->packId = $packId; + $this->isDefaultPiece = $isDefaultPiece; + $this->productId = $productId; + } + + public function getPieceId() : string{ + return $this->pieceId; + } + + public function getPieceType() : string{ + return $this->pieceType; + } + + public function getPackId() : string{ + return $this->packId; + } + + public function isDefaultPiece() : bool{ + return $this->isDefaultPiece; + } + + public function getProductId() : string{ + return $this->productId; + } +} \ No newline at end of file diff --git a/src/pocketmine/network/mcpe/protocol/types/SkinData.php b/src/pocketmine/network/mcpe/protocol/types/SkinData.php index e7ca29312..1393748b4 100644 --- a/src/pocketmine/network/mcpe/protocol/types/SkinData.php +++ b/src/pocketmine/network/mcpe/protocol/types/SkinData.php @@ -27,6 +27,9 @@ use pocketmine\utils\UUID; class SkinData{ + public const ARM_SIZE_SLIM = "slim"; + public const ARM_SIZE_WIDE = "wide"; + /** @var string */ private $skinId; /** @var string */ @@ -51,11 +54,23 @@ class SkinData{ private $capeId; /** @var string */ private $fullSkinId; + /** @var string */ + private $armSize; + /** @var string */ + private $skinColor; + /** @var PersonaSkinPiece[] */ + private $personaPieces; + /** @var PersonaPieceTintColor[] */ + private $pieceTintColors; + /** @var bool */ + private $isVerified; /** - * @param SkinAnimation[] $animations + * @param SkinAnimation[] $animations + * @param PersonaSkinPiece[] $personaPieces + * @param PersonaPieceTintColor[] $pieceTintColors */ - 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){ + 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, string $armSize = self::ARM_SIZE_WIDE, string $skinColor = "", array $personaPieces = [], array $pieceTintColors = [], bool $isVerified = false){ $this->skinId = $skinId; $this->resourcePatch = $resourcePatch; $this->skinImage = $skinImage; @@ -69,6 +84,11 @@ class SkinData{ $this->capeId = $capeId; //this has to be unique or the client will do stupid things $this->fullSkinId = $fullSkinId ?? UUID::fromRandom()->toString(); + $this->armSize = $armSize; + $this->skinColor = $skinColor; + $this->personaPieces = $personaPieces; + $this->pieceTintColors = $pieceTintColors; + $this->isVerified = $isVerified; } public function getSkinId() : string{ @@ -121,4 +141,37 @@ class SkinData{ public function getFullSkinId() : string{ return $this->fullSkinId; } + + public function getArmSize() : string{ + return $this->armSize; + } + + public function getSkinColor() : string{ + return $this->skinColor; + } + + /** + * @return PersonaSkinPiece[] + */ + public function getPersonaPieces() : array{ + return $this->personaPieces; + } + + /** + * @return PersonaPieceTintColor[] + */ + public function getPieceTintColors() : array{ + return $this->pieceTintColors; + } + + public function isVerified() : bool{ + return $this->isVerified; + } + + /** + * @internal + */ + public function setVerified(bool $verified) : void{ + $this->isVerified = $verified; + } }