Merge branch 'stable' into next-minor

This commit is contained in:
Dylan K. Taylor 2019-12-12 13:07:02 +00:00
commit 1a467420e3
37 changed files with 165 additions and 48 deletions

14
changelogs/3.11.md Normal file
View File

@ -0,0 +1,14 @@
**For Minecraft: Bedrock Edition 1.14.0**
### Note about API versions
Plugins which don't touch the protocol and compatible with any previous 3.x.y version will also run on these releases and do not need API bumps.
Plugin developers should **only** update their required API to this version if you need the changes in this build.
**WARNING: If your plugin uses the protocol, you're not shielded by API change constraints.** You should consider using the `mcpe-protocol` directive in `plugin.yml` as a constraint if you do.
# 3.11.0
- Added support for Minecraft: Bedrock Edition 1.14.0
- Removed compatibility with 1.13.0
# 3.11.1
- Fixed blocks with incorrect properties when placed or interacted with.

View File

@ -1,12 +1,14 @@
includes:
- tests/phpstan/configs/debug-const-checks.neon
- tests/phpstan/configs/gc-hacks.neon
- tests/phpstan/configs/optional-com-dotnet.neon
- tests/phpstan/configs/optional-leveldb.neon
- tests/phpstan/configs/phpstan-bugs.neon
- tests/phpstan/configs/pthreads-bugs.neon
- tests/phpstan/configs/runtime-type-checks.neon
parameters:
level: 3
level: 4
autoload_files:
- tests/phpstan/bootstrap.php
- src/pocketmine/PocketMine.php

View File

