Added network components for skins, to collect instead of throw out data

This commit is contained in:
Stephen 2019-11-20 21:43:41 -05:00
parent 7f3460190b
commit be9c413a9e
13 changed files with 238 additions and 35 deletions

View File

@ -146,6 +146,9 @@ 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\PlayerPermissions;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\UpdateAttributesPacket;
use pocketmine\network\mcpe\protocol\UpdateBlockPacket;
use pocketmine\network\mcpe\VerifyLoginTask;
@ -1915,9 +1918,32 @@ 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 $animation){
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], $animation["Image"]), $animation["Type"], $animation["Frames"]);
}
new SkinData(
$packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinResourcePatch"] ?? ""),
new SkinImage($packet->clientData["SkinImageHeight"], $packet->clientData["SkinImageWidth"], base64_decode($packet->clientData["SkinData"])),
$animations,
new SkinImage($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"] ?? ""
);
$skinData = base64_decode($packet->clientData["SkinData"]);
if((bool) $packet->clientData["PersonaSkin"]){
$skinData = str_repeat(random_bytes(3) . "\xff", 2048);
}
$skin = new Skin(
$packet->clientData["SkinId"],
base64_decode($packet->clientData["SkinData"] ?? ""),
$skinData,
base64_decode($packet->clientData["CapeData"] ?? ""),
base64_decode($packet->clientData["SkinResourcePatch"] ?? ""),
base64_decode($packet->clientData["SkinGeometryData"] ?? "")

View File

@ -76,6 +76,7 @@ use pocketmine\network\mcpe\protocol\DataPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\RakLibInterface;
use pocketmine\network\Network;
use pocketmine\network\query\QueryHandler;
@ -2399,7 +2400,7 @@ class Server{
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin, $xboxUserId);
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, SkinAdapterSingleton::get()->toSkinData($skin), $xboxUserId);
$this->broadcastPacket($players ?? $this->playerList, $pk);
}
@ -2422,7 +2423,7 @@ class Server{
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
foreach($this->playerList as $player){
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin(), $player->getXuid());
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), SkinAdapterSingleton::get()->toSkinData($player->getSkin()), $player->getXuid());
}
$p->dataPacket($pk);

View File

@ -53,6 +53,7 @@ use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\Player;
use pocketmine\utils\UUID;
use function array_filter;
@ -182,7 +183,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
public function sendSkin(?array $targets = null) : void{
$pk = new PlayerSkinPacket();
$pk->uuid = $this->getUniqueId();
$pk->skin = $this->skin;
$pk->skin = SkinAdapterSingleton::get()->toSkinData($this->skin);
$this->server->broadcastPacket($targets ?? $this->hasSpawned, $pk);
}
@ -850,7 +851,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
$pk = new PlayerListPacket();
$pk->type = PlayerListPacket::TYPE_ADD;
$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), $this->skin)];
$pk->entries = [PlayerListEntry::createAdditionEntry($this->uuid, $this->id, $this->getName(), SkinAdapterSingleton::get()->toSkinData($this->skin))];
$player->dataPacket($pk);
}

View File

@ -32,6 +32,7 @@ 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\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\utils\UUID;
use function str_repeat;
@ -96,7 +97,9 @@ class FloatingTextParticle extends Particle{
$add = new PlayerListPacket();
$add->type = PlayerListPacket::TYPE_ADD;
$add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, new Skin("Standard_Custom", str_repeat("\x00", 8192)))];
$add->entries = [PlayerListEntry::createAdditionEntry($uuid, $this->entityId, $name, SkinAdapterSingleton::get()->toSkinData(new Skin(
"Standard_Custom", str_repeat("\x00", 8192), "", '{"geometry" : {"default" : "geometry.humanoid.custom"}}' //TODO: Remove, hack to fix ftp
)))];
$p[] = $add;
$pk = new AddPlayerPacket();

View File

