From 42d835782153df40d193fd7053f3ca46f1aea24b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Nov 2019 11:58:29 +0000 Subject: [PATCH 01/29] AvailableCommandsPacket: fixed missing decoded overloads with 0 arguments these should be listed even if they have 0 arguments --- src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 9af852bba..86088c8dc 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -227,6 +227,7 @@ class AvailableCommandsPacket extends DataPacket{ $retval->aliases = $enums[$this->getLInt()] ?? null; for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){ + $retval->overloads[$overloadIndex] = []; for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){ $parameter = new CommandParameter(); $parameter->paramName = $this->getString(); From 6d109bfc6f0ee7a12ffbee6d699cdcfdfe559cc0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 30 Nov 2019 21:15:37 +0000 Subject: [PATCH 02/29] CraftingDataPacket: fixed not retaining cleanRecipes during decode --- src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php b/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php index 27f59e73b..bb5f7cd8f 100644 --- a/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/CraftingDataPacket.php @@ -140,7 +140,7 @@ class CraftingDataPacket extends DataPacket{ } $this->decodedEntries[] = $entry; } - $this->getBool(); //cleanRecipes + $this->cleanRecipes = $this->getBool(); } private static function writeEntry($entry, NetworkBinaryStream $stream, int $pos){ From 3968f85c82f29beeb116832d4139d27d0a28ef51 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 08:54:48 +0000 Subject: [PATCH 03/29] sync composer dependencies --- composer.lock | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/composer.lock b/composer.lock index a3eea84d6..26b239330 100644 --- a/composer.lock +++ b/composer.lock @@ -160,16 +160,16 @@ }, { "name": "pocketmine/nbt", - "version": "0.2.11", + "version": "0.2.12", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "78784b93632c51f0fad0719b2d6ffe072529db6d" + "reference": "b5777265329753b74dd40bb105eedabeefb98724" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/78784b93632c51f0fad0719b2d6ffe072529db6d", - "reference": "78784b93632c51f0fad0719b2d6ffe072529db6d", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/b5777265329753b74dd40bb105eedabeefb98724", + "reference": "b5777265329753b74dd40bb105eedabeefb98724", "shasum": "" }, "require": { @@ -194,10 +194,10 @@ ], "description": "PHP library for working with Named Binary Tags", "support": { - "source": "https://github.com/pmmp/NBT/tree/0.2.11", + "source": "https://github.com/pmmp/NBT/tree/0.2", "issues": "https://github.com/pmmp/NBT/issues" }, - "time": "2019-10-21T14:50:43+00:00" + "time": "2019-12-01T08:20:26+00:00" }, { "name": "pocketmine/raklib", @@ -276,23 +276,20 @@ }, { "name": "pocketmine/spl", - "version": "0.3.2", + "version": "0.3.3", "source": { "type": "git", "url": "https://github.com/pmmp/SPL.git", - "reference": "7fd53857cd000491ba69e8db865792a024dd2c49" + "reference": "94d4df142fe837ba836e9348dd00209e4bdcc307" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/SPL/zipball/7fd53857cd000491ba69e8db865792a024dd2c49", - "reference": "7fd53857cd000491ba69e8db865792a024dd2c49", + "url": "https://api.github.com/repos/pmmp/SPL/zipball/94d4df142fe837ba836e9348dd00209e4bdcc307", + "reference": "94d4df142fe837ba836e9348dd00209e4bdcc307", "shasum": "" }, "type": "library", "autoload": { - "exclude-from-classmap": [ - "stubs" - ], "classmap": [ "./" ] @@ -302,9 +299,10 @@ ], "description": "Standard library files required by PocketMine-MP and related projects", "support": { - "source": "https://github.com/pmmp/SPL/tree/master" + "source": "https://github.com/pmmp/SPL/tree/0.3.3", + "issues": "https://github.com/pmmp/SPL/issues" }, - "time": "2018-08-12T15:17:39+00:00" + "time": "2019-10-28T11:41:20+00:00" } ], "packages-dev": [], From 47a959dace95eafe79212a444e3f865475c6ee8e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 09:29:22 +0000 Subject: [PATCH 04/29] block: fix some possible crashes when plugins overwrite tile classes in bad ways phpstan was complaining on level 2, and it's not wrong to ... --- src/pocketmine/block/BurningFurnace.php | 3 +++ src/pocketmine/block/Chest.php | 3 +++ src/pocketmine/block/ItemFrame.php | 3 +++ 3 files changed, 9 insertions(+) diff --git a/src/pocketmine/block/BurningFurnace.php b/src/pocketmine/block/BurningFurnace.php index 01bbd6779..c189f5b65 100644 --- a/src/pocketmine/block/BurningFurnace.php +++ b/src/pocketmine/block/BurningFurnace.php @@ -80,6 +80,9 @@ class BurningFurnace extends Solid{ $furnace = $this->getLevel()->getTile($this); if(!($furnace instanceof TileFurnace)){ $furnace = Tile::createTile(Tile::FURNACE, $this->getLevel(), TileFurnace::createNBT($this)); + if(!($furnace instanceof TileFurnace)){ + return true; + } } if(!$furnace->canOpenWith($item->getCustomName())){ diff --git a/src/pocketmine/block/Chest.php b/src/pocketmine/block/Chest.php index b11809ef2..a9cadbb1b 100644 --- a/src/pocketmine/block/Chest.php +++ b/src/pocketmine/block/Chest.php @@ -109,6 +109,9 @@ class Chest extends Transparent{ $chest = $t; }else{ $chest = Tile::createTile(Tile::CHEST, $this->getLevel(), TileChest::createNBT($this)); + if(!($chest instanceof TileChest)){ + return true; + } } if( diff --git a/src/pocketmine/block/ItemFrame.php b/src/pocketmine/block/ItemFrame.php index 6038e0a55..6644c682b 100644 --- a/src/pocketmine/block/ItemFrame.php +++ b/src/pocketmine/block/ItemFrame.php @@ -47,6 +47,9 @@ class ItemFrame extends Flowable{ $tile = $this->level->getTile($this); if(!($tile instanceof TileItemFrame)){ $tile = Tile::createTile(Tile::ITEM_FRAME, $this->getLevel(), TileItemFrame::createNBT($this)); + if(!($tile instanceof TileItemFrame)){ + return true; + } } if($tile->hasItem()){ From ecbf3e9722c2f1657cedefe4e0c2b7aa7baba3cd Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 09:33:12 +0000 Subject: [PATCH 05/29] GamemodeCommand: fix CommandSender assignment causing troubles for type inference on static analyzers this would never crash, but in strongly typed code it would be a compile failure. --- src/pocketmine/command/defaults/GamemodeCommand.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/command/defaults/GamemodeCommand.php b/src/pocketmine/command/defaults/GamemodeCommand.php index 063993aee..6070d7866 100644 --- a/src/pocketmine/command/defaults/GamemodeCommand.php +++ b/src/pocketmine/command/defaults/GamemodeCommand.php @@ -60,7 +60,6 @@ class GamemodeCommand extends VanillaCommand{ return true; } - $target = $sender; if(isset($args[1])){ $target = $sender->getServer()->getPlayer($args[1]); if($target === null){ @@ -68,7 +67,9 @@ class GamemodeCommand extends VanillaCommand{ return true; } - }elseif(!($sender instanceof Player)){ + }elseif($sender instanceof Player){ + $target = $sender; + }else{ throw new InvalidCommandSyntaxException(); } From a4a6d3e09451023972e5c87ea5bd26c563c8d49b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 18:08:25 +0000 Subject: [PATCH 06/29] PlayerCreationEvent: fixed illegal doc comment types --- src/pocketmine/event/player/PlayerCreationEvent.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pocketmine/event/player/PlayerCreationEvent.php b/src/pocketmine/event/player/PlayerCreationEvent.php index a67be8792..5102da454 100644 --- a/src/pocketmine/event/player/PlayerCreationEvent.php +++ b/src/pocketmine/event/player/PlayerCreationEvent.php @@ -46,8 +46,8 @@ class PlayerCreationEvent extends Event{ /** * @param SourceInterface $interface - * @param Player::class $baseClass - * @param Player::class $playerClass + * @param string $baseClass + * @param string $playerClass * @param string $address * @param int $port */ @@ -91,14 +91,14 @@ class PlayerCreationEvent extends Event{ } /** - * @return Player::class + * @return string */ public function getBaseClass(){ return $this->baseClass; } /** - * @param Player::class $class + * @param string $class */ public function setBaseClass($class){ if(!is_a($class, $this->baseClass, true)){ @@ -109,14 +109,14 @@ class PlayerCreationEvent extends Event{ } /** - * @return Player::class + * @return string */ public function getPlayerClass(){ return $this->playerClass; } /** - * @param Player::class $class + * @param string $class */ public function setPlayerClass($class){ if(!is_a($class, $this->baseClass, true)){ From 163ed225f211cc5b1805a8e1168a2177bae110f5 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 18:41:02 +0000 Subject: [PATCH 07/29] NetworkBinaryStream: fixed crash when non-compound root tag is provided for itemstack --- src/pocketmine/network/mcpe/NetworkBinaryStream.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index 32a3629e9..85c6766ab 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -93,7 +93,11 @@ class NetworkBinaryStream extends BinaryStream{ if($c !== 1){ throw new \UnexpectedValueException("Unexpected NBT count $c"); } - $nbt = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512); + $decodedNBT = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512); + if(!($decodedNBT instanceof CompoundTag)){ + throw new \UnexpectedValueException("Unexpected root tag type for itemstack"); + } + $nbt = $decodedNBT; }elseif($nbtLen !== 0){ throw new \UnexpectedValueException("Unexpected fake NBT length $nbtLen"); } From 0890b5fc993c35753347ee6026955ca8cb576fa7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 19:28:05 +0000 Subject: [PATCH 08/29] AsyncPool: assert() that the unstacked task is actually an AsyncTask it's possible that it might not be if the workers were accessed directly, but that shouldn't be possible. This also silences a PHPStan warning on level 2. --- src/pocketmine/scheduler/AsyncPool.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/scheduler/AsyncPool.php b/src/pocketmine/scheduler/AsyncPool.php index 8174b230c..a5e778db5 100644 --- a/src/pocketmine/scheduler/AsyncPool.php +++ b/src/pocketmine/scheduler/AsyncPool.php @@ -263,6 +263,7 @@ class AsyncPool{ while(($task = $worker->unstack()) !== null){ //cancelRun() is not strictly necessary here, but it might be used to inform plugins of the task state //(i.e. it never executed). + assert($task instanceof AsyncTask); $task->cancelRun(); $this->removeTask($task, true); } From ea413d0882553f866dd4bdb6910656363a89cbff Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 19:32:03 +0000 Subject: [PATCH 09/29] phpstan: analyze on level 2, close #3193 --- phpstan.neon | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index eeae576fe..787f9ef6e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,7 @@ parameters: - level: 1 + level: 2 autoload_files: - tests/phpstan/bootstrap.php - src/pocketmine/PocketMine.php @@ -63,6 +63,12 @@ parameters: path: src/pocketmine/network/upnp/UPnP.php comment: "only available on Windows" + - + message: "#^Access to property \\$StaticPortMappingCollection on an unknown class COM\\.$#" + count: 4 + path: src/pocketmine/network/upnp/UPnP.php + comment: "only available on Windows" + - message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#" count: 1 @@ -122,3 +128,19 @@ parameters: - message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:getDatabase\\(\\) has invalid type LevelDB\\.$#" path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected TOKEN_VARIABLE at offset \\d+$#" + path: src/pocketmine + comment: "phpstan stupidity" + + - + message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#" + path: src/pocketmine + comment: "phpstan bug" + + - + message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#" + count: 1 + path: src/pocketmine/command/defaults/TeleportCommand.php + comment: "not actually possible, but high cost to fix warning" From 1a1e3ff63b74dcd3afb62403cf1f03e77a09d541 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 19:45:16 +0000 Subject: [PATCH 10/29] BaseInventory: fixed incorrect & redundant default value for slots field --- src/pocketmine/inventory/BaseInventory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/inventory/BaseInventory.php b/src/pocketmine/inventory/BaseInventory.php index 6f32492fc..4f64680a2 100644 --- a/src/pocketmine/inventory/BaseInventory.php +++ b/src/pocketmine/inventory/BaseInventory.php @@ -47,7 +47,7 @@ abstract class BaseInventory implements Inventory{ /** @var string */ protected $title; /** @var \SplFixedArray|Item[] */ - protected $slots = []; + protected $slots; /** @var Player[] */ protected $viewers = []; /** @var InventoryEventProcessor */ From 3226a9dc6a64e84e89589cb7c3b827408d0e3c8e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 19:52:49 +0000 Subject: [PATCH 11/29] phpstan: ignore more optional-leveldb errors --- phpstan.neon | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/phpstan.neon b/phpstan.neon index 787f9ef6e..0bd71bd95 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -128,6 +128,12 @@ parameters: - message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:getDatabase\\(\\) has invalid type LevelDB\\.$#" path: src/pocketmine/level/format/io/leveldb/LevelDB.php + - + message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:\\$db has unknown class LevelDB as its type\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + - + message: "#^Call to method (get|put|delete|close)\\(\\) on an unknown class LevelDB\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php - message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected TOKEN_VARIABLE at offset \\d+$#" From 15f8886958072243d061b0429066440060b195df Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 20:12:41 +0000 Subject: [PATCH 12/29] phpstan: separate non-PM bugs from the main neon config everything left in here is now a PM problem that needs to be looked into. --- phpstan.neon | 57 ++----------------- .../phpstan/configs/optional-com-dotnet.neon | 12 ++++ tests/phpstan/configs/optional-leveldb.neon | 30 ++++++++++ tests/phpstan/configs/phpstan-bugs.neon | 10 ++++ tests/phpstan/configs/pthreads-bugs.neon | 6 ++ 5 files changed, 63 insertions(+), 52 deletions(-) create mode 100644 tests/phpstan/configs/optional-com-dotnet.neon create mode 100644 tests/phpstan/configs/optional-leveldb.neon create mode 100644 tests/phpstan/configs/phpstan-bugs.neon create mode 100644 tests/phpstan/configs/pthreads-bugs.neon diff --git a/phpstan.neon b/phpstan.neon index 0bd71bd95..e2d3ca6d5 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,4 +1,8 @@ - +includes: + - 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 parameters: level: 2 @@ -57,28 +61,11 @@ parameters: count: 1 path: src/pocketmine/network/mcpe/protocol/StartGamePacket.php - - - message: "#^Instantiated class COM not found\\.$#" - count: 2 - path: src/pocketmine/network/upnp/UPnP.php - comment: "only available on Windows" - - - - message: "#^Access to property \\$StaticPortMappingCollection on an unknown class COM\\.$#" - count: 4 - path: src/pocketmine/network/upnp/UPnP.php - comment: "only available on Windows" - - message: "#^Constructor of class pocketmine\\\\scheduler\\\\TaskScheduler has an unused parameter \\$logger\\.$#" count: 1 path: src/pocketmine/scheduler/TaskScheduler.php - - - message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#" - path: src/pocketmine/MemoryManager.php - comment: "this isn't defined on threads (thanks pthreads)" - - message: "#^Constant pocketmine\\\\COMPOSER_AUTOLOADER_PATH not found\\.$#" path: src/pocketmine @@ -110,40 +97,6 @@ parameters: - message: "#^Constant pocketmine\\\\VERSION not found\\.$#" path: src/pocketmine - - - message: "#^Used constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - comment: "explicitly checked" - - - message: "#^Constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - comment: "explicitly checked" - - - message: "#^Instantiated class LevelDB not found\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - comment: "leveldb extension currently optional" - - - message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:createDB\\(\\) has invalid type LevelDB\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - - - message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:getDatabase\\(\\) has invalid type LevelDB\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - - - message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:\\$db has unknown class LevelDB as its type\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - - - message: "#^Call to method (get|put|delete|close)\\(\\) on an unknown class LevelDB\\.$#" - path: src/pocketmine/level/format/io/leveldb/LevelDB.php - - - - message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected TOKEN_VARIABLE at offset \\d+$#" - path: src/pocketmine - comment: "phpstan stupidity" - - - - message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#" - path: src/pocketmine - comment: "phpstan bug" - message: "#^Call to an undefined method pocketmine\\\\command\\\\CommandSender\\:\\:teleport\\(\\)\\.$#" diff --git a/tests/phpstan/configs/optional-com-dotnet.neon b/tests/phpstan/configs/optional-com-dotnet.neon new file mode 100644 index 000000000..efa2d82ab --- /dev/null +++ b/tests/phpstan/configs/optional-com-dotnet.neon @@ -0,0 +1,12 @@ +parameters: + ignoreErrors: + - + message: "#^Instantiated class COM not found\\.$#" + count: 2 + path: src/pocketmine/network/upnp/UPnP.php + + - + message: "#^Access to property \\$StaticPortMappingCollection on an unknown class COM\\.$#" + count: 4 + path: src/pocketmine/network/upnp/UPnP.php + diff --git a/tests/phpstan/configs/optional-leveldb.neon b/tests/phpstan/configs/optional-leveldb.neon new file mode 100644 index 000000000..7ad8f1e28 --- /dev/null +++ b/tests/phpstan/configs/optional-leveldb.neon @@ -0,0 +1,30 @@ +parameters: + ignoreErrors: + - + message: "#^Used constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Constant LEVELDB_ZLIB_RAW_COMPRESSION not found\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Instantiated class LevelDB not found\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:createDB\\(\\) has invalid type LevelDB\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Return typehint of method pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:getDatabase\\(\\) has invalid type LevelDB\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Property pocketmine\\\\level\\\\format\\\\io\\\\leveldb\\\\LevelDB\\:\\:\\$db has unknown class LevelDB as its type\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + + - + message: "#^Call to method (get|put|delete|close)\\(\\) on an unknown class LevelDB\\.$#" + path: src/pocketmine/level/format/io/leveldb/LevelDB.php + diff --git a/tests/phpstan/configs/phpstan-bugs.neon b/tests/phpstan/configs/phpstan-bugs.neon new file mode 100644 index 000000000..90fef5cea --- /dev/null +++ b/tests/phpstan/configs/phpstan-bugs.neon @@ -0,0 +1,10 @@ +parameters: + ignoreErrors: + - + message: "#^PHPDoc tag @param has invalid value \\(.+\\)\\: Unexpected token \"&\", expected TOKEN_VARIABLE at offset \\d+$#" + path: src/pocketmine + + - + message: "#^Default value of the parameter \\#\\d+ \\$[A-Za-z\\d_]+ \\(\\-?\\d+\\) of method .+\\(\\) is incompatible with type float\\.$#" + path: src/pocketmine + diff --git a/tests/phpstan/configs/pthreads-bugs.neon b/tests/phpstan/configs/pthreads-bugs.neon new file mode 100644 index 000000000..65979a989 --- /dev/null +++ b/tests/phpstan/configs/pthreads-bugs.neon @@ -0,0 +1,6 @@ +parameters: + ignoreErrors: + - + message: "#^Variable \\$GLOBALS in isset\\(\\) always exists and is not nullable\\.$#" + path: src/pocketmine/MemoryManager.php + From 8a7017fd6bd8943c68f677deb40c1a1a81a53a57 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 20:16:45 +0000 Subject: [PATCH 13/29] Enchantment: fixed doc comment for static enchantments field --- src/pocketmine/item/enchantment/Enchantment.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index 80831911e..58dfba841 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -94,7 +94,7 @@ class Enchantment{ public const SLOT_ELYTRA = 0x4000; public const SLOT_TRIDENT = 0x8000; - /** @var Enchantment[] */ + /** @var \SplFixedArray|Enchantment[] */ protected static $enchantments; public static function init() : void{ From 293c2710d0f54e06232f01956d820121305ced88 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 20:19:59 +0000 Subject: [PATCH 14/29] PlayerCreationEvent: fixed doc comments for baseClass and playerClass fields --- src/pocketmine/event/player/PlayerCreationEvent.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/event/player/PlayerCreationEvent.php b/src/pocketmine/event/player/PlayerCreationEvent.php index 5102da454..f79a3411d 100644 --- a/src/pocketmine/event/player/PlayerCreationEvent.php +++ b/src/pocketmine/event/player/PlayerCreationEvent.php @@ -39,9 +39,9 @@ class PlayerCreationEvent extends Event{ /** @var int */ private $port; - /** @var Player::class */ + /** @var string */ private $baseClass; - /** @var Player::class */ + /** @var string */ private $playerClass; /** From 92e1811b06903594cfaa24b8580403aa81c8b9cc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 20:36:56 +0000 Subject: [PATCH 15/29] DataPacket: fixed bad null assignment to buffer in clean() this is never expected to be null, so implicitly relies on PHP magic behaviour to convert it to string when appended. --- src/pocketmine/network/mcpe/protocol/DataPacket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/DataPacket.php b/src/pocketmine/network/mcpe/protocol/DataPacket.php index f2e60caa5..aeeeaf054 100644 --- a/src/pocketmine/network/mcpe/protocol/DataPacket.php +++ b/src/pocketmine/network/mcpe/protocol/DataPacket.php @@ -135,7 +135,7 @@ abstract class DataPacket extends NetworkBinaryStream{ abstract public function handle(NetworkSession $session) : bool; public function clean(){ - $this->buffer = null; + $this->buffer = ""; $this->isEncoded = false; $this->offset = 0; return $this; From 5caae37768b2506ee74f7342c2b45273f91c310c Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:00:49 +0000 Subject: [PATCH 16/29] Server: fixed return type doc comment for getCommandAliases() --- src/pocketmine/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 742bd2277..89d36ab58 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1444,7 +1444,7 @@ class Server{ } /** - * @return string[] + * @return string[][] */ public function getCommandAliases() : array{ $section = $this->getProperty("aliases"); From 4b65e1cbe1409d6d15f6cec0f63cc780e73ef085 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:01:57 +0000 Subject: [PATCH 17/29] Command: fix type doc comment for commandMap field --- src/pocketmine/command/Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/command/Command.php b/src/pocketmine/command/Command.php index 2f47e2029..33b8a645b 100644 --- a/src/pocketmine/command/Command.php +++ b/src/pocketmine/command/Command.php @@ -55,7 +55,7 @@ abstract class Command{ */ private $activeAliases = []; - /** @var CommandMap */ + /** @var CommandMap|null */ private $commandMap = null; /** @var string */ From 9be95bf263c9d8ab6d6520ae8b27fb06711f9b54 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:02:49 +0000 Subject: [PATCH 18/29] Block: return [] instead of null in getMetadata() (return type is non-nullable) --- src/pocketmine/block/Block.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/block/Block.php b/src/pocketmine/block/Block.php index 0ed6eb803..3fee8b260 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -763,7 +763,7 @@ class Block extends Position implements BlockIds, Metadatable{ return $this->level->getBlockMetadata()->getMetadata($this, $metadataKey); } - return null; + return []; } public function hasMetadata(string $metadataKey) : bool{ From c2afc05e7c066ffd0f5676c48e18371a9f39cc99 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:03:29 +0000 Subject: [PATCH 19/29] Entity: fix type doc comment for static knownEntities field --- src/pocketmine/entity/Entity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index fac66b10c..1496e1633 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -318,7 +318,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ public const DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK public static $entityCount = 1; - /** @var Entity[] */ + /** @var string[] */ private static $knownEntities = []; /** @var string[][] */ private static $saveNames = []; From cd778661c23b1ffbbdc4a9a0c38245552cf1a8dc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:03:57 +0000 Subject: [PATCH 20/29] Entity: fixed type doc comment for blocksAround field --- src/pocketmine/entity/Entity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 1496e1633..60b9eec39 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -460,7 +460,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ /** @var EntityDamageEvent|null */ protected $lastDamageCause = null; - /** @var Block[] */ + /** @var Block[]|null */ protected $blocksAround = []; /** @var float|null */ From 8d2e59222e9e5ff519f69975a798013ad81ff999 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:05:36 +0000 Subject: [PATCH 21/29] Entity: fixed not calculating surrounding blocks on entity creation it's unclear if this was actually causing any bugs, but if it was it would likely manifest in the form of, for example, not burning in lava. --- src/pocketmine/entity/Entity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 60b9eec39..3eb596d78 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -461,7 +461,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ protected $lastDamageCause = null; /** @var Block[]|null */ - protected $blocksAround = []; + protected $blocksAround = null; /** @var float|null */ public $lastX = null; From 25e6cb74b3fd0992c6b3764e6cc0fe5509360ffc Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:06:03 +0000 Subject: [PATCH 22/29] Squid: fixed type doc comment of swimDirection field --- src/pocketmine/entity/Squid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Squid.php b/src/pocketmine/entity/Squid.php index abce81095..950164fc0 100644 --- a/src/pocketmine/entity/Squid.php +++ b/src/pocketmine/entity/Squid.php @@ -40,7 +40,7 @@ class Squid extends WaterAnimal{ public $width = 0.95; public $height = 0.95; - /** @var Vector3 */ + /** @var Vector3|null */ public $swimDirection = null; public $swimSpeed = 0.1; From fee3c171483931a4680dcc3f4fe27f094ae6f9fb Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:06:34 +0000 Subject: [PATCH 23/29] CraftingManager: fixed type doc of craftingDataCache field --- src/pocketmine/inventory/CraftingManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/inventory/CraftingManager.php b/src/pocketmine/inventory/CraftingManager.php index 528b364a9..5944eb927 100644 --- a/src/pocketmine/inventory/CraftingManager.php +++ b/src/pocketmine/inventory/CraftingManager.php @@ -43,7 +43,7 @@ class CraftingManager{ /** @var FurnaceRecipe[] */ protected $furnaceRecipes = []; - /** @var BatchPacket */ + /** @var BatchPacket|null */ private $craftingDataCache; public function __construct(){ From 17037f5e9ca9ca1169ee5291d32ac2d4fe93f44e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:14:23 +0000 Subject: [PATCH 24/29] Chunk: clean up nonsensical code in initChunk() I have no idea why the extra check was there, or why the null assignment was used, because it doesn't make any sense. --- src/pocketmine/level/format/Chunk.php | 72 +++++++++++++-------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/src/pocketmine/level/format/Chunk.php b/src/pocketmine/level/format/Chunk.php index 8bbdefe19..5847dd0ab 100644 --- a/src/pocketmine/level/format/Chunk.php +++ b/src/pocketmine/level/format/Chunk.php @@ -694,50 +694,48 @@ class Chunk{ public function initChunk(Level $level){ if(!$this->isInit){ $changed = false; - if($this->NBTentities !== null){ - $level->timings->syncChunkLoadEntitiesTimer->startTiming(); - foreach($this->NBTentities as $nbt){ - if($nbt instanceof CompoundTag){ - if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb) - $changed = true; - continue; - } - try{ - $entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt); - if(!($entity instanceof Entity)){ - $changed = true; - continue; - } - }catch(\Throwable $t){ - $level->getServer()->getLogger()->logException($t); + $level->timings->syncChunkLoadEntitiesTimer->startTiming(); + foreach($this->NBTentities as $nbt){ + if($nbt instanceof CompoundTag){ + if(!$nbt->hasTag("id")){ //allow mixed types (because of leveldb) + $changed = true; + continue; + } + + try{ + $entity = Entity::createEntity($nbt->getTag("id")->getValue(), $level, $nbt); + if(!($entity instanceof Entity)){ $changed = true; continue; } + }catch(\Throwable $t){ + $level->getServer()->getLogger()->logException($t); + $changed = true; + continue; } } - $level->timings->syncChunkLoadEntitiesTimer->stopTiming(); - - $level->timings->syncChunkLoadTileEntitiesTimer->startTiming(); - foreach($this->NBTtiles as $nbt){ - if($nbt instanceof CompoundTag){ - if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){ - $changed = true; - continue; - } - - if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){ - $changed = true; - continue; - } - } - } - - $level->timings->syncChunkLoadTileEntitiesTimer->stopTiming(); - - $this->NBTentities = null; - $this->NBTtiles = null; } + $this->NBTentities = []; + $level->timings->syncChunkLoadEntitiesTimer->stopTiming(); + + $level->timings->syncChunkLoadTileEntitiesTimer->startTiming(); + foreach($this->NBTtiles as $nbt){ + if($nbt instanceof CompoundTag){ + if(!$nbt->hasTag(Tile::TAG_ID, StringTag::class)){ + $changed = true; + continue; + } + + if(Tile::createTile($nbt->getString(Tile::TAG_ID), $level, $nbt) === null){ + $changed = true; + continue; + } + } + } + + $this->NBTtiles = []; + $level->timings->syncChunkLoadTileEntitiesTimer->stopTiming(); $this->hasChanged = $changed; From 2b08bbc7b160d9990165ef6f0e59a06dd0b5aff4 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:18:20 +0000 Subject: [PATCH 25/29] Server: fixed type doc comment of nextTick field --- src/pocketmine/Server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 89d36ab58..a4327b337 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -227,7 +227,7 @@ class Server{ * @var int */ private $tickCounter = 0; - /** @var int */ + /** @var float */ private $nextTick = 0; /** @var float[] */ private $tickAverage = [20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20]; From dbab8b5733689dd03ce6e161bf6687ae0e7a4b29 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:21:42 +0000 Subject: [PATCH 26/29] Level: fixed type doc of tickRateTime field --- src/pocketmine/level/Level.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/level/Level.php b/src/pocketmine/level/Level.php index 0d1b50188..59754eb92 100644 --- a/src/pocketmine/level/Level.php +++ b/src/pocketmine/level/Level.php @@ -265,7 +265,7 @@ class Level implements ChunkManager, Metadatable{ /** @var LevelTimings */ public $timings; - /** @var int */ + /** @var float */ public $tickRateTime = 0; /** * @deprecated From c4a8781b5caee7b630031a7223fe9bb95d6571de Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:40:11 +0000 Subject: [PATCH 27/29] Fixed doc type inconsistencies surrounding chat broadcast handling (several problems that are all related) --- src/pocketmine/Server.php | 4 ++-- src/pocketmine/event/player/PlayerChatEvent.php | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index a4327b337..6a1a2c417 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1789,7 +1789,7 @@ class Server{ /** * @param TextContainer|string $message - * @param Player[] $recipients + * @param CommandSender[] $recipients * * @return int */ @@ -1798,7 +1798,7 @@ class Server{ return $this->broadcast($message, self::BROADCAST_CHANNEL_USERS); } - /** @var Player[] $recipients */ + /** @var CommandSender[] $recipients */ foreach($recipients as $recipient){ $recipient->sendMessage($message); } diff --git a/src/pocketmine/event/player/PlayerChatEvent.php b/src/pocketmine/event/player/PlayerChatEvent.php index 4ebddecdd..0bf9317b8 100644 --- a/src/pocketmine/event/player/PlayerChatEvent.php +++ b/src/pocketmine/event/player/PlayerChatEvent.php @@ -23,6 +23,7 @@ declare(strict_types=1); namespace pocketmine\event\player; +use pocketmine\command\CommandSender; use pocketmine\event\Cancellable; use pocketmine\permission\PermissionManager; use pocketmine\Player; @@ -39,15 +40,15 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ protected $format; /** - * @var Player[] + * @var CommandSender[] */ protected $recipients = []; /** - * @param Player $player - * @param string $message - * @param string $format - * @param Player[] $recipients + * @param Player $player + * @param string $message + * @param string $format + * @param CommandSender[] $recipients */ public function __construct(Player $player, string $message, string $format = "chat.type.text", array $recipients = null){ $this->player = $player; @@ -100,14 +101,14 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ } /** - * @return Player[] + * @return CommandSender[] */ public function getRecipients() : array{ return $this->recipients; } /** - * @param Player[] $recipients + * @param CommandSender[] $recipients */ public function setRecipients(array $recipients) : void{ $this->recipients = $recipients; From ce27c03774aac5744f0c2faa62e9dfa782bc3987 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 1 Dec 2019 21:44:13 +0000 Subject: [PATCH 28/29] PlayerChatEvent: fixed crash when non-CommandSender permissibles subscribe to broadcast permission doing such a thing doesn't make any sense, but the system allows it, so it has to be accounted for. --- src/pocketmine/event/player/PlayerChatEvent.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/event/player/PlayerChatEvent.php b/src/pocketmine/event/player/PlayerChatEvent.php index 0bf9317b8..1b8bbcaff 100644 --- a/src/pocketmine/event/player/PlayerChatEvent.php +++ b/src/pocketmine/event/player/PlayerChatEvent.php @@ -28,6 +28,7 @@ use pocketmine\event\Cancellable; use pocketmine\permission\PermissionManager; use pocketmine\Player; use pocketmine\Server; +use function spl_object_id; /** * Called when a player chats something @@ -57,7 +58,11 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{ $this->format = $format; if($recipients === null){ - $this->recipients = PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS); + foreach(PermissionManager::getInstance()->getPermissionSubscriptions(Server::BROADCAST_CHANNEL_USERS) as $permissible){ + if($permissible instanceof CommandSender){ + $this->recipients[spl_object_id($permissible)] = $permissible; + } + } }else{ $this->recipients = $recipients; } From dbbe1f2d5c04059ee9ddad12a0d33fbaea933683 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 3 Dec 2019 10:41:06 +0000 Subject: [PATCH 29/29] Revert "Entity: remove redundant check from spawnTo()" This reverts commit 3028832cd35c53937bb6502f74d3ad53646b12a7. When I created this commit, I made the flawed assumption that spawnTo() would not be used by plugins. In addition, I was not aware that there are some usages of spawnTo() in the core which do not check for chunk usage, such as in Player->showPlayer(). This caused a collection of problems including memory leaks and crashes due to disconnecting players not removing their references from viewed entities. The reverted commit may be the cause of #3178. --- src/pocketmine/entity/Entity.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index 3eb596d78..a2b3468e9 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -2048,7 +2048,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ * @param Player $player */ public function spawnTo(Player $player) : void{ - if(!isset($this->hasSpawned[$player->getLoaderId()])){ + if(!isset($this->hasSpawned[$player->getLoaderId()]) and $this->chunk !== null and isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])){ $this->hasSpawned[$player->getLoaderId()] = $player; $this->sendSpawnPacket($player);