mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-05 17:41:46 +00:00
New skin API, add support for custom capes & custom geometry (#1416)
* Added support for changing skins ingame, custom capes & geometry * Use PlayerSkinPacket for setting Human skin instead of PlayerList hack
This commit is contained in:
parent
c273a46537
commit
e6cecabf3f
@ -34,6 +34,7 @@ use pocketmine\entity\Entity;
|
|||||||
use pocketmine\entity\Human;
|
use pocketmine\entity\Human;
|
||||||
use pocketmine\entity\Item as DroppedItem;
|
use pocketmine\entity\Item as DroppedItem;
|
||||||
use pocketmine\entity\Living;
|
use pocketmine\entity\Living;
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
use pocketmine\event\entity\EntityDamageByBlockEvent;
|
||||||
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
use pocketmine\event\entity\EntityDamageByEntityEvent;
|
||||||
use pocketmine\event\entity\EntityDamageEvent;
|
use pocketmine\event\entity\EntityDamageEvent;
|
||||||
@ -46,6 +47,7 @@ use pocketmine\event\player\PlayerAnimationEvent;
|
|||||||
use pocketmine\event\player\PlayerBedEnterEvent;
|
use pocketmine\event\player\PlayerBedEnterEvent;
|
||||||
use pocketmine\event\player\PlayerBedLeaveEvent;
|
use pocketmine\event\player\PlayerBedLeaveEvent;
|
||||||
use pocketmine\event\player\PlayerBlockPickEvent;
|
use pocketmine\event\player\PlayerBlockPickEvent;
|
||||||
|
use pocketmine\event\player\PlayerChangeSkinEvent;
|
||||||
use pocketmine\event\player\PlayerChatEvent;
|
use pocketmine\event\player\PlayerChatEvent;
|
||||||
use pocketmine\event\player\PlayerCommandPreprocessEvent;
|
use pocketmine\event\player\PlayerCommandPreprocessEvent;
|
||||||
use pocketmine\event\player\PlayerDeathEvent;
|
use pocketmine\event\player\PlayerDeathEvent;
|
||||||
@ -182,15 +184,6 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return $lname !== "rcon" and $lname !== "console" and $len >= 1 and $len <= 16 and preg_match("/[^A-Za-z0-9_ ]/", $name) === 0;
|
return $lname !== "rcon" and $lname !== "console" and $len >= 1 and $len <= 16 and preg_match("/[^A-Za-z0-9_ ]/", $name) === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the length of a supplied skin bitmap and returns whether the length is valid.
|
|
||||||
* @param string $skin
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public static function isValidSkin(string $skin) : bool{
|
|
||||||
return strlen($skin) === 64 * 64 * 4 or strlen($skin) === 64 * 32 * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var SourceInterface */
|
/** @var SourceInterface */
|
||||||
protected $interface;
|
protected $interface;
|
||||||
@ -717,15 +710,36 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
public function setDisplayName(string $name){
|
public function setDisplayName(string $name){
|
||||||
$this->displayName = $name;
|
$this->displayName = $name;
|
||||||
if($this->spawned){
|
if($this->spawned){
|
||||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $this->getSkinId(), $this->getSkinData());
|
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $this->getSkin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSkin(string $str, string $skinId){
|
/**
|
||||||
parent::setSkin($str, $skinId);
|
* Called when a player changes their skin.
|
||||||
if($this->spawned){
|
* Plugin developers should not use this, use setSkin() and sendSkin() instead.
|
||||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getDisplayName(), $skinId, $str);
|
*
|
||||||
|
* @param Skin $skin
|
||||||
|
* @param string $newSkinName
|
||||||
|
* @param string $oldSkinName
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function changeSkin(Skin $skin, string $newSkinName, string $oldSkinName) : bool{
|
||||||
|
if(!$skin->isValid()){
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$ev = new PlayerChangeSkinEvent($this, $this->getSkin(), $skin);
|
||||||
|
$this->server->getPluginManager()->callEvent($ev);
|
||||||
|
|
||||||
|
if($ev->isCancelled()){
|
||||||
|
$this->sendSkin([$this]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setSkin($ev->getNewSkin());
|
||||||
|
$this->sendSkin($this->server->getOnlinePlayers());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jump(){
|
public function jump(){
|
||||||
@ -2005,12 +2019,20 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Player::isValidSkin($packet->skin)){
|
$skin = new Skin(
|
||||||
|
$packet->clientData["SkinId"],
|
||||||
|
base64_decode($packet->clientData["SkinData"] ?? ""),
|
||||||
|
base64_decode($packet->clientData["CapeData"] ?? ""),
|
||||||
|
$packet->clientData["SkinGeometryName"],
|
||||||
|
base64_decode($packet->clientData["SkinGeometry"] ?? "")
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!$skin->isValid()){
|
||||||
$this->close("", "disconnectionScreen.invalidSkin");
|
$this->close("", "disconnectionScreen.invalidSkin");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setSkin($packet->skin, $packet->skinId);
|
$this->setSkin($skin);
|
||||||
|
|
||||||
if(!$this->server->isWhitelisted($this->iusername) and $this->kick("Server is white-listed", false)){
|
if(!$this->server->isWhitelisted($this->iusername) and $this->kick("Server is white-listed", false)){
|
||||||
return true;
|
return true;
|
||||||
|
@ -81,7 +81,7 @@ namespace pocketmine {
|
|||||||
|
|
||||||
const NAME = "PocketMine-MP";
|
const NAME = "PocketMine-MP";
|
||||||
const VERSION = "1.7dev";
|
const VERSION = "1.7dev";
|
||||||
const API_VERSION = "3.0.0-ALPHA8";
|
const API_VERSION = "3.0.0-ALPHA9";
|
||||||
const CODENAME = "[REDACTED]";
|
const CODENAME = "[REDACTED]";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -36,6 +36,7 @@ use pocketmine\command\SimpleCommandMap;
|
|||||||
use pocketmine\entity\Attribute;
|
use pocketmine\entity\Attribute;
|
||||||
use pocketmine\entity\Effect;
|
use pocketmine\entity\Effect;
|
||||||
use pocketmine\entity\Entity;
|
use pocketmine\entity\Entity;
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\event\HandlerList;
|
use pocketmine\event\HandlerList;
|
||||||
use pocketmine\event\level\LevelInitEvent;
|
use pocketmine\event\level\LevelInitEvent;
|
||||||
use pocketmine\event\level\LevelLoadEvent;
|
use pocketmine\event\level\LevelLoadEvent;
|
||||||
@ -2283,7 +2284,7 @@ class Server{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function addOnlinePlayer(Player $player){
|
public function addOnlinePlayer(Player $player){
|
||||||
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
|
$this->updatePlayerListData($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
|
|
||||||
$this->playerList[$player->getRawUniqueId()] = $player;
|
$this->playerList[$player->getRawUniqueId()] = $player;
|
||||||
}
|
}
|
||||||
@ -2300,15 +2301,14 @@ class Server{
|
|||||||
* @param UUID $uuid
|
* @param UUID $uuid
|
||||||
* @param int $entityId
|
* @param int $entityId
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param string $skinId
|
* @param Skin $skin
|
||||||
* @param string $skinData
|
|
||||||
* @param Player[]|null $players
|
* @param Player[]|null $players
|
||||||
*/
|
*/
|
||||||
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, string $skinId, string $skinData, array $players = null){
|
public function updatePlayerListData(UUID $uuid, int $entityId, string $name, Skin $skin, array $players = null){
|
||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
|
|
||||||
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skinId, $skinData);
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($uuid, $entityId, $name, $skin);
|
||||||
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
$this->broadcastPacket($players ?? $this->playerList, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2330,7 +2330,7 @@ class Server{
|
|||||||
$pk = new PlayerListPacket();
|
$pk = new PlayerListPacket();
|
||||||
$pk->type = PlayerListPacket::TYPE_ADD;
|
$pk->type = PlayerListPacket::TYPE_ADD;
|
||||||
foreach($this->playerList as $player){
|
foreach($this->playerList as $player){
|
||||||
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkinId(), $player->getSkinData());
|
$pk->entries[] = PlayerListEntry::createAdditionEntry($player->getUniqueId(), $player->getId(), $player->getDisplayName(), $player->getSkin());
|
||||||
}
|
}
|
||||||
|
|
||||||
$p->dataPacket($pk);
|
$p->dataPacket($pk);
|
||||||
|
@ -37,6 +37,7 @@ use pocketmine\nbt\tag\IntTag;
|
|||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
use pocketmine\nbt\tag\StringTag;
|
use pocketmine\nbt\tag\StringTag;
|
||||||
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
use pocketmine\network\mcpe\protocol\AddPlayerPacket;
|
||||||
|
use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
|
||||||
use pocketmine\Player;
|
use pocketmine\Player;
|
||||||
use pocketmine\utils\UUID;
|
use pocketmine\utils\UUID;
|
||||||
|
|
||||||
@ -60,8 +61,8 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
public $height = 1.8;
|
public $height = 1.8;
|
||||||
public $eyeHeight = 1.62;
|
public $eyeHeight = 1.62;
|
||||||
|
|
||||||
protected $skinId;
|
/** @var Skin */
|
||||||
protected $skin = "";
|
protected $skin;
|
||||||
|
|
||||||
protected $foodTickTimer = 0;
|
protected $foodTickTimer = 0;
|
||||||
|
|
||||||
@ -71,19 +72,22 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
protected $baseOffset = 1.62;
|
protected $baseOffset = 1.62;
|
||||||
|
|
||||||
public function __construct(Level $level, CompoundTag $nbt){
|
public function __construct(Level $level, CompoundTag $nbt){
|
||||||
if($this->skin === "" and (!isset($nbt->Skin) or !isset($nbt->Skin->Data) or !Player::isValidSkin($nbt->Skin->Data->getValue()))){
|
if($this->skin === null and (!isset($nbt->Skin) or !isset($nbt->Skin->Data) or !Player::isValidSkin($nbt->Skin->Data->getValue()))){
|
||||||
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($level, $nbt);
|
parent::__construct($level, $nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSkinData(){
|
/**
|
||||||
return $this->skin;
|
* Checks the length of a supplied skin bitmap and returns whether the length is valid.
|
||||||
}
|
*
|
||||||
|
* @param string $skin
|
||||||
public function getSkinId(){
|
*
|
||||||
return $this->skinId;
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isValidSkin(string $skin) : bool{
|
||||||
|
return strlen($skin) === 64 * 64 * 4 or strlen($skin) === 64 * 32 * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,16 +105,35 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $str
|
* Returns a Skin object containing information about this human's skin.
|
||||||
* @param string $skinId
|
* @return Skin
|
||||||
*/
|
*/
|
||||||
public function setSkin(string $str, string $skinId){
|
public function getSkin() : Skin{
|
||||||
if(!Player::isValidSkin($str)){
|
return $this->skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the human's skin. This will not send any update to viewers, you need to do that manually using
|
||||||
|
* {@link sendSkin}.
|
||||||
|
*
|
||||||
|
* @param Skin $skin
|
||||||
|
*/
|
||||||
|
public function setSkin(Skin $skin) : void{
|
||||||
|
if(!$skin->isValid()){
|
||||||
throw new \InvalidStateException("Specified skin is not valid, must be 8KiB or 16KiB");
|
throw new \InvalidStateException("Specified skin is not valid, must be 8KiB or 16KiB");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->skin = $str;
|
$this->skin = $skin;
|
||||||
$this->skinId = $skinId;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player[] $targets
|
||||||
|
*/
|
||||||
|
public function sendSkin(array $targets) : void{
|
||||||
|
$pk = new PlayerSkinPacket();
|
||||||
|
$pk->uuid = $this->getUniqueId();
|
||||||
|
$pk->skin = $this->skin;
|
||||||
|
$this->server->broadcastPacket($targets, $pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function jump(){
|
public function jump(){
|
||||||
@ -287,10 +310,13 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(isset($this->namedtag->Skin) and $this->namedtag->Skin instanceof CompoundTag){
|
if(isset($this->namedtag->Skin) and $this->namedtag->Skin instanceof CompoundTag){
|
||||||
$this->setSkin($this->namedtag->Skin["Data"], $this->namedtag->Skin["Name"]);
|
$this->setSkin(new Skin(
|
||||||
|
$this->namedtag->Skin["Name"],
|
||||||
|
$this->namedtag->Skin["Data"]
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->uuid = UUID::fromData((string) $this->getId(), $this->getSkinData(), $this->getNameTag());
|
$this->uuid = UUID::fromData((string) $this->getId(), $this->skin->getSkinData(), $this->getNameTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function initEntity(){
|
protected function initEntity(){
|
||||||
@ -467,10 +493,11 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
$this->namedtag->SelectedInventorySlot = new IntTag("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
|
$this->namedtag->SelectedInventorySlot = new IntTag("SelectedInventorySlot", $this->inventory->getHeldItemIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strlen($this->getSkinData()) > 0){
|
if($this->skin !== null){
|
||||||
$this->namedtag->Skin = new CompoundTag("Skin", [
|
$this->namedtag->Skin = new CompoundTag("Skin", [
|
||||||
new StringTag("Data", $this->getSkinData()),
|
//TODO: save cape & geometry
|
||||||
new StringTag("Name", $this->getSkinId())
|
new StringTag("Data", $this->skin->getSkinData()),
|
||||||
|
new StringTag("Name", $this->skin->getSkinId())
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,14 +506,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
if($player !== $this and !isset($this->hasSpawned[$player->getLoaderId()])){
|
if($player !== $this and !isset($this->hasSpawned[$player->getLoaderId()])){
|
||||||
$this->hasSpawned[$player->getLoaderId()] = $player;
|
$this->hasSpawned[$player->getLoaderId()] = $player;
|
||||||
|
|
||||||
if(!Player::isValidSkin($this->skin)){
|
if(!$this->skin->isValid()){
|
||||||
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!($this instanceof Player)){
|
|
||||||
$this->server->updatePlayerListData($this->getUniqueId(), $this->getId(), $this->getName(), $this->skinId, $this->skin, [$player]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$pk = new AddPlayerPacket();
|
$pk = new AddPlayerPacket();
|
||||||
$pk->uuid = $this->getUniqueId();
|
$pk->uuid = $this->getUniqueId();
|
||||||
$pk->username = $this->getName();
|
$pk->username = $this->getName();
|
||||||
@ -502,7 +525,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
$this->inventory->sendArmorContents($player);
|
$this->inventory->sendArmorContents($player);
|
||||||
|
|
||||||
if(!($this instanceof Player)){
|
if(!($this instanceof Player)){
|
||||||
$this->server->removePlayerListData($this->getUniqueId(), [$player]);
|
$this->sendSkin([$player]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
90
src/pocketmine/entity/Skin.php
Normal file
90
src/pocketmine/entity/Skin.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?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\entity;
|
||||||
|
|
||||||
|
class Skin{
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
private $skinId;
|
||||||
|
/** @var string */
|
||||||
|
private $skinData;
|
||||||
|
/** @var string */
|
||||||
|
private $capeData;
|
||||||
|
/** @var string */
|
||||||
|
private $geometryName;
|
||||||
|
/** @var string */
|
||||||
|
private $geometryData;
|
||||||
|
|
||||||
|
public function __construct(string $skinId, string $skinData, string $capeData = "", string $geometryName = "", string $geometryData = ""){
|
||||||
|
$this->skinId = $skinId;
|
||||||
|
$this->skinData = $skinData;
|
||||||
|
$this->capeData = $capeData;
|
||||||
|
$this->geometryName = $geometryName;
|
||||||
|
$this->geometryData = $geometryData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid() : bool{
|
||||||
|
return (
|
||||||
|
$this->skinId !== "" and
|
||||||
|
(($s = strlen($this->skinData)) === 16384 or $s === 8192) and
|
||||||
|
($this->capeData === "" or strlen($this->capeData) === 8192)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSkinId() : string{
|
||||||
|
return $this->skinId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getSkinData() : string{
|
||||||
|
return $this->skinData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getCapeData() : string{
|
||||||
|
return $this->capeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getGeometryName() : string{
|
||||||
|
return $this->geometryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getGeometryData() : string{
|
||||||
|
return $this->geometryData;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
src/pocketmine/event/player/PlayerChangeSkinEvent.php
Normal file
78
src/pocketmine/event/player/PlayerChangeSkinEvent.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?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\event\player;
|
||||||
|
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
|
use pocketmine\event\Cancellable;
|
||||||
|
use pocketmine\Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a player changes their skin in-game.
|
||||||
|
*/
|
||||||
|
class PlayerChangeSkinEvent extends PlayerEvent implements Cancellable{
|
||||||
|
public static $handlerList = null;
|
||||||
|
|
||||||
|
/** @var Skin */
|
||||||
|
private $oldSkin;
|
||||||
|
/** @var Skin */
|
||||||
|
private $newSkin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Player $player
|
||||||
|
* @param Skin $oldSkin
|
||||||
|
* @param Skin $newSkin
|
||||||
|
*/
|
||||||
|
public function __construct(Player $player, Skin $oldSkin, Skin $newSkin){
|
||||||
|
$this->player = $player;
|
||||||
|
$this->oldSkin = $oldSkin;
|
||||||
|
$this->newSkin = $newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Skin
|
||||||
|
*/
|
||||||
|
public function getOldSkin() : Skin{
|
||||||
|
return $this->oldSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Skin
|
||||||
|
*/
|
||||||
|
public function getNewSkin() : Skin{
|
||||||
|
return $this->newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Skin $skin
|
||||||
|
* @throws \InvalidArgumentException if the specified skin is not valid
|
||||||
|
*/
|
||||||
|
public function setNewSkin(Skin $skin) : void{
|
||||||
|
if(!$skin->isValid()){
|
||||||
|
throw new \InvalidArgumentException("Skin format is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->newSkin = $skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -228,7 +228,7 @@ class PlayerNetworkSessionAdapter extends NetworkSession{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
|
public function handlePlayerSkin(PlayerSkinPacket $packet) : bool{
|
||||||
return false; //TODO
|
return $this->player->changeSkin($packet->skin, $packet->newSkinName, $packet->oldSkinName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
|
public function handleModalFormResponse(ModalFormResponsePacket $packet) : bool{
|
||||||
|
@ -48,11 +48,6 @@ class LoginPacket extends DataPacket{
|
|||||||
/** @var string */
|
/** @var string */
|
||||||
public $serverAddress;
|
public $serverAddress;
|
||||||
|
|
||||||
/** @var string */
|
|
||||||
public $skinId;
|
|
||||||
/** @var string */
|
|
||||||
public $skin = "";
|
|
||||||
|
|
||||||
/** @var array (the "chain" index contains one or more JWTs) */
|
/** @var array (the "chain" index contains one or more JWTs) */
|
||||||
public $chainData = [];
|
public $chainData = [];
|
||||||
/** @var string */
|
/** @var string */
|
||||||
@ -102,11 +97,6 @@ class LoginPacket extends DataPacket{
|
|||||||
|
|
||||||
$this->clientId = $this->clientData["ClientRandomId"] ?? null;
|
$this->clientId = $this->clientData["ClientRandomId"] ?? null;
|
||||||
$this->serverAddress = $this->clientData["ServerAddress"] ?? null;
|
$this->serverAddress = $this->clientData["ServerAddress"] ?? null;
|
||||||
$this->skinId = $this->clientData["SkinId"] ?? null;
|
|
||||||
|
|
||||||
if(isset($this->clientData["SkinData"])){
|
|
||||||
$this->skin = base64_decode($this->clientData["SkinData"]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
|
@ -26,6 +26,7 @@ namespace pocketmine\network\mcpe\protocol;
|
|||||||
#include <rules/DataPacket.h>
|
#include <rules/DataPacket.h>
|
||||||
|
|
||||||
|
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
|
||||||
|
|
||||||
@ -55,11 +56,13 @@ class PlayerListPacket extends DataPacket{
|
|||||||
$entry->uuid = $this->getUUID();
|
$entry->uuid = $this->getUUID();
|
||||||
$entry->entityUniqueId = $this->getEntityUniqueId();
|
$entry->entityUniqueId = $this->getEntityUniqueId();
|
||||||
$entry->username = $this->getString();
|
$entry->username = $this->getString();
|
||||||
$entry->skinId = $this->getString();
|
$entry->skin = new Skin(
|
||||||
$entry->skinData = $this->getString();
|
$this->getString(), //id
|
||||||
$entry->capeData = $this->getString();
|
$this->getString(), //data
|
||||||
$entry->geometryModel = $this->getString();
|
$this->getString(), //cape
|
||||||
$entry->geometryData = $this->getString();
|
$this->getString(), //geometry name
|
||||||
|
$this->getString() //geometry data
|
||||||
|
);
|
||||||
$entry->xboxUserId = $this->getString();
|
$entry->xboxUserId = $this->getString();
|
||||||
}else{
|
}else{
|
||||||
$entry->uuid = $this->getUUID();
|
$entry->uuid = $this->getUUID();
|
||||||
@ -77,11 +80,11 @@ class PlayerListPacket extends DataPacket{
|
|||||||
$this->putUUID($entry->uuid);
|
$this->putUUID($entry->uuid);
|
||||||
$this->putEntityUniqueId($entry->entityUniqueId);
|
$this->putEntityUniqueId($entry->entityUniqueId);
|
||||||
$this->putString($entry->username);
|
$this->putString($entry->username);
|
||||||
$this->putString($entry->skinId);
|
$this->putString($entry->skin->getSkinId());
|
||||||
$this->putString($entry->skinData);
|
$this->putString($entry->skin->getSkinData());
|
||||||
$this->putString($entry->capeData);
|
$this->putString($entry->skin->getCapeData());
|
||||||
$this->putString($entry->geometryModel);
|
$this->putString($entry->skin->getGeometryName());
|
||||||
$this->putString($entry->geometryData);
|
$this->putString($entry->skin->getGeometryData());
|
||||||
$this->putString($entry->xboxUserId);
|
$this->putString($entry->xboxUserId);
|
||||||
}else{
|
}else{
|
||||||
$this->putUUID($entry->uuid);
|
$this->putUUID($entry->uuid);
|
||||||
|
@ -25,6 +25,7 @@ namespace pocketmine\network\mcpe\protocol;
|
|||||||
|
|
||||||
#include <rules/DataPacket.h>
|
#include <rules/DataPacket.h>
|
||||||
|
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\network\mcpe\NetworkSession;
|
use pocketmine\network\mcpe\NetworkSession;
|
||||||
use pocketmine\utils\UUID;
|
use pocketmine\utils\UUID;
|
||||||
|
|
||||||
@ -34,41 +35,37 @@ class PlayerSkinPacket extends DataPacket{
|
|||||||
/** @var UUID */
|
/** @var UUID */
|
||||||
public $uuid;
|
public $uuid;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public $skinId;
|
public $oldSkinName = "";
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public $newSkinName;
|
public $newSkinName = "";
|
||||||
/** @var string */
|
/** @var Skin */
|
||||||
public $oldSkinName;
|
public $skin;
|
||||||
/** @var string */
|
|
||||||
public $skinData;
|
|
||||||
/** @var string */
|
|
||||||
public $capeData;
|
|
||||||
/** @var string */
|
|
||||||
public $geometryModel;
|
|
||||||
/** @var string */
|
|
||||||
public $geometryData;
|
|
||||||
|
|
||||||
|
|
||||||
protected function decodePayload(){
|
protected function decodePayload(){
|
||||||
$this->uuid = $this->getUUID();
|
$this->uuid = $this->getUUID();
|
||||||
$this->skinId = $this->getString();
|
|
||||||
|
$skinId = $this->getString();
|
||||||
$this->newSkinName = $this->getString();
|
$this->newSkinName = $this->getString();
|
||||||
$this->oldSkinName = $this->getString();
|
$this->oldSkinName = $this->getString();
|
||||||
$this->skinData = $this->getString();
|
$skinData = $this->getString();
|
||||||
$this->capeData = $this->getString();
|
$capeData = $this->getString();
|
||||||
$this->geometryModel = $this->getString();
|
$geometryModel = $this->getString();
|
||||||
$this->geometryData = $this->getString();
|
$geometryData = $this->getString();
|
||||||
|
|
||||||
|
$this->skin = new Skin($skinId, $skinData, $capeData, $geometryModel, $geometryData);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function encodePayload(){
|
protected function encodePayload(){
|
||||||
$this->putUUID($this->uuid);
|
$this->putUUID($this->uuid);
|
||||||
$this->putString($this->skinId);
|
|
||||||
|
$this->putString($this->skin->getSkinId());
|
||||||
$this->putString($this->newSkinName);
|
$this->putString($this->newSkinName);
|
||||||
$this->putString($this->oldSkinName);
|
$this->putString($this->oldSkinName);
|
||||||
$this->putString($this->skinData);
|
$this->putString($this->skin->getSkinData());
|
||||||
$this->putString($this->capeData);
|
$this->putString($this->skin->getCapeData());
|
||||||
$this->putString($this->geometryModel);
|
$this->putString($this->skin->getGeometryName());
|
||||||
$this->putString($this->geometryData);
|
$this->putString($this->skin->getGeometryData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handle(NetworkSession $session) : bool{
|
public function handle(NetworkSession $session) : bool{
|
||||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\network\mcpe\protocol\types;
|
namespace pocketmine\network\mcpe\protocol\types;
|
||||||
|
|
||||||
|
use pocketmine\entity\Skin;
|
||||||
use pocketmine\utils\UUID;
|
use pocketmine\utils\UUID;
|
||||||
|
|
||||||
class PlayerListEntry{
|
class PlayerListEntry{
|
||||||
@ -33,16 +34,8 @@ class PlayerListEntry{
|
|||||||
public $entityUniqueId;
|
public $entityUniqueId;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public $username;
|
public $username;
|
||||||
/** @var string */
|
/** @var Skin */
|
||||||
public $skinId;
|
public $skin;
|
||||||
/** @var string */
|
|
||||||
public $skinData;
|
|
||||||
/** @var string */
|
|
||||||
public $capeData; //TODO
|
|
||||||
/** @var string */
|
|
||||||
public $geometryModel; //TODO
|
|
||||||
/** @var string */
|
|
||||||
public $geometryData; //TODO
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
public $xboxUserId; //TODO
|
public $xboxUserId; //TODO
|
||||||
|
|
||||||
@ -53,26 +46,12 @@ class PlayerListEntry{
|
|||||||
return $entry;
|
return $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function createAdditionEntry(
|
public static function createAdditionEntry(UUID $uuid, int $entityUniqueId, string $username, Skin $skin, string $xboxUserId = "") : PlayerListEntry{
|
||||||
UUID $uuid,
|
|
||||||
int $entityUniqueId,
|
|
||||||
string $username,
|
|
||||||
string $skinId,
|
|
||||||
string $skinData,
|
|
||||||
string $capeData = "",
|
|
||||||
string $geometryModel = "",
|
|
||||||
string $geometryData = "",
|
|
||||||
string $xboxUserId = ""
|
|
||||||
) : PlayerListEntry{
|
|
||||||
$entry = new PlayerListEntry();
|
$entry = new PlayerListEntry();
|
||||||
$entry->uuid = $uuid;
|
$entry->uuid = $uuid;
|
||||||
$entry->entityUniqueId = $entityUniqueId;
|
$entry->entityUniqueId = $entityUniqueId;
|
||||||
$entry->username = $username;
|
$entry->username = $username;
|
||||||
$entry->skinId = $skinId;
|
$entry->skin = $skin;
|
||||||
$entry->skinData = $skinData;
|
|
||||||
$entry->capeData = $capeData;
|
|
||||||
$entry->geometryModel = $geometryModel;
|
|
||||||
$entry->geometryData = $geometryData;
|
|
||||||
$entry->xboxUserId = $xboxUserId;
|
$entry->xboxUserId = $xboxUserId;
|
||||||
|
|
||||||
return $entry;
|
return $entry;
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit eec5da2443b84821bd7e7224adea4921c81dc674
|
Subproject commit 857e8afab4a7a34c7235ce06e43796bf64581e3d
|
@ -1 +1 @@
|
|||||||
Subproject commit 9249723281f7ee63e51cd51862682187bbe70ad2
|
Subproject commit 7e084a9eea099fadf0eb52c683b367b340a2b570
|
Loading…
x
Reference in New Issue
Block a user