From e2fc7cdf880938dfde3f9b3e81acf01f367dcd41 Mon Sep 17 00:00:00 2001 From: Stephen Date: Sun, 10 Nov 2019 21:04:38 -0500 Subject: [PATCH] Friendly BC skins (persona not supported) --- src/pocketmine/Player.php | 16 +-- src/pocketmine/entity/Human.php | 31 ++---- src/pocketmine/entity/Skin.php | 100 +++--------------- .../level/particle/FloatingTextParticle.php | 2 +- .../network/mcpe/NetworkBinaryStream.php | 28 ++--- 5 files changed, 42 insertions(+), 135 deletions(-) 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..59fd5c266 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -120,16 +120,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; @@ -839,19 +833,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ 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..17630a679 100644 --- a/src/pocketmine/entity/Skin.php +++ b/src/pocketmine/entity/Skin.php @@ -41,38 +41,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 +81,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 +101,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 +126,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..7a7e622d3 100644 --- a/src/pocketmine/level/particle/FloatingTextParticle.php +++ b/src/pocketmine/level/particle/FloatingTextParticle.php @@ -97,7 +97,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 5b87a2d26..7d969dd0d 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{