Merge branch 'stable' into next-minor

This commit is contained in:
Dylan K. Taylor 2020-02-27 16:51:06 +00:00
commit dbaf851be7
29 changed files with 228 additions and 42 deletions

@ -1 +1 @@
Subproject commit 83085714483a0cf3a13b4fa780bd14b153c5c36b Subproject commit 61e20ab9e39fb64514c1031e5ae6320b8129e14c

@ -1 +1 @@
Subproject commit 63e0092d623d13e47f9083b3d65fdf431933a471 Subproject commit da363df5f15e3a92817683b695455eced04992ba

View File

@ -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. - `ClientboundMapItemDataPacket` now uses `MapDecoration` objects for decorations instead of associative arrays.
- Updated Composer dependencies to get bug fixes in `pocketmine/nbt` and other libraries. - 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. - 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()`

19
composer.lock generated
View File

@ -386,7 +386,7 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://gitlab.irstea.fr/pole-is/tools/phpunit-shim.git", "url": "https://gitlab.irstea.fr/pole-is/tools/phpunit-shim.git",
"reference": "39b6155954d6caec1110a9e78582c4816ab247bc" "reference": "8ec63f895972681271191821a36f9081c236b993"
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
@ -408,6 +408,11 @@
"phpunit" "phpunit"
], ],
"type": "library", "type": "library",
"autoload": {
"exclude-from-classmap": [
"phpunit"
]
},
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"license": [ "license": [
"BSD-3-Clause" "BSD-3-Clause"
@ -427,20 +432,20 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2020-01-09T03:20:20+00:00" "time": "2020-01-23T13:39:47+00:00"
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "0.12.9", "version": "0.12.11",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32" "reference": "ca5f2b7cf81c6d8fba74f9576970399c5817e03b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/297cb2458a96ea96d5e9d6ef38f1b7305c071f32", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ca5f2b7cf81c6d8fba74f9576970399c5817e03b",
"reference": "297cb2458a96ea96d5e9d6ef38f1b7305c071f32", "reference": "ca5f2b7cf81c6d8fba74f9576970399c5817e03b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -466,7 +471,7 @@
"MIT" "MIT"
], ],
"description": "PHPStan - PHP Static Analysis Tool", "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", "name": "phpstan/phpstan-phpunit",

View File

@ -81,6 +81,7 @@ use pocketmine\item\Durable;
use pocketmine\item\enchantment\EnchantmentInstance; use pocketmine\item\enchantment\EnchantmentInstance;
use pocketmine\item\enchantment\MeleeWeaponEnchantment; use pocketmine\item\enchantment\MeleeWeaponEnchantment;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\item\WritableBook; use pocketmine\item\WritableBook;
use pocketmine\item\WrittenBook; use pocketmine\item\WrittenBook;
use pocketmine\lang\TextContainer; use pocketmine\lang\TextContainer;
@ -2450,7 +2451,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR: case InventoryTransactionPacket::USE_ITEM_ACTION_CLICK_AIR:
if($this->isUsingItem()){ if($this->isUsingItem()){
$slot = $this->inventory->getItemInHand(); $slot = $this->inventory->getItemInHand();
if($slot instanceof Consumable){ if($slot instanceof Consumable and !($slot instanceof MaybeConsumable and !$slot->canBeConsumed())){
$ev = new PlayerItemConsumeEvent($this, $slot); $ev = new PlayerItemConsumeEvent($this, $slot);
if($this->hasItemCooldown($slot)){ if($this->hasItemCooldown($slot)){
$ev->setCancelled(); $ev->setCancelled();

View File

@ -31,6 +31,6 @@ if(defined('pocketmine\_VERSION_INFO_INCLUDED')){
const _VERSION_INFO_INCLUDED = true; const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP"; const NAME = "PocketMine-MP";
const BASE_VERSION = "3.11.6"; const BASE_VERSION = "3.11.7";
const IS_DEVELOPMENT_BUILD = true; const IS_DEVELOPMENT_BUILD = true;
const BUILD_NUMBER = 0; const BUILD_NUMBER = 0;

View File

@ -55,7 +55,7 @@ abstract class Crops extends Flowable{
$this->getLevel()->setBlock($this, $ev->getNewState(), true, true); $this->getLevel()->setBlock($this, $ev->getNewState(), true, true);
} }
$item->count--; $item->pop();
return true; return true;
} }

View File

@ -99,7 +99,7 @@ class Grass extends Solid{
public function onActivate(Item $item, Player $player = null) : bool{ public function onActivate(Item $item, Player $player = null) : bool{
if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){ if($item->getId() === Item::DYE and $item->getDamage() === 0x0F){
$item->count--; $item->pop();
TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2); TallGrassObject::growGrass($this->getLevel(), $this, new Random(mt_rand()), 8, 2);
return true; return true;

View File

@ -72,7 +72,7 @@ class Sapling extends Flowable{
//TODO: change log type //TODO: change log type
Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant()); Tree::growTree($this->getLevel(), $this->x, $this->y, $this->z, new Random(mt_rand()), $this->getVariant());
$item->count--; $item->pop();
return true; return true;
} }

View File

@ -62,7 +62,7 @@ class Sugarcane extends Flowable{
$this->getLevel()->setBlock($this, $this, true); $this->getLevel()->setBlock($this, $this, true);
} }
$item->count--; $item->pop();
return true; return true;
} }

View File

@ -38,6 +38,7 @@ use pocketmine\item\Durable;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\FoodSource; use pocketmine\item\FoodSource;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\item\Totem; use pocketmine\item\Totem;
use pocketmine\level\Level; use pocketmine\level\Level;
use pocketmine\nbt\NBT; 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\AddPlayerPacket;
use pocketmine\network\mcpe\protocol\LevelEventPacket; use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket;
use pocketmine\network\mcpe\protocol\MovePlayerPacket;
use pocketmine\network\mcpe\protocol\PlayerListPacket; use pocketmine\network\mcpe\protocol\PlayerListPacket;
use pocketmine\network\mcpe\protocol\PlayerSkinPacket; use pocketmine\network\mcpe\protocol\PlayerSkinPacket;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry; use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
@ -295,6 +297,10 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{
} }
public function consumeObject(Consumable $consumable) : bool{ public function consumeObject(Consumable $consumable) : bool{
if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){
return false;
}
if($consumable instanceof FoodSource){ if($consumable instanceof FoodSource){
if($consumable->requiresHunger() and !$this->isHungry()){ if($consumable->requiresHunger() and !$this->isHungry()){
return false; 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{ public function close() : void{
if(!$this->closed){ if(!$this->closed){
if($this->inventory !== null){ if($this->inventory !== null){

View File

@ -37,6 +37,7 @@ use pocketmine\item\Consumable;
use pocketmine\item\Durable; use pocketmine\item\Durable;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\MaybeConsumable;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\math\VoxelRayTrace; use pocketmine\math\VoxelRayTrace;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
@ -111,7 +112,7 @@ abstract class Living extends Entity implements Damageable{
$this->setHealth($health); $this->setHealth($health);
/** @var CompoundTag[]|ListTag|null */ /** @var CompoundTag[]|ListTag|null $activeEffectsTag */
$activeEffectsTag = $this->namedtag->getListTag("ActiveEffects"); $activeEffectsTag = $this->namedtag->getListTag("ActiveEffects");
if($activeEffectsTag !== null){ if($activeEffectsTag !== null){
foreach($activeEffectsTag as $e){ foreach($activeEffectsTag as $e){
@ -359,6 +360,10 @@ abstract class Living extends Entity implements Damageable{
* etc. * etc.
*/ */
public function consumeObject(Consumable $consumable) : bool{ public function consumeObject(Consumable $consumable) : bool{
if($consumable instanceof MaybeConsumable and !$consumable->canBeConsumed()){
return false;
}
foreach($consumable->getAdditionalEffects() as $effect){ foreach($consumable->getAdditionalEffects() as $effect){
$this->addEffect($effect); $this->addEffect($effect);
} }

View File

@ -246,18 +246,18 @@ abstract class BaseInventory implements Inventory{
} }
public function canAddItem(Item $item) : bool{ public function canAddItem(Item $item) : bool{
$item = clone $item; $count = $item->getCount();
for($i = 0, $size = $this->getSize(); $i < $size; ++$i){ for($i = 0, $size = $this->getSize(); $i < $size; ++$i){
$slot = $this->getItem($i); $slot = $this->getItem($i);
if($item->equals($slot)){ if($item->equals($slot)){
if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){ if(($diff = $slot->getMaxStackSize() - $slot->getCount()) > 0){
$item->setCount($item->getCount() - $diff); $count -= $diff;
} }
}elseif($slot->isNull()){ }elseif($slot->isNull()){
$item->setCount($item->getCount() - $this->getMaxStackSize()); $count -= $this->getMaxStackSize();
} }
if($item->getCount() <= 0){ if($count <= 0){
return true; return true;
} }
} }

View File

@ -33,7 +33,7 @@ use pocketmine\event\player\PlayerBucketFillEvent;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\Player; use pocketmine\Player;
class Bucket extends Item implements Consumable{ class Bucket extends Item implements MaybeConsumable{
public function __construct(int $meta = 0){ public function __construct(int $meta = 0){
parent::__construct(self::BUCKET, $meta, "Bucket"); parent::__construct(self::BUCKET, $meta, "Bucket");
} }

View File

@ -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. * 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 * @throws \InvalidArgumentException if trying to pop more items than are on the stack
*/ */
public function pop(int $count = 1) : Item{ public function pop(int $count = 1) : Item{

View File

@ -0,0 +1,36 @@
<?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\item;
/**
* Items which are sometimes (but not always) consumable should implement this interface.
*
* Note: If implementing custom items, consider making separate items instead of using this.
* This interface serves as a workaround for the consumability of buckets and shouldn't
* really be used for anything else.
*/
interface MaybeConsumable extends Consumable{
public function canBeConsumed() : bool;
}

View File

@ -96,7 +96,7 @@ class PaintingItem extends Item{
$entity = Entity::createEntity("Painting", $blockReplace->getLevel(), $nbt); $entity = Entity::createEntity("Painting", $blockReplace->getLevel(), $nbt);
if($entity instanceof Entity){ if($entity instanceof Entity){
--$this->count; $this->pop();
$entity->spawnToAll(); $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 $player->getLevel()->broadcastLevelEvent($blockReplace->add(0.5, 0.5, 0.5), LevelEventPacket::EVENT_SOUND_ITEMFRAME_PLACE); //item frame and painting have the same sound

View File

@ -54,7 +54,7 @@ abstract class ProjectileItem extends Item{
$projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce())); $projectile->setMotion($projectile->getMotion()->multiply($this->getThrowForce()));
} }
$this->count--; $this->pop();
if($projectile instanceof Projectile){ if($projectile instanceof Projectile){
$projectileEv = new ProjectileLaunchEvent($projectile); $projectileEv = new ProjectileLaunchEvent($projectile);

View File

@ -44,7 +44,7 @@ class SpawnEgg extends Item{
$entity = Entity::createEntity($this->meta, $player->getLevel(), $nbt); $entity = Entity::createEntity($this->meta, $player->getLevel(), $nbt);
if($entity instanceof Entity){ if($entity instanceof Entity){
--$this->count; $this->pop();
$entity->spawnToAll(); $entity->spawnToAll();
return true; return true;
} }

View File

@ -264,7 +264,7 @@ class Level implements ChunkManager, Metadatable{
private $chunksPerTick; private $chunksPerTick;
/** @var bool */ /** @var bool */
private $clearChunksOnTick; private $clearChunksOnTick;
/** @var \SplFixedArray<Block> */ /** @var \SplFixedArray<Block|null> */
private $randomTickBlocks; private $randomTickBlocks;
/** @var LevelTimings */ /** @var LevelTimings */
@ -1042,7 +1042,7 @@ class Level implements ChunkManager, Metadatable{
} }
/** /**
* @phpstan-return \SplFixedArray<Block> * @phpstan-return \SplFixedArray<Block|null>
*/ */
public function getRandomTickedBlocks() : \SplFixedArray{ public function getRandomTickedBlocks() : \SplFixedArray{
return $this->randomTickBlocks; return $this->randomTickBlocks;

View File

@ -548,6 +548,7 @@ class Chunk{
*/ */
public function setLightPopulated(bool $value = true){ public function setLightPopulated(bool $value = true){
$this->lightPopulated = $value; $this->lightPopulated = $value;
$this->hasChanged = true;
} }
public function isPopulated() : bool{ public function isPopulated() : bool{
@ -559,6 +560,7 @@ class Chunk{
*/ */
public function setPopulated(bool $value = true){ public function setPopulated(bool $value = true){
$this->terrainPopulated = $value; $this->terrainPopulated = $value;
$this->hasChanged = true;
} }
public function isGenerated() : bool{ public function isGenerated() : bool{
@ -570,6 +572,7 @@ class Chunk{
*/ */
public function setGenerated(bool $value = true){ public function setGenerated(bool $value = true){
$this->terrainGenerated = $value; $this->terrainGenerated = $value;
$this->hasChanged = true;
} }
/** /**

View File

@ -98,23 +98,27 @@ class PopulationTask extends AsyncTask{
$manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk); $manager->setChunk($chunk->getX(), $chunk->getZ(), $chunk);
if(!$chunk->isGenerated()){ if(!$chunk->isGenerated()){
$generator->generateChunk($chunk->getX(), $chunk->getZ()); $generator->generateChunk($chunk->getX(), $chunk->getZ());
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
$chunk->setGenerated(); $chunk->setGenerated();
} }
foreach($chunks as $c){ foreach($chunks as $i => $c){
$manager->setChunk($c->getX(), $c->getZ(), $c); $manager->setChunk($c->getX(), $c->getZ(), $c);
if(!$c->isGenerated()){ if(!$c->isGenerated()){
$generator->generateChunk($c->getX(), $c->getZ()); $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()); $generator->populateChunk($chunk->getX(), $chunk->getZ());
$chunk = $manager->getChunk($chunk->getX(), $chunk->getZ());
$chunk->setPopulated();
$chunk->recalculateHeightMap(); $chunk->recalculateHeightMap();
$chunk->populateSkyLight(); $chunk->populateSkyLight();
$chunk->setLightPopulated(); $chunk->setLightPopulated();
$chunk->setPopulated();
$this->chunk = $chunk->fastSerialize(); $this->chunk = $chunk->fastSerialize();
foreach($chunks as $i => $c){ foreach($chunks as $i => $c){

View File

@ -100,7 +100,7 @@ class NetworkBinaryStream extends BinaryStream{
$capeId = $this->getString(); $capeId = $this->getString();
$fullSkinId = $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->isPersona());
$this->putBool($skin->isPersonaCapeOnClassic()); $this->putBool($skin->isPersonaCapeOnClassic());
$this->putString($skin->getCapeId()); $this->putString($skin->getCapeId());
$this->putString($skin->getFullSkinId());
//this has to be unique or the client will do stupid things
$this->putString(UUID::fromRandom()->toString()); //full skin ID
} }
private function getSkinImage() : SkinImage{ private function getSkinImage() : SkinImage{

View File

@ -39,6 +39,12 @@ abstract class DataPacket extends NetworkBinaryStream{
public const NETWORK_ID = 0; 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 */ /** @var bool */
public $isEncoded = false; public $isEncoded = false;
/** @var CachedEncapsulatedPacket|null */ /** @var CachedEncapsulatedPacket|null */
@ -92,10 +98,13 @@ abstract class DataPacket extends NetworkBinaryStream{
* @throws \UnexpectedValueException * @throws \UnexpectedValueException
*/ */
protected function decodeHeader(){ protected function decodeHeader(){
$pid = $this->getUnsignedVarInt(); $header = $this->getUnsignedVarInt();
$pid = $header & self::PID_MASK;
if($pid !== static::NETWORK_ID){ if($pid !== static::NETWORK_ID){
throw new \UnexpectedValueException("Expected " . static::NETWORK_ID . " for packet ID, got $pid"); 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 * @return void
*/ */
protected function encodeHeader(){ 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)
);
} }
/** /**

View File

@ -196,7 +196,7 @@ class PacketPool{
*/ */
public static function getPacket(string $buffer) : DataPacket{ public static function getPacket(string $buffer) : DataPacket{
$offset = 0; $offset = 0;
$pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset)); $pk = static::getPacketById(Binary::readUnsignedVarInt($buffer, $offset) & DataPacket::PID_MASK);
$pk->setBuffer($buffer, $offset); $pk->setBuffer($buffer, $offset);
return $pk; return $pk;

View File

@ -48,9 +48,9 @@ class UpdateTradePacket extends DataPacket{
/** @var string */ /** @var string */
public $displayName; public $displayName;
/** @var bool */ /** @var bool */
public $isWilling;
/** @var bool */
public $isV2Trading; public $isV2Trading;
/** @var bool */
public $isWilling;
/** @var string */ /** @var string */
public $offers; public $offers;
@ -62,8 +62,8 @@ class UpdateTradePacket extends DataPacket{
$this->traderEid = $this->getEntityUniqueId(); $this->traderEid = $this->getEntityUniqueId();
$this->playerEid = $this->getEntityUniqueId(); $this->playerEid = $this->getEntityUniqueId();
$this->displayName = $this->getString(); $this->displayName = $this->getString();
$this->isWilling = $this->getBool();
$this->isV2Trading = $this->getBool(); $this->isV2Trading = $this->getBool();
$this->isWilling = $this->getBool();
$this->offers = $this->getRemaining(); $this->offers = $this->getRemaining();
} }
@ -75,8 +75,8 @@ class UpdateTradePacket extends DataPacket{
$this->putEntityUniqueId($this->traderEid); $this->putEntityUniqueId($this->traderEid);
$this->putEntityUniqueId($this->playerEid); $this->putEntityUniqueId($this->playerEid);
$this->putString($this->displayName); $this->putString($this->displayName);
$this->putBool($this->isWilling);
$this->putBool($this->isV2Trading); $this->putBool($this->isV2Trading);
$this->putBool($this->isWilling);
$this->put($this->offers); $this->put($this->offers);
} }

View File

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types; namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\utils\UUID;
class SkinData{ class SkinData{
/** @var string */ /** @var string */
@ -47,11 +49,13 @@ class SkinData{
private $personaCapeOnClassic; private $personaCapeOnClassic;
/** @var string */ /** @var string */
private $capeId; private $capeId;
/** @var string */
private $fullSkinId;
/** /**
* @param SkinAnimation[] $animations * @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->skinId = $skinId;
$this->resourcePatch = $resourcePatch; $this->resourcePatch = $resourcePatch;
$this->skinImage = $skinImage; $this->skinImage = $skinImage;
@ -63,6 +67,8 @@ class SkinData{
$this->persona = $persona; $this->persona = $persona;
$this->personaCapeOnClassic = $personaCapeOnClassic; $this->personaCapeOnClassic = $personaCapeOnClassic;
$this->capeId = $capeId; $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{ public function getSkinId() : string{
@ -112,4 +118,7 @@ class SkinData{
return $this->capeId; return $this->capeId;
} }
public function getFullSkinId() : string{
return $this->fullSkinId;
}
} }

View File

@ -0,0 +1,42 @@
<?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;
use PHPUnit\Framework\TestCase;
class DataPacketTest extends TestCase{
public function testHeaderFidelity() : void{
$pk = new TestPacket();
$pk->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);
}
}

View File

@ -0,0 +1,34 @@
<?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;
use pocketmine\network\mcpe\NetworkSession;
class TestPacket extends DataPacket{
public const NETWORK_ID = 1023;
public function handle(NetworkSession $handler) : bool{
return false;
}
}