mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-13 09:19:42 +00:00
Merge branch 'stable' of https://github.com/drew-mcbe/pocketmine-mp into drew-1.13
This commit is contained in:
commit
8ee0fbccc5
@ -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()){
|
||||
|
@ -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())
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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();
|
||||
|
@ -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{
|
||||
|
@ -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{
|
||||
|
@ -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{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user