diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 9ee384ba6..f3930e136 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -1917,22 +1917,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->uuid = UUID::fromString($packet->clientUUID); $this->rawUUID = $this->uuid->toBinary(); - $animations = []; - foreach($packet->clientData["AnimatedImageData"] as $animatedData){ - $animations[] = new SkinAnimation(new SerializedImage($animatedData["ImageHeight"], $animatedData["ImageWidth"], base64_decode($animatedData["Image"])), $animatedData["Type"], $animatedData["Frames"]); - } $skin = new Skin( $packet->clientData["SkinId"], + base64_decode($packet->clientData["SkinData"] ?? ""), + base64_decode($packet->clientData["CapeData"] ?? ""), base64_decode($packet->clientData["SkinResourcePatch"] ?? ""), - new SerializedImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"] ?? "")), - $animations, - new SerializedImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "")), - base64_decode($packet->clientData["SkinGeometryData"] ?? ""), - base64_decode($packet->clientData["AnimationData"] ?? ""), - $packet->clientData["PremiumSkin"] ?? false, - $packet->clientData["PersonaSkin"] ?? false, - $packet->clientData["CapeOnClassicSkin"] ?? false, - $packet->clientData["CapeId"] ?? "" + base64_decode($packet->clientData["SkinGeometryData"] ?? "") ); if(!$skin->isValid()){ diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 2955d1f88..0a9def938 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -42,7 +42,6 @@ use pocketmine\item\Totem; use pocketmine\level\Level; use pocketmine\nbt\NBT; use pocketmine\nbt\tag\ByteArrayTag; -use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\IntTag; use pocketmine\nbt\tag\ListTag; @@ -55,8 +54,6 @@ use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\Player; -use pocketmine\utils\SerializedImage; -use pocketmine\utils\SkinAnimation; use pocketmine\utils\UUID; use function array_filter; use function array_merge; @@ -120,16 +117,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ protected static function deserializeSkinNBT(CompoundTag $skinTag) : Skin{ $skin = new Skin( $skinTag->getString("Name"), - $skinTag->getString("SkinResourcePatch", ""), - new SerializedImage($skinTag->getInt("SkinImageHeight"), $skinTag->getInt("SkinImageWidth"), $skinTag->getByteArray("Data")), - "", //TODO: animations - new SerializedImage($skinTag->getInt("CapeImageHeight"), $skinTag->getInt("CapeImageWidth"), $skinTag->getByteArray("CapeData")), - $skinTag->getByteArray("GeometryData", ""), - $skinTag->getByteArray("AnimationData", ""), - $skinTag->getByte("PremiumSkin") === 1, - $skinTag->getByte("PersonaSkin") === 1, - $skinTag->getByte("CapeOnClassic") === 1, - $skinTag->getString("CapeId", "") + $skinTag->hasTag("Data", StringTag::class) ? $skinTag->getString("Data") : $skinTag->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM) + $skinTag->getByteArray("CapeData", ""), + $skinTag->getString("GeometryName", ""), + $skinTag->getByteArray("GeometryData", "") ); $skin->validate(); return $skin; @@ -835,23 +826,13 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $this->namedtag->setTag(new ListTag("EnderChestInventory", $items, NBT::TAG_Compound)); } - //TODO: Save animations if($this->skin !== null){ $this->namedtag->setTag(new CompoundTag("Skin", [ new StringTag("Name", $this->skin->getSkinId()), - new StringTag("SkinResourcePatch", $this->skin->getSkinResourcePatch()), - new ByteArrayTag("Data", $this->skin->getSkinData()->getData()), - new IntTag("SkinImageHeight", $this->skin->getSkinData()->getHeight()), - new IntTag("SkinImageWidth", $this->skin->getSkinData()->getWidth()), - new ByteArrayTag("CapeData", $this->skin->getCapeData()->getData()), - new IntTag("CapeImageHeight", $this->skin->getCapeData()->getHeight()), - new IntTag("CapeImageWidth", $this->skin->getCapeData()->getWidth()), - new ByteArrayTag("GeometryData", $this->skin->getGeometryData()), - new ByteArrayTag("AnimationData", $this->skin->getAnimationData()), - new ByteTag("PremiumSkin", $this->skin->getPremium() ? 1 : 0), - new ByteTag("PersonaSkin", $this->skin->getPersona() ? 1 : 0), - new ByteTag("CapeOnClassic", $this->skin->getCapeOnClassic() ? 1 : 0), - new StringTag("CapeId", $this->skin->getCapeId()) + new ByteArrayTag("Data", $this->skin->getSkinData()), + new ByteArrayTag("CapeData", $this->skin->getCapeData()), + new StringTag("GeometryName", $this->skin->getGeometryName()), + new ByteArrayTag("GeometryData", $this->skin->getGeometryData()) ])); } } diff --git a/src/pocketmine/entity/Skin.php b/src/pocketmine/entity/Skin.php index 0be896b62..5164e4e51 100644 --- a/src/pocketmine/entity/Skin.php +++ b/src/pocketmine/entity/Skin.php @@ -24,8 +24,6 @@ declare(strict_types=1); namespace pocketmine\entity; use Ahc\Json\Comment as CommentedJsonDecoder; -use pocketmine\utils\SerializedImage; -use pocketmine\utils\SkinAnimation; use function implode; use function in_array; use function json_encode; @@ -41,38 +39,20 @@ class Skin{ /** @var string */ private $skinId; /** @var string */ - private $skinResourcePatch; - /** @var SerializedImage */ private $skinData; - /** @var SkinAnimation[] */ - private $animations = []; - /** @var SerializedImage */ + /** @var string */ private $capeData; /** @var string */ + private $geometryName; + /** @var string */ private $geometryData; - /** @var string */ - private $animationData; - /** @var bool */ - private $premium; - /** @var bool */ - private $persona; - /** @var bool */ - private $capeOnClassic; - /** @var string */ - private $capeId; - public function __construct(string $skinId, string $skinResourcePatch, SerializedImage $skinData, array $animations = [], SerializedImage $capeData = null, string $geometryData = "", string $animationData = "", bool $premium = false, bool $persona = false, bool $capeOnClassic = false, string $capeId = ""){ + public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){ $this->skinId = $skinId; - $this->skinResourcePatch = $skinResourcePatch; $this->skinData = $skinData; - $this->animations = $animations; $this->capeData = $capeData; + $this->geometryName = $geometryName; $this->geometryData = $geometryData; - $this->animationData = $animationData; - $this->premium = $premium; - $this->persona = $persona; - $this->capeOnClassic = $capeOnClassic; - $this->capeId = $capeId; } public static function convertToLegacyName(string $name) : string{ @@ -99,14 +79,13 @@ class Skin{ if($this->skinId === ""){ throw new \InvalidArgumentException("Skin ID must not be empty"); } - //Broken with Persona skins - /*$len = strlen($this->skinData->getData()); + $len = strlen($this->skinData); if(!in_array($len, self::ACCEPTED_SKIN_SIZES, true)){ throw new \InvalidArgumentException("Invalid skin data size $len bytes (allowed sizes: " . implode(", ", self::ACCEPTED_SKIN_SIZES) . ")"); } - if($this->capeData->getData() !== "" and strlen($this->capeData->getData()) !== 8192){ - throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData->getData()) . " bytes (must be exactly 8192 bytes)"); - }*/ + if($this->capeData !== "" and strlen($this->capeData) !== 8192){ + throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData) . " bytes (must be exactly 8192 bytes)"); + } //TODO: validate geometry } @@ -120,29 +99,22 @@ class Skin{ /** * @return string */ - public function getSkinResourcePatch() : string{ - return $this->skinResourcePatch; - } - - /** - * @return SerializedImage - */ - public function getSkinData() : SerializedImage{ + public function getSkinData() : string{ return $this->skinData; } /** - * @return SkinAnimation[] + * @return string */ - public function getAnimations() : array{ - return $this->animations; + public function getCapeData() : string{ + return $this->capeData; } /** - * @return SerializedImage + * @return string */ - public function getCapeData() : SerializedImage{ - return $this->capeData ?? new SerializedImage(0, 0, ""); + public function getGeometryName() : string{ + return $this->geometryName; } /** @@ -152,48 +124,6 @@ class Skin{ return $this->geometryData; } - /** - * @return string - */ - public function getAnimationData() : string{ - return $this->animationData; - } - - /** - * @return bool - */ - public function getPremium() : bool{ - return $this->premium; - } - - /** - * @return bool - */ - public function getPersona() : bool{ - return $this->persona; - } - - /** - * @return bool - */ - public function getCapeOnClassic() : bool{ - return $this->capeOnClassic; - } - - /** - * @return string - */ - public function getCapeId() : string{ - return $this->capeId; - } - - /** - * @return string - */ - public function getFullSkinId() : string{ - return $this->skinId . "_" . $this->capeId; - } - /** * Hack to cut down on network overhead due to skins, by un-pretty-printing geometry JSON. * diff --git a/src/pocketmine/level/particle/FloatingTextParticle.php b/src/pocketmine/level/particle/FloatingTextParticle.php index a8b859e20..8c6f6df83 100644 --- a/src/pocketmine/level/particle/FloatingTextParticle.php +++ b/src/pocketmine/level/particle/FloatingTextParticle.php @@ -32,7 +32,6 @@ use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\RemoveActorPacket; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; -use pocketmine\utils\SerializedImage; use pocketmine\utils\UUID; use function str_repeat; @@ -97,7 +96,7 @@ class FloatingTextParticle extends Particle{ $add = new PlayerListPacket(); $add->type = PlayerListPacket::TYPE_ADD; - $add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", Skin::convertToLegacyName("geometry.humanoid.custom"), SerializedImage::fromLegacy(str_repeat("\x00", 8192))))]; + $add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", str_repeat("\x00", 8192), "", Skin::convertToLegacyName("geometry.humanoid.custom"), ""))]; $p[] = $add; $pk = new AddPlayerPacket(); diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index 0c4cdd563..890a57a19 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -95,29 +95,29 @@ class NetworkBinaryStream extends BinaryStream{ $capeId = $this->getString(); $fullSkinId = $this->getString(); - return new Skin( - $skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId - ); + return new Skin($skinId, $skinData->getData(), $capeData->getData(), $skinResourcePatch, $geometryData); } public function putSkin(Skin $skin){ $this->putString($skin->getSkinId()); - $this->putString($skin->getSkinResourcePatch()); - $this->putImage($skin->getSkinData()); - $this->putLInt(count($skin->getAnimations())); - foreach($skin->getAnimations() as $animation){ + $this->putString($skin->getGeometryName()); //resource patch + $this->putImage(SerializedImage::fromLegacy($skin->getSkinData())); + /** @var SkinAnimation[] $animations */ + $animations = []; + $this->putLInt(count($animations)); + foreach($animations as $animation){ $this->putImage($animation->getImage()); $this->putLInt($animation->getType()); $this->putLFloat($animation->getFrames()); } - $this->putImage($skin->getCapeData()); + $this->putImage(new SerializedImage(0, 0, $skin->getCapeData())); $this->putString($skin->getGeometryData()); - $this->putString($skin->getAnimationData()); - $this->putBool($skin->getPremium()); - $this->putBool($skin->getPersona()); - $this->putBool($skin->getCapeOnClassic()); - $this->putString($skin->getCapeId()); - $this->putString($skin->getFullSkinId()); + $this->putString(""); //animation data + $this->putBool(false); //isPremium + $this->putBool(false); //isPersona + $this->putBool(false); //isCapeOnClassic + $this->putString(""); //capeId + $this->putString(""); //fullskinId } public function getImage() : SerializedImage{ diff --git a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php index 2500849f5..8d8672628 100644 --- a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php +++ b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php @@ -253,7 +253,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{ } public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{ - return $this->player->changeSkin($packet->skin, "", ""); + return $this->player->changeSkin($packet->skin, $packet->newSkinName, $packet->oldSkinName); } public function handleBookEdit(BookEditPacket $packet) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php b/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php index d40901c62..bbe513bd6 100644 --- a/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php +++ b/src/pocketmine/network/mcpe/protocol/PlayerSkinPacket.php @@ -36,25 +36,25 @@ class PlayerSkinPacket extends DataPacket{ /** @var UUID */ public $uuid; - /** @var Skin */ - public $skin; + /** @var string */ + public $oldSkinName = ""; /** @var string */ public $newSkinName = ""; - /** @var string */ - public $unknownString = ""; //Sent as empty, assuming it is the old skin name + /** @var Skin */ + public $skin; protected function decodePayload(){ $this->uuid = $this->getUUID(); $this->skin = $this->getSkin(); $this->newSkinName = $this->getString(); - $this->unknownString = $this->getString(); + $this->oldSkinName = $this->getString(); } protected function encodePayload(){ $this->putUUID($this->uuid); $this->putSkin($this->skin); $this->putString($this->newSkinName); - $this->putString($this->unknownString); + $this->putString($this->oldSkinName); } public function handle(NetworkSession $session) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/types/PlayerListEntry.php b/src/pocketmine/network/mcpe/protocol/types/PlayerListEntry.php index 525083d03..4803a4f1d 100644 --- a/src/pocketmine/network/mcpe/protocol/types/PlayerListEntry.php +++ b/src/pocketmine/network/mcpe/protocol/types/PlayerListEntry.php @@ -54,7 +54,7 @@ class PlayerListEntry{ return $entry; } - public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = 0, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{ + public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = -1, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{ $entry = new PlayerListEntry(); $entry->uuid = $uuid; $entry->entityUniqueId = $entityUniqueId; diff --git a/src/pocketmine/utils/SkinAnimation.php b/src/pocketmine/utils/SkinAnimation.php index 10092059b..b35c41cea 100644 --- a/src/pocketmine/utils/SkinAnimation.php +++ b/src/pocketmine/utils/SkinAnimation.php @@ -25,7 +25,9 @@ namespace pocketmine\utils; class SkinAnimation{ - public const TYPE_HEAD = 1; //Might want a double check on this + public const TYPE_HEAD = 1; + public const TYPE_BODY_32 = 2; + public const TYPE_BODY_64 = 3; /** @var SerializedImage */ private $image; @@ -40,15 +42,30 @@ class SkinAnimation{ $this->frames = $frames; } + /** + * Image of the animation. + * + * @return SerializedImage + */ public function getImage() : SerializedImage{ return $this->image; } + /** + * The type of animation you are applying. + * + * @return int + */ public function getType() : int{ return $this->type; } + /** + * The total amount of frames in an animation. + * + * @return float + */ public function getFrames() : float{ return $this->frames; } -} \ No newline at end of file +}