diff --git a/build/php b/build/php index 830857144..61e20ab9e 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit 83085714483a0cf3a13b4fa780bd14b153c5c36b +Subproject commit 61e20ab9e39fb64514c1031e5ae6320b8129e14c diff --git a/build/preprocessor b/build/preprocessor index 63e0092d6..da363df5f 160000 --- a/build/preprocessor +++ b/build/preprocessor @@ -1 +1 @@ -Subproject commit 63e0092d623d13e47f9083b3d65fdf431933a471 +Subproject commit da363df5f15e3a92817683b695455eced04992ba diff --git a/changelogs/3.11.md b/changelogs/3.11.md index d6efefbd3..3e471a43c 100644 --- a/changelogs/3.11.md +++ b/changelogs/3.11.md @@ -66,3 +66,16 @@ Plugin developers should **only** update their required API to this version if y - `ClientboundMapItemDataPacket` now uses `MapDecoration` objects for decorations instead of associative arrays. - Updated Composer dependencies to get bug fixes in `pocketmine/nbt` and other libraries. - Packages `pocketmine/classloader` and `pocketmine/log` are now required; these provide classes previously part of `pocketmine/spl`. This change has no effect on API compatibility. + +# 3.11.6 +- Core code, tests and build scripts are now analyzed using `phpstan-strict-rules` and `phpstan-phpunit` rules. +- Added more PHPStan-specific type annotations to improve static analysis. +- Fixed more incorrect PHPDoc types. +- Added a workaround for player movement not working since 1.14.30. +- Fixed lava and water buckets being edible since 1.13. +- `AutoUpdater` is now created before any plugins are loaded. +- Fixed trees not generating below y=2 in custom generators. +- Fixed crash when opening a chest improperly unpaired from its pair (destroyed, setBlock(), unloaded, etc.). +- `ThreadManager` is now lazily initialized. +- Removed raw NBT storage from `Item` internals. The following methods are now deprecated: + - `Item::setCompoundTag()` diff --git a/composer.lock b/composer.lock index 41e2834c3..7dd115e86 100644 --- a/composer.lock +++ b/composer.lock @@ -386,7 +386,7 @@ "source": { "type": "git", "url": "https://gitlab.irstea.fr/pole-is/tools/phpunit-shim.git", - "reference": "39b6155954d6caec1110a9e78582c4816ab247bc" + "reference": "8ec63f895972681271191821a36f9081c236b993" }, "require": { "ext-dom": "*", @@ -408,6 +408,11 @@ "phpunit" ], "type": "library", + "autoload": { + "exclude-from-classmap": [ + "phpunit" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -427,20 +432,20 @@ "testing", "xunit" ], - "time": "2020-01-09T03:20:20+00:00" + "time": "2020-01-23T13:39:47+00:00" }, { "name": "phpstan/phpstan", - "version": "0.12.9", + "version": "0.12.11", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32" + "reference": "ca5f2b7cf81c6d8fba74f9576970399c5817e03b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/297cb2458a96ea96d5e9d6ef38f1b7305c071f32", - "reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ca5f2b7cf81c6d8fba74f9576970399c5817e03b", + "reference": "ca5f2b7cf81c6d8fba74f9576970399c5817e03b", "shasum": "" }, "require": { @@ -466,7 +471,7 @@ "MIT" ], "description": "PHPStan - PHP Static Analysis Tool", - "time": "2020-02-04T22:30:27+00:00" + "time": "2020-02-16T14:00:29+00:00" }, { "name": "phpstan/phpstan-phpunit", diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 142aab122..4f9b42179 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -81,6 +81,7 @@ use pocketmine\item\Durable; use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\enchantment\MeleeWeaponEnchantment; use pocketmine\item\Item; +use pocketmine\item\MaybeConsumable; use pocketmine\item\WritableBook; use pocketmine\item\WrittenBook; use pocketmine\lang\TextContainer; @@ -2450,7 +2451,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR: if($this->isUsingItem()){ $slot = $this->inventory->getItemInHand(); - if($slot instanceof Consumable){ + if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){ $ev = new PlayerItemConsumeEvent($this, $slot); if($this->hasItemCooldown($slot)){ $ev->setCancelled(); diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index f06205889..6e4ec054f 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -31,6 +31,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){ const _VERSION_INFO_INCLUDED = true; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.11.6"; +const BASE_VERSION = "3.11.7"; const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; diff --git a/src/pocketmine/block/Crops.php b/src/pocketmine/block/Crops.php index 32852472b..eaebfe0a2 100644 --- a/src/pocketmine/block/Crops.php +++ b/src/pocketmine/block/Crops.php @@ -55,7 +55,7 @@ abstract class Crops extends Flowable{ $this->getLevel()->setBlock($this, $ev->getNewState(), true, true); } - $item->count--; + $item->pop(); return true; } diff --git a/src/pocketmine/block/Grass.php b/src/pocketmine/block/Grass.php index e7ccfa040..afd4b54ad 100644 --- a/src/pocketmine/block/Grass.php +++ b/src/pocketmine/block/Grass.php @@ -99,7 +99,7 @@ class Grass extends Solid{ public function onActivate(Item $item, Player $player = null) : bool{ if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ - $item->count--; + $item->pop(); TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2); return true; diff --git a/src/pocketmine/block/Sapling.php b/src/pocketmine/block/Sapling.php index 43737f80c..682f2251a 100644 --- a/src/pocketmine/block/Sapling.php +++ b/src/pocketmine/block/Sapling.php @@ -72,7 +72,7 @@ class Sapling extends Flowable{ //TODO: change log type Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); - $item->count--; + $item->pop(); return true; } diff --git a/src/pocketmine/block/Sugarcane.php b/src/pocketmine/block/Sugarcane.php index 884715e93..ad4e95aff 100644 --- a/src/pocketmine/block/Sugarcane.php +++ b/src/pocketmine/block/Sugarcane.php @@ -62,7 +62,7 @@ class Sugarcane extends Flowable{ $this->getLevel()->setBlock($this, $this, true); } - $item->count--; + $item->pop(); return true; } diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 9049024f6..05bf75f4b 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -38,6 +38,7 @@ use pocketmine\item\Durable; use pocketmine\item\enchantment\Enchantment; use pocketmine\item\FoodSource; use pocketmine\item\Item; +use pocketmine\item\MaybeConsumable; use pocketmine\item\Totem; use pocketmine\level\Level; use pocketmine\nbt\NBT; @@ -50,6 +51,7 @@ use pocketmine\network\mcpe\protocol\ActorEventPacket; use pocketmine\network\mcpe\protocol\AddPlayerPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; +use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket; use pocketmine\network\mcpe\protocol\types\PlayerListEntry; @@ -295,6 +297,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } public function consumeObject(Consumable $consumable) : bool{ + if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){ + return false; + } + if($consumable instanceof FoodSource){ if($consumable->requiresHunger() and !$this->isHungry()){ return false; @@ -819,6 +825,23 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } } + public function broadcastMovement(bool $teleport = false) : void{ + //TODO: workaround 1.14.30 bug: MoveActor(Absolute|Delta)Packet don't work on players anymore :( + $pk = new MovePlayerPacket(); + $pk->entityRuntimeId = $this->getId(); + $pk->position = $this->getOffsetPosition($this); + $pk->yaw = $this->yaw; + $pk->pitch = $this->pitch; + $pk->headYaw = $this->yaw; + $pk->mode = $teleport ? MovePlayerPacket::MODE_TELEPORT : MovePlayerPacket::MODE_NORMAL; + + //we can't assume that everyone who is using our chunk wants to see this movement, + //because this human might be a player who shouldn't be receiving his own movement. + //this didn't matter when we were able to use MoveActorPacket because + //the client just ignored MoveActor for itself, but it doesn't ignore MovePlayer for itself. + $this->server->broadcastPacket($this->hasSpawned, $pk); + } + public function close() : void{ if(!$this->closed){ if($this->inventory !== null){ diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 5de84968b..9d9f0e1b8 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -37,6 +37,7 @@ use pocketmine\item\Consumable; use pocketmine\item\Durable; use pocketmine\item\enchantment\Enchantment; use pocketmine\item\Item; +use pocketmine\item\MaybeConsumable; use pocketmine\math\Vector3; use pocketmine\math\VoxelRayTrace; use pocketmine\nbt\tag\ByteTag; @@ -111,7 +112,7 @@ abstract class Living extends Entity implements Damageable{ $this->setHealth($health); - /** @var CompoundTag[]|ListTag|null */ + /** @var CompoundTag[]|ListTag|null $activeEffectsTag */ $activeEffectsTag = $this->namedtag->getListTag("ActiveEffects"); if($activeEffectsTag !== null){ foreach($activeEffectsTag as $e){ @@ -359,6 +360,10 @@ abstract class Living extends Entity implements Damageable{ * etc. */ public function consumeObject(Consumable $consumable) : bool{ + if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){ + return false; + } + foreach($consumable->getAdditionalEffects() as $effect){ $this->addEffect($effect); } diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index f4c7f80ac..94933099d 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -246,18 +246,18 @@ abstract class BaseInventory implements Inventory{ } public function canAddItem(Item $item) : bool{ - $item = clone $item; + $count = $item->getCount(); for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ $slot = $this->getItem($i); if($item->equals($slot)){ if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){ - $item->setCount($item->getCount() - $diff); + $count -= $diff; } }elseif($slot->isNull()){ - $item->setCount($item->getCount() - $this->getMaxStackSize()); + $count -= $this->getMaxStackSize(); } - if($item->getCount() <= 0){ + if($count <= 0){ return true; } } diff --git a/src/pocketmine/item/Bucket.php b/src/pocketmine/item/Bucket.php index 3c7834350..717a4b5c6 100644 --- a/src/pocketmine/item/Bucket.php +++ b/src/pocketmine/item/Bucket.php @@ -33,7 +33,7 @@ use pocketmine\event\player\PlayerBucketFillEvent; use pocketmine\math\Vector3; use pocketmine\Player; -class Bucket extends Item implements Consumable{ +class Bucket extends Item implements MaybeConsumable{ public function __construct(int $meta = 0){ parent::__construct(self::BUCKET, $meta, "Bucket"); } diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index da1759252..5edd234e8 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -565,7 +565,7 @@ class Item implements ItemIds, \JsonSerializable{ /** * Pops an item from the stack and returns it, decreasing the stack count of this item stack by one. * - * @return $this + * @return static A clone of this itemstack containing the amount of items that were removed from this stack. * @throws \InvalidArgumentException if trying to pop more items than are on the stack */ public function pop(int $count = 1) : Item{ diff --git a/src/pocketmine/item/MaybeConsumable.php b/src/pocketmine/item/MaybeConsumable.php new file mode 100644 index 000000000..2bd380e14 --- /dev/null +++ b/src/pocketmine/item/MaybeConsumable.php @@ -0,0 +1,36 @@ +getLevel(), $nbt); if($entity instanceof Entity){ - --$this->count; + $this->pop(); $entity->spawnToAll(); $player->getLevel()->broadcastLevelEvent($blockReplace->add(0.5, 0.5, 0.5), LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE); //item frame and painting have the same sound diff --git a/src/pocketmine/item/ProjectileItem.php b/src/pocketmine/item/ProjectileItem.php index 79a437811..f0f0860cc 100644 --- a/src/pocketmine/item/ProjectileItem.php +++ b/src/pocketmine/item/ProjectileItem.php @@ -54,7 +54,7 @@ abstract class ProjectileItem extends Item{ $projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce())); } - $this->count--; + $this->pop(); if($projectile instanceof Projectile){ $projectileEv = new ProjectileLaunchEvent($projectile); diff --git a/src/pocketmine/item/SpawnEgg.php b/src/pocketmine/item/SpawnEgg.php index 175ddc58a..92ac5d4a1 100644 --- a/src/pocketmine/item/SpawnEgg.php +++ b/src/pocketmine/item/SpawnEgg.php @@ -44,7 +44,7 @@ class SpawnEgg extends Item{ $entity = Entity::createEntity($this->meta, $player->getLevel(), $nbt); if($entity instanceof Entity){ - --$this->count; + $this->pop(); $entity->spawnToAll(); return true; } diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index b1d11c6cb..c883a222f 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -264,7 +264,7 @@ class Level implements ChunkManager, Metadatable{ private $chunksPerTick; /** @var bool */ private $clearChunksOnTick; - /** @var \SplFixedArray */ + /** @var \SplFixedArray */ private $randomTickBlocks; /** @var LevelTimings */ @@ -1042,7 +1042,7 @@ class Level implements ChunkManager, Metadatable{ } /** - * @phpstan-return \SplFixedArray + * @phpstan-return \SplFixedArray */ public function getRandomTickedBlocks() : \SplFixedArray{ return $this->randomTickBlocks; diff --git a/src/pocketmine/level/format/Chunk.php b/src/pocketmine/level/format/Chunk.php index 1d7e294ac..c5989a934 100644 --- a/src/pocketmine/level/format/Chunk.php +++ b/src/pocketmine/level/format/Chunk.php @@ -548,6 +548,7 @@ class Chunk{ */ public function setLightPopulated(bool $value = true){ $this->lightPopulated = $value; + $this->hasChanged = true; } public function isPopulated() : bool{ @@ -559,6 +560,7 @@ class Chunk{ */ public function setPopulated(bool $value = true){ $this->terrainPopulated = $value; + $this->hasChanged = true; } public function isGenerated() : bool{ @@ -570,6 +572,7 @@ class Chunk{ */ public function setGenerated(bool $value = true){ $this->terrainGenerated = $value; + $this->hasChanged = true; } /** diff --git a/src/pocketmine/level/generator/PopulationTask.php b/src/pocketmine/level/generator/PopulationTask.php index 95019457a..8ff8d86e9 100644 --- a/src/pocketmine/level/generator/PopulationTask.php +++ b/src/pocketmine/level/generator/PopulationTask.php @@ -98,23 +98,27 @@ class PopulationTask extends AsyncTask{ $manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk); if(!$chunk->isGenerated()){ $generator->generateChunk($chunk->getX(), $chunk->getZ()); + $chunk = $manager->getChunk($chunk->getX(), $chunk->getZ()); $chunk->setGenerated(); } - foreach($chunks as $c){ + foreach($chunks as $i => $c){ $manager->setChunk($c->getX(), $c->getZ(), $c); if(!$c->isGenerated()){ $generator->generateChunk($c->getX(), $c->getZ()); - $c->setGenerated(); + $chunks[$i] = $manager->getChunk($c->getX(), $c->getZ()); + $chunks[$i]->setGenerated(); } } $generator->populateChunk($chunk->getX(), $chunk->getZ()); + $chunk = $manager->getChunk($chunk->getX(), $chunk->getZ()); + $chunk->setPopulated(); $chunk->recalculateHeightMap(); $chunk->populateSkyLight(); $chunk->setLightPopulated(); - $chunk->setPopulated(); + $this->chunk = $chunk->fastSerialize(); foreach($chunks as $i => $c){ diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index 0e8831e6b..c2890bfa2 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -100,7 +100,7 @@ class NetworkBinaryStream extends BinaryStream{ $capeId = $this->getString(); $fullSkinId = $this->getString(); - return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId); + return new SkinData($skinId, $skinResourcePatch, $skinData, $animations, $capeData, $geometryData, $animationData, $premium, $persona, $capeOnClassic, $capeId, $fullSkinId); } /** @@ -123,9 +123,7 @@ class NetworkBinaryStream extends BinaryStream{ $this->putBool($skin->isPersona()); $this->putBool($skin->isPersonaCapeOnClassic()); $this->putString($skin->getCapeId()); - - //this has to be unique or the client will do stupid things - $this->putString(UUID::fromRandom()->toString()); //full skin ID + $this->putString($skin->getFullSkinId()); } private function getSkinImage() : SkinImage{ diff --git a/src/pocketmine/network/mcpe/protocol/DataPacket.php b/src/pocketmine/network/mcpe/protocol/DataPacket.php index 7f8aa2fb7..0bd10be43 100644 --- a/src/pocketmine/network/mcpe/protocol/DataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/DataPacket.php @@ -39,6 +39,12 @@ abstract class DataPacket extends NetworkBinaryStream{ public const NETWORK_ID = 0; + public const PID_MASK = 0x3ff; //10 bits + + private const SUBCLIENT_ID_MASK = 0x03; //2 bits + private const SENDER_SUBCLIENT_ID_SHIFT = 10; + private const RECIPIENT_SUBCLIENT_ID_SHIFT = 12; + /** @var bool */ public $isEncoded = false; /** @var CachedEncapsulatedPacket|null */ @@ -92,10 +98,13 @@ abstract class DataPacket extends NetworkBinaryStream{ * @throws \UnexpectedValueException */ protected function decodeHeader(){ - $pid = $this->getUnsignedVarInt(); + $header = $this->getUnsignedVarInt(); + $pid = $header & self::PID_MASK; if($pid !== static::NETWORK_ID){ throw new \UnexpectedValueException("Expected " . static::NETWORK_ID . " for packet ID, got $pid"); } + $this->senderSubId = ($header >> self::SENDER_SUBCLIENT_ID_SHIFT) & self::SUBCLIENT_ID_MASK; + $this->recipientSubId = ($header >> self::RECIPIENT_SUBCLIENT_ID_SHIFT) & self::SUBCLIENT_ID_MASK; } /** @@ -123,7 +132,11 @@ abstract class DataPacket extends NetworkBinaryStream{ * @return void */ protected function encodeHeader(){ - $this->putUnsignedVarInt(static::NETWORK_ID); + $this->putUnsignedVarInt( + static::NETWORK_ID | + ($this->senderSubId << self::SENDER_SUBCLIENT_ID_SHIFT) | + ($this->recipientSubId << self::RECIPIENT_SUBCLIENT_ID_SHIFT) + ); } /** diff --git a/src/pocketmine/network/mcpe/protocol/PacketPool.php b/src/pocketmine/network/mcpe/protocol/PacketPool.php index 3c8e3610e..d6383dded 100644 --- a/src/pocketmine/network/mcpe/protocol/PacketPool.php +++ b/src/pocketmine/network/mcpe/protocol/PacketPool.php @@ -196,7 +196,7 @@ class PacketPool{ */ public static function getPacket(string $buffer) : DataPacket{ $offset = 0; - $pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset)); + $pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset) & DataPacket::PID_MASK); $pk->setBuffer($buffer, $offset); return $pk; diff --git a/src/pocketmine/network/mcpe/protocol/UpdateTradePacket.php b/src/pocketmine/network/mcpe/protocol/UpdateTradePacket.php index 8bf01c70d..1a0b3be60 100644 --- a/src/pocketmine/network/mcpe/protocol/UpdateTradePacket.php +++ b/src/pocketmine/network/mcpe/protocol/UpdateTradePacket.php @@ -48,9 +48,9 @@ class UpdateTradePacket extends DataPacket{ /** @var string */ public $displayName; /** @var bool */ - public $isWilling; - /** @var bool */ public $isV2Trading; + /** @var bool */ + public $isWilling; /** @var string */ public $offers; @@ -62,8 +62,8 @@ class UpdateTradePacket extends DataPacket{ $this->traderEid = $this->getEntityUniqueId(); $this->playerEid = $this->getEntityUniqueId(); $this->displayName = $this->getString(); - $this->isWilling = $this->getBool(); $this->isV2Trading = $this->getBool(); + $this->isWilling = $this->getBool(); $this->offers = $this->getRemaining(); } @@ -75,8 +75,8 @@ class UpdateTradePacket extends DataPacket{ $this->putEntityUniqueId($this->traderEid); $this->putEntityUniqueId($this->playerEid); $this->putString($this->displayName); - $this->putBool($this->isWilling); $this->putBool($this->isV2Trading); + $this->putBool($this->isWilling); $this->put($this->offers); } diff --git a/src/pocketmine/network/mcpe/protocol/types/SkinData.php b/src/pocketmine/network/mcpe/protocol/types/SkinData.php index 6ff6dfda8..e7ca29312 100644 --- a/src/pocketmine/network/mcpe/protocol/types/SkinData.php +++ b/src/pocketmine/network/mcpe/protocol/types/SkinData.php @@ -23,6 +23,8 @@ declare(strict_types=1); namespace pocketmine\network\mcpe\protocol\types; +use pocketmine\utils\UUID; + class SkinData{ /** @var string */ @@ -47,11 +49,13 @@ class SkinData{ private $personaCapeOnClassic; /** @var string */ private $capeId; + /** @var string */ + private $fullSkinId; /** * @param SkinAnimation[] $animations */ - 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 $personaCapeOnClassic = false, string $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 $personaCapeOnClassic = false, string $capeId = "", ?string $fullSkinId = null){ $this->skinId = $skinId; $this->resourcePatch = $resourcePatch; $this->skinImage = $skinImage; @@ -63,6 +67,8 @@ class SkinData{ $this->persona = $persona; $this->personaCapeOnClassic = $personaCapeOnClassic; $this->capeId = $capeId; + //this has to be unique or the client will do stupid things + $this->fullSkinId = $fullSkinId ?? UUID::fromRandom()->toString(); } public function getSkinId() : string{ @@ -112,4 +118,7 @@ class SkinData{ return $this->capeId; } + public function getFullSkinId() : string{ + return $this->fullSkinId; + } } diff --git a/tests/phpunit/network/mcpe/protocol/DataPacketTest.php b/tests/phpunit/network/mcpe/protocol/DataPacketTest.php new file mode 100644 index 000000000..99cd0b4f2 --- /dev/null +++ b/tests/phpunit/network/mcpe/protocol/DataPacketTest.php @@ -0,0 +1,42 @@ +senderSubId = 3; + $pk->recipientSubId = 2; + $pk->encode(); + + $pk2 = new TestPacket(); + $pk2->setBuffer($pk->getBuffer()); + $pk2->decode(); + self::assertSame($pk2->senderSubId, 3); + self::assertSame($pk2->recipientSubId, 2); + } +} diff --git a/tests/phpunit/network/mcpe/protocol/TestPacket.php b/tests/phpunit/network/mcpe/protocol/TestPacket.php new file mode 100644 index 000000000..b38e04ec4 --- /dev/null +++ b/tests/phpunit/network/mcpe/protocol/TestPacket.php @@ -0,0 +1,34 @@ +