@ -464,11 +464,11 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
}
public function getFirstPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("firstPlayed", 0, true) : null;
return $this->namedtag->getLong("firstPlayed", 0, true);
}
public function getLastPlayed(){
return $this->namedtag instanceof CompoundTag ? $this->namedtag->getLong("lastPlayed", 0, true) : null;
return $this->namedtag->getLong("lastPlayed", 0, true);
}
public function hasPlayedBefore() : bool{
@ -1921,7 +1921,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$animations = [];
foreach($packet->clientData["AnimatedImageData"] as $animation){
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], $animation["Image"]), $animation["Type"], $animation["Frames"]);
$animations[] = new SkinAnimation(new SkinImage($animation["ImageHeight"], $animation["ImageWidth"], base64_decode($animation["Image"], true)), $animation["Type"], $animation["Frames"]);
}
$skinData = new SkinData(
@ -1931,7 +1931,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{
$animations,
new SkinImage($packet->clientData["CapeImageHeight"], $packet->clientData["CapeImageWidth"], base64_decode($packet->clientData["CapeData"] ?? "")),
base64_decode($packet->clientData["SkinGeometryData"] ?? ""),
base64_decode($packet->clientData["AnimationData"] ?? ""),
base64_decode($packet->clientData["SkinAnimationData"] ?? ""),
$packet->clientData["PremiumSkin"] ?? false,
$packet->clientData["PersonaSkin"] ?? false,
$packet->clientData["CapeOnClassicSkin"] ?? false,

View File

@ -115,6 +115,7 @@ use function asort;
use function assert;
use function base64_encode;
use function class_exists;
use function cli_set_process_title;
use function count;
use function define;
use function explode;
@ -129,7 +130,6 @@ use function getmypid;
use function getopt;
use function gettype;
use function implode;
use function ini_get;
use function ini_set;
use function is_array;
use function is_bool;

View File

@ -30,6 +30,6 @@ const _VERSION_INFO_INCLUDED = true;
const NAME = "PocketMine-MP";
const BASE_VERSION = "3.10.2";
const BASE_VERSION = "3.11.2";
const IS_DEVELOPMENT_BUILD = true;
const BUILD_NUMBER = 0;

View File

@ -34,7 +34,6 @@ use pocketmine\level\Position;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\IntTag;
use function abs;
use function floor;
use function get_class;
class FallingBlock extends Entity{

View File

@ -46,7 +46,7 @@ abstract class BaseInventory implements Inventory{
protected $name;
/** @var string */
protected $title;
/** @var \SplFixedArray|Item[] */
/** @var \SplFixedArray|(Item|null)[] */
protected $slots;
/** @var Player[] */
protected $viewers = [];

View File

@ -2442,7 +2442,7 @@ class Level implements ChunkManager, Metadatable{
* @param int $x
* @param int $z
*
* @return Chunk[]
* @return (Chunk|null)[]
*/
public function getAdjacentChunks(int $x, int $z) : array{
$result = [];

View File

@ -71,7 +71,7 @@ interface LevelProvider{
* @param string $name
* @param int $seed
* @param string $generator
* @param array[] $options
* @param array $options
*/
public static function generate(string $path, string $name, int $seed, string $generator, array $options = []);

View File

@ -33,7 +33,12 @@ use pocketmine\level\generator\GeneratorManager;
use pocketmine\level\Level;
use pocketmine\level\LevelException;
use pocketmine\nbt\LittleEndianNBTStream;
use pocketmine\nbt\tag\{ByteTag, CompoundTag, FloatTag, IntTag, LongTag, StringTag};
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\nbt\tag\LongTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\utils\Binary;
use pocketmine\utils\BinaryStream;

View File

@ -56,11 +56,9 @@ class PopulationTask extends AsyncTask{
}
public function onRun(){
/** @var SimpleChunkManager $manager */
$manager = $this->getFromThreadStore("generation.level{$this->levelId}.manager");
/** @var Generator $generator */
$generator = $this->getFromThreadStore("generation.level{$this->levelId}.generator");
if($manager === null or $generator === null){
if(!($manager instanceof SimpleChunkManager) or !($generator instanceof Generator)){
$this->state = false;
return;
}

View File

@ -38,9 +38,9 @@ use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\IntTag;
use pocketmine\network\mcpe\protocol\types\CommandOriginData;
use pocketmine\network\mcpe\protocol\types\EntityLink;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\SkinImage;
use pocketmine\network\mcpe\protocol\types\SkinAnimation;
use pocketmine\network\mcpe\protocol\types\StructureSettings;
use pocketmine\utils\BinaryStream;
use pocketmine\utils\UUID;

View File

@ -67,7 +67,6 @@ use pocketmine\network\mcpe\protocol\ShowCreditsPacket;
use pocketmine\network\mcpe\protocol\SpawnExperienceOrbPacket;
use pocketmine\network\mcpe\protocol\TextPacket;
use pocketmine\network\mcpe\protocol\types\SkinAdapterSingleton;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\Player;
use pocketmine\Server;
use pocketmine\timings\Timings;

View File

@ -37,6 +37,7 @@ use function openssl_verify;
use function ord;
use function str_split;
use function strlen;
use function strtr;
use function time;
use function wordwrap;
use const OPENSSL_ALGO_SHA384;

View File

@ -26,7 +26,6 @@ namespace pocketmine\network\mcpe\protocol;
#include <rules/DataPacket.h>
use pocketmine\network\mcpe\NetworkSession;
use function base64_decode;
use function file_get_contents;
class AvailableActorIdentifiersPacket extends DataPacket{

View File

@ -31,6 +31,7 @@ use pocketmine\network\mcpe\protocol\types\CommandEnum;
use pocketmine\network\mcpe\protocol\types\CommandEnumConstraint;
use pocketmine\network\mcpe\protocol\types\CommandParameter;
use pocketmine\utils\BinaryDataException;
use function array_search;
use function count;
use function dechex;

View File

@ -27,7 +27,6 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\SkinData;
use pocketmine\network\mcpe\protocol\types\PlayerListEntry;
use function count;

View File

@ -39,15 +39,15 @@ interface ProtocolInfo{
/**
* Actual Minecraft: PE protocol version
*/
public const CURRENT_PROTOCOL = 388;
public const CURRENT_PROTOCOL = 389;
/**
* Current Minecraft PE version reported by the server. This is usually the earliest currently supported version.
*/
public const MINECRAFT_VERSION = 'v1.13.0';
public const MINECRAFT_VERSION = 'v1.14.0';
/**
* Version number sent to clients in ping responses.
*/
public const MINECRAFT_VERSION_NETWORK = '1.13.0';
public const MINECRAFT_VERSION_NETWORK = '1.14.0';
public const LOGIN_PACKET = 0x01;
public const PLAY_STATUS_PACKET = 0x02;

View File

@ -28,7 +28,6 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\network\mcpe\NetworkSession;
use function strlen;
class ResourcePackChunkDataPacket extends DataPacket{
public const NETWORK_ID = ProtocolInfo::RESOURCE_PACK_CHUNK_DATA_PACKET;

View File

@ -28,9 +28,7 @@ namespace pocketmine\network\mcpe\protocol;
use pocketmine\math\Vector3;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\network\mcpe\NetworkBinaryStream;
use pocketmine\network\mcpe\NetworkSession;
use pocketmine\network\mcpe\protocol\types\PlayerPermissions;

View File

@ -27,14 +27,16 @@ use pocketmine\entity\Skin;
use function is_array;
use function is_string;
use function json_decode;
use function json_encode;
use function random_bytes;
use function str_repeat;
class LegacySkinAdapter implements SkinAdapter{
public function toSkinData(Skin $skin) : SkinData{
$capeData = new SkinImage(32, 64, $skin->getCapeData());
if($skin->getCapeData() === ""){
$capeData = new SkinImage(0, 0, $skin->getCapeData());
}
$capeData = $skin->getCapeData();
$capeImage = $capeData === "" ? new SkinImage(0, 0, "") : new SkinImage(32, 64, $capeData);
$geometryName = $skin->getGeometryName();
if($geometryName === ""){
$geometryName = "geometry.humanoid.custom";
@ -43,13 +45,18 @@ class LegacySkinAdapter implements SkinAdapter{
$skin->getSkinId(),
json_encode(["geometry" => ["default" => $geometryName]]),
SkinImage::fromLegacy($skin->getSkinData()), [],
$capeData,
$capeImage,
$skin->getGeometryData()
);
}
public function fromSkinData(SkinData $data) : Skin{
$capeData = $data->getCapeImage()->getData();
if($data->isPersona()){
return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048));
}
$capeData = $data->isPersonaCapeOnClassic() ? "" : $data->getCapeImage()->getData();
$geometryName = "";
$resourcePatch = json_decode($data->getResourcePatch(), true);
if(is_array($resourcePatch["geometry"]) && is_string($resourcePatch["geometry"]["default"])){
@ -57,11 +64,7 @@ class LegacySkinAdapter implements SkinAdapter{
}else{
//TODO: Kick for invalid skin
}
if($data->isPersona()){
return new Skin("Standard_Custom", str_repeat(random_bytes(3) . "\xff", 2048));
}elseif($data->isPersonaCapeOnClassic()){
$capeData = "";
}
return new Skin($data->getSkinId(), $data->getSkinImage()->getData(), $capeData, $geometryName, $data->getGeometryData());
}
}

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use pocketmine\entity\Skin;
use pocketmine\utils\UUID;
class PlayerListEntry{

View File

@ -28,8 +28,6 @@ use pocketmine\nbt\NBT;
use pocketmine\nbt\NetworkLittleEndianNBTStream;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\utils\BinaryDataException;
use function file_get_contents;
use function getmypid;
use function json_decode;

View File

@ -25,7 +25,7 @@ namespace pocketmine\network\mcpe\protocol\types;
/**
* Accessor for SkinAdapter
*/
*/
class SkinAdapterSingleton{
/** @var SkinAdapter|null */
private static $skinAdapter = null;

View File

@ -22,6 +22,7 @@
declare(strict_types=1);
namespace pocketmine\network\mcpe\protocol\types;
use function strlen;
class SkinImage{
@ -33,6 +34,9 @@ class SkinImage{
private $data;
public function __construct(int $height, int $width, string $data){
if(($expected = $height * $width * 4) !== ($actual = strlen($data))){
throw new \InvalidArgumentException("Data should be exactly $expected bytes, got $actual bytes");
}
$this->height = $height;
$this->width = $width;
$this->data = $data;

View File

@ -136,10 +136,10 @@ class BanEntry{
/**
* @param string $date
*
* @return \DateTime|null
* @return \DateTime
* @throws \RuntimeException
*/
private static function parseDate(string $date) : ?\DateTime{
private static function parseDate(string $date) : \DateTime{
$datetime = \DateTime::createFromFormat(self::$format, $date);
if(!($datetime instanceof \DateTime)){
throw new \RuntimeException("Error parsing date for BanEntry: " . implode(", ", \DateTime::getLastErrors()["errors"]));

View File

@ -38,6 +38,7 @@ use function strlen;
use function strtoupper;
use function substr;
use function version_compare;
use function yaml_parse;
class PluginDescription{
private $map;

View File

@ -40,6 +40,7 @@ use pocketmine\timings\TimingsHandler;
use pocketmine\utils\Utils;
use function array_intersect;
use function array_map;
use function array_merge;
use function array_pad;
use function class_exists;
use function count;

View File

@ -34,6 +34,7 @@ use function filesize;
use function fopen;
use function fread;
use function fseek;
use function gettype;
use function hash_file;
use function implode;

@ -1 +1 @@
Subproject commit a38b42788883fa2094f67874f15594044be1ac4d
Subproject commit cc132c80dd9d76a44e4b0a360e85e8e28bba8956

View File

@ -31,6 +31,8 @@ use pocketmine\tile\Tile;
use function dechex;
abstract class Timings{
/** @var bool */
private static $initialized = false;
/** @var TimingsHandler */
public static $fullTickTimer;
@ -104,9 +106,10 @@ abstract class Timings{
public static $pluginTaskTimingMap = [];
public static function init(){
if(self::$serverTickTimer instanceof TimingsHandler){
if(self::$initialized){
return;
}
self::$initialized = true;
self::$fullTickTimer = new TimingsHandler("Full Server Tick");
self::$serverTickTimer = new TimingsHandler("** Full Server Tick", self::$fullTickTimer);

View File

@ -168,7 +168,7 @@ class TimingsHandler{
public function stopTiming(){
if(self::$enabled){
if(--$this->timingDepth !== 0 or $this->start === 0){
if(--$this->timingDepth !== 0 or $this->start == 0){
return;
}

View File

@ -57,6 +57,7 @@ use function is_object;
use function is_readable;
use function is_string;
use function json_decode;
use function ltrim;
use function ob_end_clean;
use function ob_get_contents;
use function ob_start;
@ -68,6 +69,7 @@ use function preg_match;
use function preg_match_all;
use function preg_replace;
use function rmdir;
use function rtrim;
use function scandir;
use function sha1;
use function spl_object_hash;
@ -78,6 +80,7 @@ use function stripos;
use function strlen;
use function strpos;
use function strtolower;
use function strtr;
use function substr;
use function sys_get_temp_dir;
use function trim;

View File

@ -0,0 +1,21 @@
parameters:
ignoreErrors:
-
message: "#^If condition is always true\\.$#"
count: 1
path: ../../../src/pocketmine/Server.php
-
message: "#^Ternary operator condition is always true\\.$#"
count: 1
path: ../../../src/pocketmine/Server.php
-
message: "#^If condition is always false\\.$#"
count: 1
path: ../../../src/pocketmine/updater/AutoUpdater.php
-
message: "#^Negated boolean expression is always false\\.$#"
count: 1
path: ../../../src/pocketmine/updater/AutoUpdater.php

View File

@ -27,7 +27,45 @@ parameters:
path: ../../../src/pocketmine/MemoryManager.php
-
message: "#^Array \\(array\\) does not accept key int\\.$#"
message: "#^Comparison operation \"\\>\\=\" between 0 and 2 is always false\\.$#"
count: 1
path: ../../../src/pocketmine/plugin/PluginDescription.php
path: ../../../src/pocketmine/block/Liquid.php
-
#adjacentSources comparison FP
message: "#^If condition is always false\\.$#"
count: 1
path: ../../../src/pocketmine/block/Liquid.php
-
#$class::NETWORK_ID false positive
message: "#^Strict comparison using \\!\\=\\= between \\-1 and \\-1 will always evaluate to false\\.$#"
count: 1
path: ../../../src/pocketmine/entity/Entity.php
-
message: "#^Call to function assert\\(\\) with false and 'unknown hit type' will always evaluate to false\\.$#"
count: 1
path: ../../../src/pocketmine/entity/projectile/Projectile.php
-
message: "#^Strict comparison using \\=\\=\\= between int\\<min, 3\\> and 4 will always evaluate to false\\.$#"
count: 1
path: ../../../src/pocketmine/level/Level.php
-
message: "#^Instanceof between int and PharFileInfo will always evaluate to false\\.$#"
count: 1
path: ../../../src/pocketmine/plugin/PharPluginLoader.php
-
#ReflectionFunction::getClosureThis() should be nullable
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 1
path: ../../../src/pocketmine/utils/Utils.php
-
#ReflectionFunction::getClosureScopeClass() should be nullable
message: "#^Unreachable statement \\- code above always terminates\\.$#"
count: 1
path: ../../../src/pocketmine/utils/Utils.php

View File

@ -0,0 +1,31 @@
parameters:
ignoreErrors:
-
#::add() / ::remove() thread parameter
message: "#^If condition is always true\\.$#"
count: 2
path: ../../../src/pocketmine/ThreadManager.php
-
#::get() tags parameter
message: "#^If condition is always false\\.$#"
count: 1
path: ../../../src/pocketmine/item/ItemFactory.php
-
#::get() tags parameter
message: "#^Strict comparison using \\!\\=\\= between null and null will always evaluate to false\\.$#"
count: 1
path: ../../../src/pocketmine/item/ItemFactory.php
-
#::get() tags parameter
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 1
path: ../../../src/pocketmine/item/ItemFactory.php
-
#->sendBlocks() blocks parameter
message: "#^Else branch is unreachable because ternary operator condition is always true\\.$#"
count: 2
path: ../../../src/pocketmine/level/Level.php

View File

@ -21,7 +21,7 @@ if [ $? -ne 0 ]; then
exit 1
fi
[ ! -f phpstan.phar ] && echo "Downloading PHPStan..." && curl -sSLO https://github.com/phpstan/phpstan/releases/download/0.12.0/phpstan.phar
[ ! -f phpstan.phar ] && echo "Downloading PHPStan..." && curl -sSLO https://github.com/phpstan/phpstan/releases/download/0.12.2/phpstan.phar
"$PHP_BINARY" phpstan.phar analyze --no-progress --memory-limit=2G || exit 1
echo "PHPStan scan succeeded"