mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-05-09 23:39:43 +00:00
Merge branch 'stable'
# Conflicts: # resources/vanilla # src/pocketmine/entity/Human.php
This commit is contained in:
commit
64f7f558a4
@ -43,7 +43,6 @@ use pocketmine\item\FoodSource;
|
|||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
use pocketmine\item\Totem;
|
use pocketmine\item\Totem;
|
||||||
use pocketmine\nbt\NBT;
|
use pocketmine\nbt\NBT;
|
||||||
use pocketmine\nbt\tag\ByteArrayTag;
|
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
use pocketmine\nbt\tag\IntTag;
|
use pocketmine\nbt\tag\IntTag;
|
||||||
use pocketmine\nbt\tag\ListTag;
|
use pocketmine\nbt\tag\ListTag;
|
||||||
@ -67,6 +66,7 @@ use function array_merge;
|
|||||||
use function array_rand;
|
use function array_rand;
|
||||||
use function array_values;
|
use function array_values;
|
||||||
use function ceil;
|
use function ceil;
|
||||||
|
use function in_array;
|
||||||
use function max;
|
use function max;
|
||||||
use function min;
|
use function min;
|
||||||
use function random_int;
|
use function random_int;
|
||||||
@ -104,18 +104,36 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
public function __construct(World $world, CompoundTag $nbt){
|
public function __construct(World $world, CompoundTag $nbt){
|
||||||
if($this->skin === null){
|
if($this->skin === null){
|
||||||
$skinTag = $nbt->getCompoundTag("Skin");
|
$skinTag = $nbt->getCompoundTag("Skin");
|
||||||
if($skinTag === null or !self::isValidSkin($skinTag->hasTag("Data", ByteArrayTag::class) ?
|
if($skinTag === null){
|
||||||
$skinTag->getByteArray("Data") :
|
|
||||||
$skinTag->getString("Data", "")
|
|
||||||
)){
|
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
$this->skin = self::deserializeSkinNBT($skinTag); //this throws if the skin is invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
parent::__construct($world, $nbt);
|
parent::__construct($world, $nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param CompoundTag $skinTag
|
||||||
|
*
|
||||||
|
* @return Skin
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
protected static function deserializeSkinNBT(CompoundTag $skinTag) : Skin{
|
||||||
|
$skin = new Skin(
|
||||||
|
$skinTag->getString("Name"),
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*
|
||||||
* Checks the length of a supplied skin bitmap and returns whether the length is valid.
|
* Checks the length of a supplied skin bitmap and returns whether the length is valid.
|
||||||
*
|
*
|
||||||
* @param string $skin
|
* @param string $skin
|
||||||
@ -123,7 +141,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public static function isValidSkin(string $skin) : bool{
|
public static function isValidSkin(string $skin) : bool{
|
||||||
return strlen($skin) === 64 * 64 * 4 or strlen($skin) === 64 * 32 * 4 or strlen($skin) === 128 * 128 * 4;
|
return in_array(strlen($skin), Skin::ACCEPTED_SKIN_SIZES, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,10 +173,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
* @param Skin $skin
|
* @param Skin $skin
|
||||||
*/
|
*/
|
||||||
public function setSkin(Skin $skin) : void{
|
public function setSkin(Skin $skin) : void{
|
||||||
if(!$skin->isValid()){
|
$skin->validate();
|
||||||
throw new \InvalidStateException("Specified skin is not valid, must be 8KiB or 16KiB");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->skin = $skin;
|
$this->skin = $skin;
|
||||||
$this->skin->debloatGeometryData();
|
$this->skin->debloatGeometryData();
|
||||||
}
|
}
|
||||||
@ -590,17 +605,6 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
$this->setNameTag($nbt->getString("NameTag"));
|
$this->setNameTag($nbt->getString("NameTag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$skin = $nbt->getCompoundTag("Skin");
|
|
||||||
if($skin !== null){
|
|
||||||
$this->setSkin(new Skin(
|
|
||||||
$skin->getString("Name"),
|
|
||||||
$skin->hasTag("Data", StringTag::class) ? $skin->getString("Data") : $skin->getByteArray("Data"), //old data (this used to be saved as a StringTag in older versions of PM)
|
|
||||||
$skin->getByteArray("CapeData", ""),
|
|
||||||
$skin->getString("GeometryName", ""),
|
|
||||||
$skin->getByteArray("GeometryData", "")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->uuid = UUID::fromData((string) $this->getId(), $this->skin->getSkinData(), $this->getNameTag());
|
$this->uuid = UUID::fromData((string) $this->getId(), $this->skin->getSkinData(), $this->getNameTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,9 +853,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function sendSpawnPacket(Player $player) : void{
|
protected function sendSpawnPacket(Player $player) : void{
|
||||||
if(!$this->skin->isValid()){
|
$this->skin->validate();
|
||||||
throw new \InvalidStateException((new \ReflectionClass($this))->getShortName() . " must have a valid skin set");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!($this instanceof Player)){
|
if(!($this instanceof Player)){
|
||||||
/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
|
/* we don't use Server->updatePlayerListData() because that uses batches, which could cause race conditions in async compression mode */
|
||||||
|
@ -23,11 +23,18 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace pocketmine\entity;
|
namespace pocketmine\entity;
|
||||||
|
|
||||||
|
use function implode;
|
||||||
|
use function in_array;
|
||||||
use function json_decode;
|
use function json_decode;
|
||||||
use function json_encode;
|
use function json_encode;
|
||||||
use function strlen;
|
use function strlen;
|
||||||
|
|
||||||
class Skin{
|
class Skin{
|
||||||
|
public const ACCEPTED_SKIN_SIZES = [
|
||||||
|
64 * 32 * 4,
|
||||||
|
64 * 64 * 4,
|
||||||
|
128 * 128 * 4
|
||||||
|
];
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $skinId;
|
private $skinId;
|
||||||
@ -48,12 +55,34 @@ class Skin{
|
|||||||
$this->geometryData = $geometryData;
|
$this->geometryData = $geometryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function isValid() : bool{
|
public function isValid() : bool{
|
||||||
return (
|
try{
|
||||||
$this->skinId !== "" and
|
$this->validate();
|
||||||
(($s = strlen($this->skinData)) === 16384 or $s === 8192 or $s === 65536) and
|
return true;
|
||||||
($this->capeData === "" or strlen($this->capeData) === 8192)
|
}catch(\InvalidArgumentException $e){
|
||||||
);
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function validate() : void{
|
||||||
|
if($this->skinId === ""){
|
||||||
|
throw new \InvalidArgumentException("Skin ID must not be empty");
|
||||||
|
}
|
||||||
|
$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 !== "" and strlen($this->capeData) !== 8192){
|
||||||
|
throw new \InvalidArgumentException("Invalid cape data size " . strlen($this->capeData) . " bytes (must be exactly 8192 bytes)");
|
||||||
|
}
|
||||||
|
//TODO: validate geometry
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,10 +70,7 @@ class PlayerChangeSkinEvent extends PlayerEvent implements Cancellable{
|
|||||||
* @throws \InvalidArgumentException if the specified skin is not valid
|
* @throws \InvalidArgumentException if the specified skin is not valid
|
||||||
*/
|
*/
|
||||||
public function setNewSkin(Skin $skin) : void{
|
public function setNewSkin(Skin $skin) : void{
|
||||||
if(!$skin->isValid()){
|
$skin->validate();
|
||||||
throw new \InvalidArgumentException("Skin format is invalid");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->newSkin = $skin;
|
$this->newSkin = $skin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user