mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-01 07:39:57 +00:00
Merge branch 'stable' into next-minor
This commit is contained in:
commit
dbaf851be7
@ -1 +1 @@
|
|||||||
Subproject commit 83085714483a0cf3a13b4fa780bd14b153c5c36b
|
Subproject commit 61e20ab9e39fb64514c1031e5ae6320b8129e14c
|
@ -1 +1 @@
|
|||||||
Subproject commit 63e0092d623d13e47f9083b3d65fdf431933a471
|
Subproject commit da363df5f15e3a92817683b695455eced04992ba
|
@ -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
19
composer.lock
generated
@ -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",
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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){
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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{
|
||||||
|
36
src/pocketmine/item/MaybeConsumable.php
Normal file
36
src/pocketmine/item/MaybeConsumable.php
Normal 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;
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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){
|
||||||
|
@ -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{
|
||||||
|
@ -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)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
tests/phpunit/network/mcpe/protocol/DataPacketTest.php
Normal file
42
tests/phpunit/network/mcpe/protocol/DataPacketTest.php
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
34
tests/phpunit/network/mcpe/protocol/TestPacket.php
Normal file
34
tests/phpunit/network/mcpe/protocol/TestPacket.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user