@ -38,6 +38,7 @@ 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\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\StructureSettings;
@ -77,7 +78,7 @@ class NetworkBinaryStream extends BinaryStream{
$this->putLInt($uuid->getPart(2));
}
public function getSkin() : Skin{
public function getSkin() : SkinData{
$skinId = $this->getString();
$skinResourcePatch = $this->getString();
$skinData = $this->getSkinImage();
@ -99,32 +100,26 @@ class NetworkBinaryStream extends BinaryStream{
$capeId = $this->getString();
$fullSkinId = $this->getString();
return new Skin($skinId, $skinData->getData(), $capeData->getData(), $skinResourcePatch, $geometryData);
return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId);
}
public function putSkin(Skin $skin){
$this->putString($skin->getSkinId());
$this->putString($skin->getGeometryName()); //resource patch
$this->putSkinImage(SkinImage::fromLegacy($skin->getSkinData()));
/** @var SkinAnimation[] $animations */
$animations = [];
$this->putLInt(count($animations));
foreach($animations as $animation){
public function putSkin(SkinData $skin){
$this->putString($skin->skinId);
$this->putString($skin->resourcePatch); //resource patch
$this->putSkinImage($skin->skinImage);
$this->putLInt(count($skin->animations));
foreach($skin->animations as $animation){
$this->putSkinImage($animation->getImage());
$this->putLInt($animation->getType());
$this->putLFloat($animation->getFrames());
}
if($skin->getCapeData() !== ""){
$this->putSkinImage(new SkinImage(32, 64, $skin->getCapeData()));
}else{
$this->putSkinImage(new SkinImage(0, 0, ""));
}
$this->putString($skin->getGeometryData());
$this->putString(""); //animation data
$this->putBool(false); //isPremium
$this->putBool(false); //isPersona
$this->putBool(false); //isCapeOnClassic
$this->putString(""); //capeId
$this->putSkinImage($skin->capeImage);
$this->putString($skin->geometryData);
$this->putString($skin->animationData);
$this->putBool($skin->premium);
$this->putBool($skin->persona);
$this->putBool($skin->capeOnClassic);
$this->putString($skin->capeId);
//this has to be unique or the client will do stupid things
$this->putString(UUID::fromRandom()->toString()); //full skin ID

View File

@ -66,6 +66,8 @@ use pocketmine\network\mcpe\protocol\SetPlayerGameTypePacket;
use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\timings\Timings;
@ -253,7 +255,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
}
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
return $this->player->changeSkin($packet->skin, $packet->newSkinName, $packet->oldSkinName);
return $this->player->changeSkin(SkinAdapterSingleton::get()->fromSkinData($packet->skin), $packet->newSkinName, $packet->oldSkinName);
}
public function handleBookEdit(BookEditPacket $packet) : bool{

View File

@ -27,6 +27,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use function count;
@ -81,7 +82,7 @@ class PlayerListPacket extends DataPacket{
$this->putString($entry->xboxUserId);
$this->putString($entry->platformChatId);
$this->putLInt($entry->buildPlatform);
$this->putSkin($entry->skin);
$this->putSkin($entry->skinData);
$this->putBool($entry->isTeacher);
$this->putBool($entry->isHost);
}else{

View File

@ -25,8 +25,8 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\entity\Skin;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\utils\UUID;
class PlayerSkinPacket extends DataPacket{
@ -38,7 +38,7 @@ class PlayerSkinPacket extends DataPacket{
public $oldSkinName = "";
/** @var string */
public $newSkinName = "";
/** @var Skin */
/** @var SkinData */
public $skin;
protected function decodePayload(){

View File

@ -0,0 +1,37 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\entity\Skin;
class LegacySkinAdapter implements SkinAdapter{
public function toSkinData(Skin $skin) : SkinData{
return new SkinData($skin->getSkinId(), $skin->getGeometryName(), SkinImage::fromLegacy($skin->getSkinData()), [], new SkinImage(32, 64, $skin->getCapeData()), $skin->getGeometryData());
}
public function fromSkinData(SkinData $data) : Skin{
return new Skin($data->skinId, $data->skinImage->getData(), $data->capeImage->getData(), $data->resourcePatch, $data->geometryData);
}
}

View File

@ -34,8 +34,8 @@ class PlayerListEntry{
public $entityUniqueId;
/** @var string */
public $username;
/** @var Skin */
public $skin;
/** @var SkinData */
public $skinData;
/** @var string */
public $xboxUserId;
/** @var string */
@ -54,12 +54,12 @@ class PlayerListEntry{
return $entry;
}
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{
public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, SkinData $skinData, string $xboxUserId = "", string $platformChatId = "", int $buildPlatform = -1, bool $isTeacher = false, bool $isHost = false) : PlayerListEntry{
$entry = new PlayerListEntry();
$entry->uuid = $uuid;
$entry->entityUniqueId = $entityUniqueId;
$entry->username = $username;
$entry->skin = $skin;
$entry->skinData = $skinData;
$entry->xboxUserId = $xboxUserId;
$entry->platformChatId = $platformChatId;
$entry->buildPlatform = $buildPlatform;

View File

@ -0,0 +1,33 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\entity\Skin;
interface SkinAdapter{
public function toSkinData(Skin $skin) : SkinData;
public function fromSkinData(SkinData $data) : Skin;
}

View File

@ -0,0 +1,40 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
class SkinAdapterSingleton{
private static $skinAdapter = null;
public static function get() : SkinAdapter{
if(self::$skinAdapter === null){
self::$skinAdapter = new LegacySkinAdapter();
}
return self::$skinAdapter;
}
public static function set(SkinAdapter $adapter){
self::$skinAdapter = $adapter;
}
}

View File

@ -0,0 +1,64 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
class SkinData{
/** @var string */
public $skinId;
/** @var string */
public $resourcePatch;
/** @var SkinImage */
public $skinImage;
/** @var SkinAnimation[] */
public $animations;
/** @var SkinImage */
public $capeImage;
/** @var string */
public $geometryData;
/** @var string */
public $animationData;
/** @var bool */
public $persona;
/** @var bool */
public $premium;
/** @var bool */
public $capeOnClassic;
/** @var string */
public $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 $capeOnClassic = false, string $capeId = ""){
$this->skinId = $skinId;
$this->resourcePatch = $resourcePatch;
$this->skinImage = $skinImage;
$this->animations = $animations;
$this->capeImage = $capeImage;
$this->geometryData = $geometryData;
$this->animationData = $animationData;
$this->premium = $premium;
$this->persona = $persona;
$this->capeOnClassic = $capeOnClassic;
$this->capeId = $capeId;
}
}