From 7ef27a1a211b604d971d1326e7b88f8c515b28ff Mon Sep 17 00:00:00 2001 From: SOFe Date: Wed, 7 Aug 2019 14:54:01 +0800 Subject: [PATCH 01/63] support.yml Discord link should point to #rules --- .github/support.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/support.yml b/.github/support.yml index 608966cb1..135728ca3 100644 --- a/.github/support.yml +++ b/.github/support.yml @@ -8,7 +8,7 @@ supportComment: > Thanks, but this issue tracker not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue). - [Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bge7dYQ) | [Forums](https://forums.pmmp.io) + [Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io) # Whether to close issues marked as support requests close: true From d75650092882ba0a02b5a1babbe1ceeb4e7c9b50 Mon Sep 17 00:00:00 2001 From: SOFe Date: Thu, 8 Aug 2019 00:03:10 +0800 Subject: [PATCH 02/63] Also updated Discord link in suppor template and README --- .github/ISSUE_TEMPLATE/help---support.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/help---support.md b/.github/ISSUE_TEMPLATE/help---support.md index a724460a6..cc34e496b 100644 --- a/.github/ISSUE_TEMPLATE/help---support.md +++ b/.github/ISSUE_TEMPLATE/help---support.md @@ -11,4 +11,4 @@ We don't accept support requests on the issue tracker. Please try the following Documentation: http://pmmp.rtfd.io Forums: https://forums.pmmp.io -Discord: https://discord.gg/bge7dYQ +Discord: https://discord.gg/bmSAZBG diff --git a/README.md b/README.md index 2df12887a..e290302c4 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ ### Discussion - [Forums](https://forums.pmmp.io/) -- [Community Discord](https://discord.gg/bge7dYQ) +- [Community Discord](https://discord.gg/bmSAZBG) ### For developers * [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development From 807b860cfe3744963d997e7935af5d5a96ea4268 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 11 Aug 2019 19:00:27 +0100 Subject: [PATCH 03/63] protocol: fixup data type changes, closes #3072 --- src/pocketmine/entity/DataPropertyManager.php | 23 +++++-------------- src/pocketmine/entity/Entity.php | 2 +- .../network/mcpe/NetworkBinaryStream.php | 8 +++---- 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/pocketmine/entity/DataPropertyManager.php b/src/pocketmine/entity/DataPropertyManager.php index c8646132f..890ff3e2f 100644 --- a/src/pocketmine/entity/DataPropertyManager.php +++ b/src/pocketmine/entity/DataPropertyManager.php @@ -23,8 +23,8 @@ declare(strict_types=1); namespace pocketmine\entity; -use pocketmine\item\Item; use pocketmine\math\Vector3; +use pocketmine\nbt\tag\CompoundTag; use function assert; use function is_float; use function is_int; @@ -140,25 +140,14 @@ class DataPropertyManager{ $this->setPropertyValue($key, Entity::DATA_TYPE_STRING, $value, $force); } - /** - * @param int $key - * - * @return null|Item - */ - public function getItem(int $key) : ?Item{ - $value = $this->getPropertyValue($key, Entity::DATA_TYPE_SLOT); - assert($value instanceof Item or $value === null); - + public function getCompoundTag(int $key) : ?CompoundTag{ + $value = $this->getPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG); + assert($value instanceof CompoundTag or $value === null); return $value; } - /** - * @param int $key - * @param Item $value - * @param bool $force - */ - public function setItem(int $key, Item $value, bool $force = false) : void{ - $this->setPropertyValue($key, Entity::DATA_TYPE_SLOT, $value, $force); + public function setCompoundTag(int $key, CompoundTag $value, bool $force = false) : void{ + $this->setPropertyValue($key, Entity::DATA_TYPE_COMPOUND_TAG, $value, $force); } /** diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index b464da92c..a2026f4ec 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -102,7 +102,7 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ public const DATA_TYPE_INT = 2; public const DATA_TYPE_FLOAT = 3; public const DATA_TYPE_STRING = 4; - public const DATA_TYPE_SLOT = 5; + public const DATA_TYPE_COMPOUND_TAG = 5; public const DATA_TYPE_POS = 6; public const DATA_TYPE_LONG = 7; public const DATA_TYPE_VECTOR3F = 8; diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index cf71dfaf1..eb2456703 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -227,8 +227,8 @@ class NetworkBinaryStream extends BinaryStream{ case Entity::DATA_TYPE_STRING: $value = $this->getString(); break; - case Entity::DATA_TYPE_SLOT: - $value = $this->getSlot(); + case Entity::DATA_TYPE_COMPOUND_TAG: + $value = (new NetworkLittleEndianNBTStream())->read($this->buffer, false, $this->offset, 512); break; case Entity::DATA_TYPE_POS: $value = new Vector3(); @@ -279,8 +279,8 @@ class NetworkBinaryStream extends BinaryStream{ case Entity::DATA_TYPE_STRING: $this->putString($d[1]); break; - case Entity::DATA_TYPE_SLOT: - $this->putSlot($d[1]); + case Entity::DATA_TYPE_COMPOUND_TAG: + $this->put((new NetworkLittleEndianNBTStream())->write($d[1])); break; case Entity::DATA_TYPE_POS: $v = $d[1]; From 53dc6e2050b547fa9b82598dc6a489b949dd57d6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 11 Aug 2019 19:06:20 +0100 Subject: [PATCH 04/63] fix TallGrass and Tree random/base amounts never being initialized, closes #2996 --- src/pocketmine/level/generator/populator/TallGrass.php | 6 +++--- src/pocketmine/level/generator/populator/Tree.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pocketmine/level/generator/populator/TallGrass.php b/src/pocketmine/level/generator/populator/TallGrass.php index a60179946..49c8fdb8b 100644 --- a/src/pocketmine/level/generator/populator/TallGrass.php +++ b/src/pocketmine/level/generator/populator/TallGrass.php @@ -30,8 +30,8 @@ use pocketmine\utils\Random; class TallGrass extends Populator{ /** @var ChunkManager */ private $level; - private $randomAmount; - private $baseAmount; + private $randomAmount = 1; + private $baseAmount = 0; public function setRandomAmount($amount){ $this->randomAmount = $amount; @@ -43,7 +43,7 @@ class TallGrass extends Populator{ public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){ $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; + $amount = $random->nextRange(0, $this->randomAmount) + $this->baseAmount; for($i = 0; $i < $amount; ++$i){ $x = $random->nextRange($chunkX * 16, $chunkX * 16 + 15); $z = $random->nextRange($chunkZ * 16, $chunkZ * 16 + 15); diff --git a/src/pocketmine/level/generator/populator/Tree.php b/src/pocketmine/level/generator/populator/Tree.php index cbe8e6bce..edcd48f2c 100644 --- a/src/pocketmine/level/generator/populator/Tree.php +++ b/src/pocketmine/level/generator/populator/Tree.php @@ -32,8 +32,8 @@ use pocketmine\utils\Random; class Tree extends Populator{ /** @var ChunkManager */ private $level; - private $randomAmount; - private $baseAmount; + private $randomAmount = 1; + private $baseAmount = 0; private $type; @@ -51,7 +51,7 @@ class Tree extends Populator{ public function populate(ChunkManager $level, int $chunkX, int $chunkZ, Random $random){ $this->level = $level; - $amount = $random->nextRange(0, $this->randomAmount + 1) + $this->baseAmount; + $amount = $random->nextRange(0, $this->randomAmount) + $this->baseAmount; for($i = 0; $i < $amount; ++$i){ $x = $random->nextRange($chunkX << 4, ($chunkX << 4) + 15); $z = $random->nextRange($chunkZ << 4, ($chunkZ << 4) + 15); From 4d0e8741fe6310168c7b1c1e344e3015a5a8ad2f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 11 Aug 2019 19:32:21 +0100 Subject: [PATCH 05/63] Added a deprecation notice to Entity->getBlocksAround() --- src/pocketmine/entity/Entity.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index a2026f4ec..bf016fa54 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -1782,6 +1782,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } /** + * @deprecated WARNING: Despite what its name implies, this function DOES NOT return all the blocks around the entity. + * Instead, it returns blocks which have reactions for an entity intersecting with them. + * * @return Block[] */ public function getBlocksAround() : array{ From dbb669b156b2a6d66d0fb918eceb36572d8ee33a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 11 Aug 2019 19:34:57 +0100 Subject: [PATCH 06/63] Entity: add some deprecation warnings to despawnFrom() and despawnFromAll() --- src/pocketmine/entity/Entity.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pocketmine/entity/Entity.php b/src/pocketmine/entity/Entity.php index bf016fa54..fac66b10c 100644 --- a/src/pocketmine/entity/Entity.php +++ b/src/pocketmine/entity/Entity.php @@ -2074,6 +2074,9 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } /** + * @deprecated WARNING: This function DOES NOT permanently hide the entity from the player. As soon as the entity or + * player moves, the player will once again be able to see the entity. + * * @param Player $player * @param bool $send */ @@ -2088,6 +2091,10 @@ abstract class Entity extends Location implements Metadatable, EntityIds{ } } + /** + * @deprecated WARNING: This function DOES NOT permanently hide the entity from viewers. As soon as the entity or + * player moves, viewers will once again be able to see the entity. + */ public function despawnFromAll() : void{ foreach($this->hasSpawned as $player){ $this->despawnFrom($player); From 2f61d42518da7c809a7a5ec9b9e7c9c913ef0530 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 2 Jul 2019 19:54:56 +0100 Subject: [PATCH 07/63] backport d23eeff8324e51ea1a902271603c50551e074c1b: FallingBlock: remove useless check --- src/pocketmine/entity/object/FallingBlock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/object/FallingBlock.php b/src/pocketmine/entity/object/FallingBlock.php index cf67890f5..7d7d6cb1c 100644 --- a/src/pocketmine/entity/object/FallingBlock.php +++ b/src/pocketmine/entity/object/FallingBlock.php @@ -110,7 +110,7 @@ class FallingBlock extends Entity{ $this->flagForDespawn(); $block = $this->level->getBlock($pos); - if($block->getId() > 0 and $block->isTransparent() and !$block->canBeReplaced()){ + if($block->isTransparent() and !$block->canBeReplaced()){ //FIXME: anvils are supposed to destroy torches $this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage())); }else{ From 7bfb55ec9a859ea45b4d31658f00a5ddee393c99 Mon Sep 17 00:00:00 2001 From: Johnmacro Date: Tue, 13 Aug 2019 22:09:03 +0900 Subject: [PATCH 08/63] Fixed some errors in support.yml (#3095) [ci skip] --- .github/support.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/support.yml b/.github/support.yml index 135728ca3..fe3493dfb 100644 --- a/.github/support.yml +++ b/.github/support.yml @@ -5,7 +5,7 @@ supportLabel: "Support request" # Comment to post on issues marked as support requests. Add a link # to a support page, or set to `false` to disable supportComment: > - Thanks, but this issue tracker not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue). + Thanks, but this issue tracker is not intended for support requests. Please read the guidelines on [submitting an issue](https://github.com/pmmp/PocketMine-MP/blob/master/CONTRIBUTING.md#creating-an-issue). [Docs](https://pmmp.rtfd.io) | [Discord](https://discord.gg/bmSAZBG) | [Forums](https://forums.pmmp.io) From 677d43028a7622c845acb6b35e13e44e06510091 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 14 Aug 2019 18:08:26 +0100 Subject: [PATCH 09/63] add php-build-scripts as a submodule --- .gitmodules | 3 +++ build/php | 1 + 2 files changed, 4 insertions(+) create mode 160000 build/php diff --git a/.gitmodules b/.gitmodules index 74a88d57b..6696eb5bc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "src/pocketmine/resources/vanilla"] path = src/pocketmine/resources/vanilla url = https://github.com/pmmp/BedrockData.git +[submodule "build/php"] + path = build/php + url = https://github.com/pmmp/php-build-scripts.git diff --git a/build/php b/build/php new file mode 160000 index 000000000..ffc465f4f --- /dev/null +++ b/build/php @@ -0,0 +1 @@ +Subproject commit ffc465f4f806269138fc210832500c51fdecd471 From 25ff90b2c6880f1179210b8da073d89aadc44d5e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 16:46:59 +0100 Subject: [PATCH 10/63] PluginManager: fix chained softdepend plugins load order Test case: - plugin2 depends on nonexistent plugin1 - plugin3 depends on plugin2 At random occasions, plugin3 would be loaded before plugin2, because plugin2 load would be deferred in the expectation of plugin1 being loaded. This would result in the assumption that plugin3's softdepend plugins would not be loaded, so they were ignored. We fix this problem by removing missing plugins from softdepend if they were not present on a scan of the directory. This way, we don't ignore any unresolved deferred dependency resolutions. --- src/pocketmine/plugin/PluginManager.php | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/pocketmine/plugin/PluginManager.php b/src/pocketmine/plugin/PluginManager.php index 7936542fd..ee92644b3 100644 --- a/src/pocketmine/plugin/PluginManager.php +++ b/src/pocketmine/plugin/PluginManager.php @@ -305,7 +305,7 @@ class PluginManager{ while(count($plugins) > 0){ - $missingDependency = true; + $loadedThisLoop = 0; foreach($plugins as $name => $file){ if(isset($dependencies[$name])){ foreach($dependencies[$name] as $key => $dependency){ @@ -329,7 +329,14 @@ class PluginManager{ if(isset($softDependencies[$name])){ foreach($softDependencies[$name] as $key => $dependency){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ + $this->server->getLogger()->debug("Successfully resolved soft dependency \"$dependency\" for plugin \"$name\""); unset($softDependencies[$name][$key]); + }elseif(!isset($plugins[$dependency])){ + //this dependency is never going to be resolved, so don't bother trying + $this->server->getLogger()->debug("Skipping resolution of missing soft dependency \"$dependency\" for plugin \"$name\""); + unset($softDependencies[$name][$key]); + }else{ + $this->server->getLogger()->debug("Deferring resolution of soft dependency \"$dependency\" for plugin \"$name\" (found but not loaded yet)"); } } @@ -340,7 +347,7 @@ class PluginManager{ if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){ unset($plugins[$name]); - $missingDependency = false; + $loadedThisLoop++; if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ $loadedPlugins[$name] = $plugin; }else{ @@ -349,27 +356,12 @@ class PluginManager{ } } - if($missingDependency){ - foreach($plugins as $name => $file){ - if(!isset($dependencies[$name])){ - unset($softDependencies[$name]); - unset($plugins[$name]); - $missingDependency = false; - if($plugin = $this->loadPlugin($file, $loaders) and $plugin instanceof Plugin){ - $loadedPlugins[$name] = $plugin; - }else{ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.genericLoadError", [$name])); - } - } - } - + if($loadedThisLoop === 0){ //No plugins loaded :( - if($missingDependency){ - foreach($plugins as $name => $file){ - $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"])); - } - $plugins = []; + foreach($plugins as $name => $file){ + $this->server->getLogger()->critical($this->server->getLanguage()->translateString("pocketmine.plugin.loadError", [$name, "%pocketmine.plugin.circularDependency"])); } + $plugins = []; } } From 2ba8eac27f13f92daf3ac3822f7fe26795877386 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 17:27:41 +0100 Subject: [PATCH 11/63] FallingBlock: fix endless falling on top of fences this is a shitty fix, but I don't think there's a better way to do it on 3.x. This also fixes dropping on cactus. close #2449, close #2895 --- src/pocketmine/entity/object/FallingBlock.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/entity/object/FallingBlock.php b/src/pocketmine/entity/object/FallingBlock.php index 7d7d6cb1c..7c47612e2 100644 --- a/src/pocketmine/entity/object/FallingBlock.php +++ b/src/pocketmine/entity/object/FallingBlock.php @@ -33,6 +33,8 @@ use pocketmine\item\ItemFactory; 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{ @@ -110,7 +112,7 @@ class FallingBlock extends Entity{ $this->flagForDespawn(); $block = $this->level->getBlock($pos); - if($block->isTransparent() and !$block->canBeReplaced()){ + if(($block->isTransparent() and !$block->canBeReplaced()) or abs($this->y - $this->getFloorY()) > 0.001){ //FIXME: anvils are supposed to destroy torches $this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage())); }else{ From 092edc9d43bb3061d0d743ab6e48f1d1fe18eb23 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 17:41:50 +0100 Subject: [PATCH 12/63] avoid breaking concrete powder --- src/pocketmine/entity/object/FallingBlock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/object/FallingBlock.php b/src/pocketmine/entity/object/FallingBlock.php index 7c47612e2..87e408d1f 100644 --- a/src/pocketmine/entity/object/FallingBlock.php +++ b/src/pocketmine/entity/object/FallingBlock.php @@ -112,7 +112,7 @@ class FallingBlock extends Entity{ $this->flagForDespawn(); $block = $this->level->getBlock($pos); - if(($block->isTransparent() and !$block->canBeReplaced()) or abs($this->y - $this->getFloorY()) > 0.001){ + if(($block->isTransparent() and !$block->canBeReplaced()) or ($this->onGround and abs($this->y - $this->getFloorY()) > 0.001)){ //FIXME: anvils are supposed to destroy torches $this->getLevel()->dropItem($this, ItemFactory::get($this->getBlock(), $this->getDamage())); }else{ From 1be6783c34ec51b578464899994285a7e8188590 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 17:58:01 +0100 Subject: [PATCH 13/63] Release 3.9.4 --- changelogs/3.9.md | 12 ++++++++++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/changelogs/3.9.md b/changelogs/3.9.md index 9e3e86b75..8e2591f72 100644 --- a/changelogs/3.9.md +++ b/changelogs/3.9.md @@ -57,3 +57,15 @@ Plugin developers should **only** update their required API to this version if y - Fixed a memory leak on async task removal in error conditions. - Fixed scheduled block updates (for example liquid) triggering chunk reloading. This could cause a significant performance issue in some conditions. - Fixed some minor cosmetic issues in documentation. + +# 3.9.4 +- Fixed a memory leak when scheduled updates were pending on a chunk being unloaded. +- Fixed plugin detection in crashdumps. Previously `src/pocketmine` anywhere in the path would cause the error to be considered a core crash, regardless of the preceding path. +- Fixed entity metadata types for 1.12. The SLOT type was removed and a COMPOUND_TAG type added. This change involves changes to internal API which may break plugins. **See the warning at the top of this changelog about API versioning.** +- Fixed random and base populator amounts of trees and tallgrass never being initialized. This bug had no obvious effect, but may have become a problem in future PHP versions. +- The following internal methods have been marked as `@deprecated` and documentation warnings added: + - `Entity->getBlocksAround()` + - `Entity->despawnFrom()` + - `Entity->despawnFromAll()` +- Fixed plugin `softdepend` not influencing load order when a soft-depended plugin had an unresolved soft dependency of its own. +- Fixed endless falling of sand on top of fences. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 25617f9eb..310d07873 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -23,5 +23,5 @@ namespace pocketmine; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.9.4"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; From a19143cae76ad55f1bdc2f39ad007b1fc170980b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 16 Aug 2019 17:58:02 +0100 Subject: [PATCH 14/63] 3.9.5 is next --- src/pocketmine/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 310d07873..d87f84ae4 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -22,6 +22,6 @@ namespace pocketmine; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.9.4"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.9.5"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; From d724374d1af369d16647bc1ec3da2e8e733d08e2 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Mon, 16 Sep 2019 15:53:00 +0100 Subject: [PATCH 15/63] StupidJsonDecodeTest: add failing test case for #3113 --- tests/phpunit/network/mcpe/StupidJsonDecodeTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php index b096c6c9d..40de1a35c 100644 --- a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php +++ b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php @@ -34,7 +34,8 @@ class StupidJsonDecodeTest extends TestCase{ ["false", false], ["NULL", null], ['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']], - ['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']] + ['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']], + ['["Hello,, PocketMine"]', ['Hello,, PocketMine']] ]; } From 70b1ac856df7c17cc0b1a0ccb3ad304491f1e4f7 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 17 Sep 2019 11:01:33 +0100 Subject: [PATCH 16/63] ZippedResourcePack: fix mishandling of wrong root JSON type (crashdump #2840512) --- src/pocketmine/resourcepacks/ZippedResourcePack.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/resourcepacks/ZippedResourcePack.php b/src/pocketmine/resourcepacks/ZippedResourcePack.php index 8aa4ca8cb..d453396b7 100644 --- a/src/pocketmine/resourcepacks/ZippedResourcePack.php +++ b/src/pocketmine/resourcepacks/ZippedResourcePack.php @@ -104,7 +104,9 @@ class ZippedResourcePack implements ResourcePack{ }catch(\RuntimeException $e){ throw new ResourcePackException("Failed to parse manifest.json: " . $e->getMessage(), $e->getCode(), $e); } - + if(!($manifest instanceof \stdClass)){ + throw new ResourcePackException("manifest.json should contain a JSON object, not " . gettype($manifest)); + } if(!self::verifyManifest($manifest)){ throw new ResourcePackException("manifest.json is missing required fields"); } From 11a6e04a288f3379fac160647f5a6f8a037c913b Mon Sep 17 00:00:00 2001 From: Dylan T Date: Wed, 18 Sep 2019 10:02:52 +0100 Subject: [PATCH 17/63] EnderPearl: remove collision box hack (this isn't needed for MCPE anyway) This was intended to address the problem that ender pearls would not stop on grass, saplings, and other similar objects. However, they don't stop on such objects in MCPE anyway, only PC. --- .../entity/projectile/EnderPearl.php | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/pocketmine/entity/projectile/EnderPearl.php b/src/pocketmine/entity/projectile/EnderPearl.php index 2bbdfab5e..627f84fde 100644 --- a/src/pocketmine/entity/projectile/EnderPearl.php +++ b/src/pocketmine/entity/projectile/EnderPearl.php @@ -23,36 +23,14 @@ declare(strict_types=1); namespace pocketmine\entity\projectile; -use pocketmine\block\Block; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\ProjectileHitEvent; use pocketmine\level\sound\EndermanTeleportSound; -use pocketmine\math\AxisAlignedBB; -use pocketmine\math\RayTraceResult; -use pocketmine\math\Vector3; use pocketmine\network\mcpe\protocol\LevelEventPacket; class EnderPearl extends Throwable{ public const NETWORK_ID = self::ENDER_PEARL; - protected function calculateInterceptWithBlock(Block $block, Vector3 $start, Vector3 $end) : ?RayTraceResult{ - if($block->getId() !== Block::AIR and empty($block->getCollisionBoxes())){ - //TODO: remove this once block collision boxes are fixed properly - $bb = new AxisAlignedBB( - $block->x, - $block->y, - $block->z, - $block->x + 1, - $block->y + 1, - $block->z + 1 - ); - - return $bb->calculateIntercept($start, $end); - } - - return parent::calculateInterceptWithBlock($block, $start, $end); - } - protected function onHit(ProjectileHitEvent $event) : void{ $owner = $this->getOwningEntity(); if($owner !== null){ From e41a2c0792b0cfc95b7b3e456e23dc8523adf201 Mon Sep 17 00:00:00 2001 From: SOFe Date: Mon, 23 Sep 2019 18:56:37 +0800 Subject: [PATCH 18/63] Link to StackOverflow in README (#3084) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e290302c4..a030cd012 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,10 @@ - [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp) - [Plugin repository](https://poggit.pmmp.io/plugins) -### Discussion +### Discussion/Help - [Forums](https://forums.pmmp.io/) - [Community Discord](https://discord.gg/bmSAZBG) +- [StackOverflow](https://stackoverflow.com/tags/pocketmine) ### For developers * [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development From 7a2a4e2aa301816e05768ead38b516e42b410b7c Mon Sep 17 00:00:00 2001 From: Dylan T Date: Wed, 25 Sep 2019 12:59:04 +0100 Subject: [PATCH 19/63] change some heading sizes [ci skip] --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a030cd012..5b4e0fcbc 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,24 @@ [![Build Status](https://travis-ci.org/pmmp/PocketMine-MP.svg?branch=master)](https://travis-ci.org/pmmp/PocketMine-MP) -### Getting started +## Getting started - [Documentation](http://pmmp.readthedocs.org/) - [Installation instructions](https://pmmp.readthedocs.io/en/rtfd/installation.html) - [Docker image](https://hub.docker.com/r/pmmp/pocketmine-mp) - [Plugin repository](https://poggit.pmmp.io/plugins) -### Discussion/Help +## Discussion/Help - [Forums](https://forums.pmmp.io/) - [Community Discord](https://discord.gg/bmSAZBG) - [StackOverflow](https://stackoverflow.com/tags/pocketmine) -### For developers +## For developers * [Latest API documentation](https://jenkins.pmmp.io/job/PocketMine-MP-doc/doxygen/) - Doxygen documentation generated from development * [DevTools](https://github.com/pmmp/PocketMine-DevTools/) - Development tools plugin for creating plugins * [ExamplePlugin](https://github.com/pmmp/ExamplePlugin/) - Example plugin demonstrating some basic API features * [Contributing Guidelines](CONTRIBUTING.md) -### Donate +## Donate - Bitcoin Cash (BCH): `qq3r46hn6ljnhnqnfwxt5pg3g447eq9jhvw5ddfear` - Bitcoin (BTC): `171u8K9e4FtU6j3e5sqNoxKUgEw9qWQdRV` - [Patreon](https://www.patreon.com/pocketminemp) From d0d61597c7c65af5587b182a02d81e68ff95046b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 26 Sep 2019 11:12:43 +0100 Subject: [PATCH 20/63] StupidJsonDecodeTest: use getClosure() instead of traditional mess this is faster and requires less code. --- tests/phpunit/network/mcpe/StupidJsonDecodeTest.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php index 40de1a35c..8fced8a71 100644 --- a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php +++ b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php @@ -26,6 +26,12 @@ namespace pocketmine\network\mcpe; use PHPUnit\Framework\TestCase; class StupidJsonDecodeTest extends TestCase{ + /** @var \Closure */ + private $stupidJsonDecodeFunc; + + public function setUp() : void{ + $this->stupidJsonDecodeFunc = (new \ReflectionMethod(PlayerNetworkSessionAdapter::class, 'stupid_json_decode'))->getClosure(); + } public function stupidJsonDecodeProvider() : array{ return [ @@ -48,10 +54,7 @@ class StupidJsonDecodeTest extends TestCase{ * @throws \ReflectionException */ public function testStupidJsonDecode(string $brokenJson, $expect){ - $func = new \ReflectionMethod(PlayerNetworkSessionAdapter::class, 'stupid_json_decode'); - $func->setAccessible(true); - - $decoded = $func->invoke(null, $brokenJson, true); + $decoded = ($this->stupidJsonDecodeFunc)($brokenJson, true); self::assertEquals($expect, $decoded); } } From 8a6381c3fa1ca150f6552f7d5fc08a2848cfcf85 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 1 Oct 2019 13:25:20 +0100 Subject: [PATCH 21/63] StupidJsonDecodeTest: add some extra test vectors --- tests/phpunit/network/mcpe/StupidJsonDecodeTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php index 8fced8a71..ac9940032 100644 --- a/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php +++ b/tests/phpunit/network/mcpe/StupidJsonDecodeTest.php @@ -41,7 +41,9 @@ class StupidJsonDecodeTest extends TestCase{ ["NULL", null], ['["\",,\"word","a\",,\"word2",]', ['",,"word', 'a",,"word2', '']], ['["\",,\"word","a\",,\"word2",""]', ['",,"word', 'a",,"word2', '']], - ['["Hello,, PocketMine"]', ['Hello,, PocketMine']] + ['["Hello,, PocketMine"]', ['Hello,, PocketMine']], + ['[,]', ['', '']], + ['[]', []] ]; } From 4da06078edfe0cc69d1e9d98d85f401ce9b86dd8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 1 Oct 2019 14:22:07 +0100 Subject: [PATCH 22/63] Server: promote Patreon on startup --- src/pocketmine/Server.php | 1 + src/pocketmine/lang/locale | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 06497fde0..6a35a1a15 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -2200,6 +2200,7 @@ class Server{ $this->logger->info($this->getLanguage()->translateString("pocketmine.server.defaultGameMode", [self::getGamemodeString($this->getGamemode())])); + $this->logger->info($this->getLanguage()->translateString("pocketmine.server.donate", [TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET])); $this->logger->info($this->getLanguage()->translateString("pocketmine.server.startFinished", [round(microtime(true) - \pocketmine\START_TIME, 3)])); $this->tickProcessor(); diff --git a/src/pocketmine/lang/locale b/src/pocketmine/lang/locale index 73ed1ab3e..85343cfb7 160000 --- a/src/pocketmine/lang/locale +++ b/src/pocketmine/lang/locale @@ -1 +1 @@ -Subproject commit 73ed1ab3e1f2a1644fe908b439f8cf8ed6c12ab5 +Subproject commit 85343cfb7f7892bcb42ae7b7f594199cebca7d03 From 63d7e7b811d130fae663aa7cc517b04a32d37492 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Tue, 1 Oct 2019 14:28:55 +0100 Subject: [PATCH 23/63] Fixed decoding form responses with double commas inside quotes (#3131) closes #3113 --- .../mcpe/PlayerNetworkSessionAdapter.php | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php index a3c8f9d65..7e546647c 100644 --- a/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php +++ b/src/pocketmine/network/mcpe/PlayerNetworkSessionAdapter.php @@ -74,7 +74,6 @@ use function implode; use function json_decode; use function json_last_error_msg; use function preg_match; -use function preg_split; use function strlen; use function substr; use function trim; @@ -270,16 +269,31 @@ class PlayerNetworkSessionAdapter extends NetworkSession{ */ private static function stupid_json_decode(string $json, bool $assoc = false){ if(preg_match('/^\[(.+)\]$/s', $json, $matches) > 0){ - $parts = preg_split('/(?:"(?:\\"|[^"])*"|)\K(,)/', $matches[1]); //Splits on commas not inside quotes, ignoring escaped quotes - foreach($parts as $k => $part){ - $part = trim($part); - if($part === ""){ - $part = "\"\""; + $raw = $matches[1]; + $lastComma = -1; + $newParts = []; + $quoteType = null; + for($i = 0, $len = strlen($raw); $i <= $len; ++$i){ + if($i === $len or ($raw[$i] === "," and $quoteType === null)){ + $part = substr($raw, $lastComma + 1, $i - ($lastComma + 1)); + if(trim($part) === ""){ //regular parts will have quotes or something else that makes them non-empty + $part = '""'; + } + $newParts[] = $part; + $lastComma = $i; + }elseif($raw[$i] === '"'){ + if($quoteType === null){ + $quoteType = $raw[$i]; + }elseif($raw[$i] === $quoteType){ + for($backslashes = 0; $backslashes < $i && $raw[$i - $backslashes - 1] === "\\"; ++$backslashes){} + if(($backslashes % 2) === 0){ //unescaped quote + $quoteType = null; + } + } } - $parts[$k] = $part; } - $fixed = "[" . implode(",", $parts) . "]"; + $fixed = "[" . implode(",", $newParts) . "]"; if(($ret = json_decode($fixed, $assoc)) === null){ throw new \InvalidArgumentException("Failed to fix JSON: " . json_last_error_msg() . "(original: $json, modified: $fixed)"); } From f0539f48983a3961290f2a4b9828586cc11b0008 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 1 Oct 2019 15:02:33 +0100 Subject: [PATCH 24/63] Release 3.9.5 --- changelogs/3.9.md | 5 +++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/changelogs/3.9.md b/changelogs/3.9.md index 8e2591f72..9e91d7c04 100644 --- a/changelogs/3.9.md +++ b/changelogs/3.9.md @@ -69,3 +69,8 @@ Plugin developers should **only** update their required API to this version if y - `Entity->despawnFromAll()` - Fixed plugin `softdepend` not influencing load order when a soft-depended plugin had an unresolved soft dependency of its own. - Fixed endless falling of sand on top of fences. + +# 3.9.5 +- Fixed some issues with multiple consecutive commas inside quotes in form responses. +- Fixed server crash when the manifest json does not contain a json object in a resource pack. +- Ender pearls no longer collide with blocks that do not have any collision boxes. diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index d87f84ae4..c4144ea55 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -23,5 +23,5 @@ namespace pocketmine; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.9.5"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; From 2807f14fcd7ee4b50ae3b0a0702550efeede785e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 1 Oct 2019 15:02:34 +0100 Subject: [PATCH 25/63] 3.9.6 is next --- src/pocketmine/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index c4144ea55..2ccede412 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -22,6 +22,6 @@ namespace pocketmine; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.9.5"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.9.6"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0; From 4e060bc13f52410dac6b97206eee995388aeec2e Mon Sep 17 00:00:00 2001 From: Ivan Date: Wed, 2 Oct 2019 15:37:05 +0300 Subject: [PATCH 26/63] EventPacket: Added some new constants (#3132) --- src/pocketmine/network/mcpe/protocol/EventPacket.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pocketmine/network/mcpe/protocol/EventPacket.php b/src/pocketmine/network/mcpe/protocol/EventPacket.php index 307092dcf..bdf440729 100644 --- a/src/pocketmine/network/mcpe/protocol/EventPacket.php +++ b/src/pocketmine/network/mcpe/protocol/EventPacket.php @@ -43,6 +43,11 @@ class EventPacket extends DataPacket{ public const TYPE_PATTERN_REMOVED = 10; //??? public const TYPE_COMMANED_EXECUTED = 11; public const TYPE_FISH_BUCKETED = 12; + public const TYPE_MOB_BORN = 13; + public const TYPE_PET_DIED = 14; + public const TYPE_CAULDRON_BLOCK_USED = 15; + public const TYPE_COMPOSTER_BLOCK_USED = 16; + public const TYPE_BELL_BLOCK_USED = 17; /** @var int */ public $playerRuntimeId; From 562b47a1e5de890213422bc19d9353505259523b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 3 Oct 2019 11:19:45 +0100 Subject: [PATCH 27/63] Player: guard against repeated resource pack sequence this can happen because of the client being super broken in 1.12 close #3036 --- src/pocketmine/Player.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 0cec6e63a..1969fc1da 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -261,6 +261,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ /** @var bool */ public $loggedIn = false; + /** @var bool */ + private $resourcePacksDone = false; + /** @var bool */ public $spawned = false; @@ -2056,6 +2059,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } public function handleResourcePackClientResponse(ResourcePackClientResponsePacket $packet) : bool{ + if($this->resourcePacksDone){ + return false; + } switch($packet->status){ case ResourcePackClientResponsePacket::STATUS_REFUSED: //TODO: add lang strings for this @@ -2097,6 +2103,7 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ $this->dataPacket($pk); break; case ResourcePackClientResponsePacket::STATUS_COMPLETED: + $this->resourcePacksDone = true; $this->completeLoginSequence(); break; default: @@ -3049,6 +3056,9 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } public function handleResourcePackChunkRequest(ResourcePackChunkRequestPacket $packet) : bool{ + if($this->resourcePacksDone){ + return false; + } $manager = $this->server->getResourcePackManager(); $pack = $manager->getPackById($packet->packId); if(!($pack instanceof ResourcePack)){ From 348c2a599bf1bb5c545e30ce41cacd0405117e78 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 4 Oct 2019 10:59:32 +0100 Subject: [PATCH 28/63] Internet: report PM version in user agent this is useful for statistics --- src/pocketmine/utils/Internet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/utils/Internet.php b/src/pocketmine/utils/Internet.php index ebd704bda..0198b319f 100644 --- a/src/pocketmine/utils/Internet.php +++ b/src/pocketmine/utils/Internet.php @@ -210,7 +210,7 @@ class Internet{ CURLOPT_RETURNTRANSFER => true, CURLOPT_CONNECTTIMEOUT_MS => (int) ($timeout * 1000), CURLOPT_TIMEOUT_MS => (int) ($timeout * 1000), - CURLOPT_HTTPHEADER => array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 " . \pocketmine\NAME], $extraHeaders), + CURLOPT_HTTPHEADER => array_merge(["User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0 " . \pocketmine\NAME . "/" . \pocketmine\VERSION], $extraHeaders), CURLOPT_HEADER => true ]); try{ From ee60a7bc365d3c00d78700de039dbaccaececa66 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Mon, 7 Oct 2019 09:37:59 +0100 Subject: [PATCH 29/63] Item: add documentation for addCreativeItem(), removeCreativeItem() and clearCreativeItems() [ci skip] --- src/pocketmine/item/Item.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/pocketmine/item/Item.php b/src/pocketmine/item/Item.php index 6187487dc..664e07bba 100644 --- a/src/pocketmine/item/Item.php +++ b/src/pocketmine/item/Item.php @@ -137,6 +137,10 @@ class Item implements ItemIds, \JsonSerializable{ } } + /** + * Removes all previously added items from the creative menu. + * Note: Players who are already online when this is called will not see this change. + */ public static function clearCreativeItems(){ Item::$creative = []; } @@ -145,10 +149,22 @@ class Item implements ItemIds, \JsonSerializable{ return Item::$creative; } + /** + * Adds an item to the creative menu. + * Note: Players who are already online when this is called will not see this change. + * + * @param Item $item + */ public static function addCreativeItem(Item $item){ Item::$creative[] = clone $item; } + /** + * Removes an item from the creative menu. + * Note: Players who are already online when this is called will not see this change. + * + * @param Item $item + */ public static function removeCreativeItem(Item $item){ $index = self::getCreativeItemIndex($item); if($index !== -1){ From 247875e3d5956c8436624e3ad28b79377f930916 Mon Sep 17 00:00:00 2001 From: Dylan T Date: Mon, 7 Oct 2019 09:44:17 +0100 Subject: [PATCH 30/63] Explosion: add documentation for explodeA() and explodeB() these functions really ought to be renamed, or possibly redesigned entirely. However, that's no task for a patch version. [ci skip] --- src/pocketmine/level/Explosion.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pocketmine/level/Explosion.php b/src/pocketmine/level/Explosion.php index 80772cbe8..e234fdd3e 100644 --- a/src/pocketmine/level/Explosion.php +++ b/src/pocketmine/level/Explosion.php @@ -89,6 +89,9 @@ class Explosion{ } /** + * Calculates which blocks will be destroyed by this explosion. If explodeB() is called without calling this, no blocks + * will be destroyed. + * * @return bool */ public function explodeA() : bool{ @@ -148,6 +151,12 @@ class Explosion{ return true; } + /** + * Executes the explosion's effects on the world. This includes destroying blocks (if any), harming and knocking back entities, + * and creating sounds and particles. + * + * @return bool + */ public function explodeB() : bool{ $send = []; $updateBlocks = []; From 13994055d90af6a75b8d546e9ae07da6fd20465f Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 9 Oct 2019 11:26:20 +0100 Subject: [PATCH 31/63] SetupWizard: disable spawn protection by default we can't change anything else wrt. this on a patch version, disabling it in the main core by default involves possible behavioural breaks --- src/pocketmine/wizard/SetupWizard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/wizard/SetupWizard.php b/src/pocketmine/wizard/SetupWizard.php index 21aa3a93b..ba7991afc 100644 --- a/src/pocketmine/wizard/SetupWizard.php +++ b/src/pocketmine/wizard/SetupWizard.php @@ -162,7 +162,7 @@ LICENSE; $this->message($this->lang->get("spawn_protection_info")); - if(strtolower($this->getInput($this->lang->get("spawn_protection"), "y", "Y/n")) === "n"){ + if(strtolower($this->getInput($this->lang->get("spawn_protection"), "n", "y/N")) === "n"){ $config->set("spawn-protection", -1); }else{ $config->set("spawn-protection", 16); From aeeee5eb5321c604f751721af19d634c4a5b564e Mon Sep 17 00:00:00 2001 From: Ivan Date: Mon, 14 Oct 2019 17:14:42 +0700 Subject: [PATCH 32/63] Added encode/decode for StructureTemplateDataExport(Request|Response)Packet (#3145) --- .../network/mcpe/NetworkBinaryStream.php | 37 +++++++++++++ ...ructureTemplateDataExportRequestPacket.php | 27 ++++++++- ...uctureTemplateDataExportResponsePacket.php | 16 +++++- .../mcpe/protocol/types/StructureSettings.php | 55 +++++++++++++++++++ 4 files changed, 131 insertions(+), 4 deletions(-) create mode 100644 src/pocketmine/network/mcpe/protocol/types/StructureSettings.php diff --git a/src/pocketmine/network/mcpe/NetworkBinaryStream.php b/src/pocketmine/network/mcpe/NetworkBinaryStream.php index eb2456703..ba48a129b 100644 --- a/src/pocketmine/network/mcpe/NetworkBinaryStream.php +++ b/src/pocketmine/network/mcpe/NetworkBinaryStream.php @@ -37,6 +37,7 @@ 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\StructureSettings; use pocketmine\utils\BinaryStream; use pocketmine\utils\UUID; use function count; @@ -592,4 +593,40 @@ class NetworkBinaryStream extends BinaryStream{ $this->putVarLong($data->varlong1); } } + + protected function getStructureSettings() : StructureSettings{ + $result = new StructureSettings(); + + $result->paletteName = $this->getString(); + + $result->ignoreEntities = $this->getBool(); + $result->ignoreBlocks = $this->getBool(); + + $this->getBlockPosition($result->structureSizeX, $result->structureSizeY, $result->structureSizeZ); + $this->getBlockPosition($result->structureOffsetX, $result->structureOffsetY, $result->structureOffsetZ); + + $result->lastTouchedByPlayerID = $this->getEntityUniqueId(); + $result->rotation = $this->getByte(); + $result->mirror = $this->getByte(); + $result->integrityValue = $this->getFloat(); + $result->integritySeed = $this->getInt(); + + return $result; + } + + protected function putStructureSettings(StructureSettings $structureSettings) : void{ + $this->putString($structureSettings->paletteName); + + $this->putBool($structureSettings->ignoreEntities); + $this->putBool($structureSettings->ignoreBlocks); + + $this->putBlockPosition($structureSettings->structureSizeX, $structureSettings->structureSizeY, $structureSettings->structureSizeZ); + $this->putBlockPosition($structureSettings->structureOffsetX, $structureSettings->structureOffsetY, $structureSettings->structureOffsetZ); + + $this->putEntityUniqueId($structureSettings->lastTouchedByPlayerID); + $this->putByte($structureSettings->rotation); + $this->putByte($structureSettings->mirror); + $this->putFloat($structureSettings->integrityValue); + $this->putInt($structureSettings->integritySeed); + } } diff --git a/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportRequestPacket.php b/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportRequestPacket.php index b1cebc172..6ae16cec4 100644 --- a/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportRequestPacket.php +++ b/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportRequestPacket.php @@ -26,16 +26,39 @@ namespace pocketmine\network\mcpe\protocol; #include use pocketmine\network\mcpe\NetworkSession; +use pocketmine\network\mcpe\protocol\types\StructureSettings; class StructureTemplateDataExportRequestPacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_REQUEST_PACKET; + public const TYPE_ALWAYS_LOAD = 1; + public const TYPE_CREATE_AND_LOAD = 2; + + /** @var string */ + public $structureTemplateName; + /** @var int */ + public $structureBlockX; + /** @var int */ + public $structureBlockY; + /** @var int */ + public $structureBlockZ; + /** @var StructureSettings */ + public $structureSettings; + /** @var int */ + public $structureTemplateResponseType; + protected function decodePayload() : void{ - //TODO + $this->structureTemplateName = $this->getString(); + $this->getBlockPosition($this->structureBlockX, $this->structureBlockY, $this->structureBlockZ); + $this->structureSettings = $this->getStructureSettings(); + $this->structureTemplateResponseType = $this->getByte(); } protected function encodePayload() : void{ - //TODO + $this->putString($this->structureTemplateName); + $this->putBlockPosition($this->structureBlockX, $this->structureBlockY, $this->structureBlockZ); + $this->putStructureSettings($this->structureSettings); + $this->putByte($this->structureTemplateResponseType); } public function handle(NetworkSession $handler) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportResponsePacket.php b/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportResponsePacket.php index b3878fd64..2ff52b116 100644 --- a/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportResponsePacket.php +++ b/src/pocketmine/network/mcpe/protocol/StructureTemplateDataExportResponsePacket.php @@ -30,12 +30,24 @@ use pocketmine\network\mcpe\NetworkSession; class StructureTemplateDataExportResponsePacket extends DataPacket{ public const NETWORK_ID = ProtocolInfo::STRUCTURE_TEMPLATE_DATA_EXPORT_RESPONSE_PACKET; + /** @var string */ + public $structureTemplateName; + /** @var string|null */ + public $namedtag; + protected function decodePayload() : void{ - //TODO + $this->structureTemplateName = $this->getString(); + if($this->getBool()){ + $this->namedtag = $this->getRemaining(); + } } protected function encodePayload() : void{ - //TODO + $this->putString($this->structureTemplateName); + $this->putBool($this->namedtag !== null); + if($this->namedtag !== null){ + $this->put($this->namedtag); + } } public function handle(NetworkSession $handler) : bool{ diff --git a/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php b/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php new file mode 100644 index 000000000..465e643cc --- /dev/null +++ b/src/pocketmine/network/mcpe/protocol/types/StructureSettings.php @@ -0,0 +1,55 @@ + Date: Wed, 16 Oct 2019 11:45:30 +0100 Subject: [PATCH 33/63] Server: fixed default difficulty being EASY instead of NORMAL --- src/pocketmine/Server.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 6a35a1a15..afab41994 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -593,7 +593,7 @@ class Server{ * @return int */ public function getDifficulty() : int{ - return $this->getConfigInt("difficulty", 1); + return $this->getConfigInt("difficulty", Level::DIFFICULTY_NORMAL); } /** @@ -1529,7 +1529,7 @@ class Server{ "force-gamemode" => false, "hardcore" => false, "pvp" => true, - "difficulty" => 1, + "difficulty" => Level::DIFFICULTY_NORMAL, "generator-settings" => "", "level-name" => "world", "level-seed" => "", From b961b4e0031a417f34bd217c70bc36bae601a132 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 16 Oct 2019 11:48:25 +0100 Subject: [PATCH 34/63] SetupWizard: use constant for default gamemode --- src/pocketmine/wizard/SetupWizard.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pocketmine/wizard/SetupWizard.php b/src/pocketmine/wizard/SetupWizard.php index ba7991afc..8c0baed73 100644 --- a/src/pocketmine/wizard/SetupWizard.php +++ b/src/pocketmine/wizard/SetupWizard.php @@ -28,6 +28,7 @@ declare(strict_types=1); namespace pocketmine\wizard; use pocketmine\lang\BaseLang; +use pocketmine\Player; use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\InternetException; @@ -45,7 +46,7 @@ class SetupWizard{ public const DEFAULT_NAME = \pocketmine\NAME . " Server"; public const DEFAULT_PORT = 19132; public const DEFAULT_PLAYERS = 20; - public const DEFAULT_GAMEMODE = 0; + public const DEFAULT_GAMEMODE = Player::SURVIVAL; /** @var BaseLang */ private $lang; From 7439e1971df2bb9be176f5197d57ce74ba5a1d68 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 17 Oct 2019 11:27:00 +0100 Subject: [PATCH 35/63] Server: stop spamming crashdumps on unsupported / corrupted worlds really we should look into making the server stop if any world fails to load, but flooding the place with crashdumps isn't the way to do it. This is a simplified version of cf73c7f5c1f0e9c549864fe0434238aa66d49649 --- src/pocketmine/Server.php | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index afab41994..e992a9a3e 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1101,11 +1101,17 @@ class Server{ return false; } - /** - * @var LevelProvider $provider - * @see LevelProvider::__construct() - */ - $provider = new $providerClass($path); + + try{ + /** + * @var LevelProvider $provider + * @see LevelProvider::__construct() + */ + $provider = new $providerClass($path); + }catch(LevelException $e){ + $this->logger->error($this->getLanguage()->translateString("pocketmine.level.loadError", [$name, $e->getMessage()])); + return false; + } try{ GeneratorManager::getGenerator($provider->getGenerator(), true); }catch(\InvalidArgumentException $e){ From 04e4a366538309349a1b4aa5c5d17ae821b7a73d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 17 Oct 2019 18:56:51 +0100 Subject: [PATCH 36/63] LevelDB: remove unnecessary \pocketmine\NAME dependency this is non-obvious and makes it a pain the ass to use outside of PM. --- src/pocketmine/level/format/io/leveldb/LevelDB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/level/format/io/leveldb/LevelDB.php b/src/pocketmine/level/format/io/leveldb/LevelDB.php index d75f0e779..6c3e5ec7d 100644 --- a/src/pocketmine/level/format/io/leveldb/LevelDB.php +++ b/src/pocketmine/level/format/io/leveldb/LevelDB.php @@ -129,7 +129,7 @@ class LevelDB extends BaseLevelProvider{ $version = $this->levelData->getInt("StorageVersion", INT32_MAX, true); if($version > self::CURRENT_STORAGE_VERSION){ - throw new LevelException("Specified LevelDB world format version ($version) is not supported by " . \pocketmine\NAME); + throw new LevelException("Specified LevelDB world format version ($version) is not supported"); } } From bf44bd016d663cb3a7e7542dd6b2ce7a7fb7cc66 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Oct 2019 14:28:53 +0100 Subject: [PATCH 37/63] TransferServerCommand: add missing boilerplate permission check --- src/pocketmine/command/defaults/TransferServerCommand.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pocketmine/command/defaults/TransferServerCommand.php b/src/pocketmine/command/defaults/TransferServerCommand.php index ee5821706..c69a8621b 100644 --- a/src/pocketmine/command/defaults/TransferServerCommand.php +++ b/src/pocketmine/command/defaults/TransferServerCommand.php @@ -42,6 +42,10 @@ class TransferServerCommand extends VanillaCommand{ } public function execute(CommandSender $sender, string $commandLabel, array $args){ + if(!$this->testPermission($sender)){ + return true; + } + if(count($args) < 1){ throw new InvalidCommandSyntaxException(); }elseif(!($sender instanceof Player)){ From 0aed7f86f5cb313db3b149b9210341d883d6f4ac Mon Sep 17 00:00:00 2001 From: Stephen Date: Sun, 20 Oct 2019 14:23:07 -0400 Subject: [PATCH 38/63] Updated BossEventPacket comments (#3155) * Updated BossBar comments * Fixed comments --- src/pocketmine/network/mcpe/protocol/BossEventPacket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/network/mcpe/protocol/BossEventPacket.php b/src/pocketmine/network/mcpe/protocol/BossEventPacket.php index 30d07d658..f23c7020b 100644 --- a/src/pocketmine/network/mcpe/protocol/BossEventPacket.php +++ b/src/pocketmine/network/mcpe/protocol/BossEventPacket.php @@ -39,9 +39,9 @@ class BossEventPacket extends DataPacket{ public const TYPE_HIDE = 2; /* C2S: Unregisters a player from a boss fight. */ public const TYPE_UNREGISTER_PLAYER = 3; - /* S2C: Appears not to be implemented. Currently bar percentage only appears to change in response to the target entity's health. */ + /* S2C: Sets the bar percentage. */ public const TYPE_HEALTH_PERCENT = 4; - /* S2C: Also appears to not be implemented. Title client-side sticks as the target entity's nametag, or their entity type name if not set. */ + /* S2C: Sets title of the bar. */ public const TYPE_TITLE = 5; /* S2C: Not sure on this. Includes color and overlay fields, plus an unknown short. TODO: check this */ public const TYPE_UNKNOWN_6 = 6; From 93cb9390e05a67826692a45d5b3fb5f1a89cf347 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 20 Oct 2019 19:59:02 +0100 Subject: [PATCH 39/63] RegionLoader: backport 62185d476bc2463be6de20604cd4ef83733dcce2 --- src/pocketmine/level/format/io/region/RegionLoader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index c6712b422..e6df3bc3e 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -31,7 +31,7 @@ use function array_fill; use function ceil; use function chr; use function fclose; -use function fgetc; +use function feof; use function file_exists; use function filesize; use function fopen; @@ -283,7 +283,7 @@ class RegionLoader{ $fileOffset = $offset << 12; fseek($this->filePointer, $fileOffset); - if(fgetc($this->filePointer) === false){ //Try and read from the location + if(feof($this->filePointer)){ throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset"); }elseif(isset($usedOffsets[$offset])){ self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ); From 20af789963770188de7c7bc4abd74cae865b9d34 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 30 Jan 2019 19:41:20 +0000 Subject: [PATCH 40/63] backport 3e58708130d9a77c261b3a1355fa2e0163a5c7c6: Add some missing @throws annotations --- src/pocketmine/event/Event.php | 2 -- .../inventory/transaction/CraftingTransaction.php | 1 + src/pocketmine/level/format/io/region/RegionLoader.php | 6 ++++++ src/pocketmine/resourcepacks/ResourcePack.php | 1 + src/pocketmine/resourcepacks/ZippedResourcePack.php | 3 ++- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/event/Event.php b/src/pocketmine/event/Event.php index e3bcf871f..015cdaafd 100644 --- a/src/pocketmine/event/Event.php +++ b/src/pocketmine/event/Event.php @@ -78,8 +78,6 @@ abstract class Event{ * Calls event handlers registered for this event. * * @throws \RuntimeException if event call recursion reaches the max depth limit - * - * @throws \ReflectionException */ public function call() : void{ if(self::$eventCallDepth >= self::MAX_EVENT_CALL_DEPTH){ diff --git a/src/pocketmine/inventory/transaction/CraftingTransaction.php b/src/pocketmine/inventory/transaction/CraftingTransaction.php index e91085812..52d5f8c60 100644 --- a/src/pocketmine/inventory/transaction/CraftingTransaction.php +++ b/src/pocketmine/inventory/transaction/CraftingTransaction.php @@ -65,6 +65,7 @@ class CraftingTransaction extends InventoryTransaction{ * @param int $iterations * * @return int + * @throws TransactionValidationException */ protected function matchRecipeItems(array $txItems, array $recipeItems, bool $wildcards, int $iterations = 0) : int{ if(empty($recipeItems)){ diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index e6df3bc3e..7ee7864f2 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -83,6 +83,9 @@ class RegionLoader{ $this->filePath = $filePath; } + /** + * @throws CorruptedRegionException + */ public function open(){ $exists = file_exists($this->filePath); if(!$exists){ @@ -263,6 +266,9 @@ class RegionLoader{ } } + /** + * @throws CorruptedRegionException + */ protected function loadLocationTable(){ fseek($this->filePointer, 0); $this->lastSector = 1; diff --git a/src/pocketmine/resourcepacks/ResourcePack.php b/src/pocketmine/resourcepacks/ResourcePack.php index 06c3b6ce5..c411c8fa6 100644 --- a/src/pocketmine/resourcepacks/ResourcePack.php +++ b/src/pocketmine/resourcepacks/ResourcePack.php @@ -73,6 +73,7 @@ interface ResourcePack{ * @param int $length Maximum length of data to return. * * @return string byte-array + * @throws \InvalidArgumentException if the chunk does not exist */ public function getPackChunk(int $start, int $length) : string; } diff --git a/src/pocketmine/resourcepacks/ZippedResourcePack.php b/src/pocketmine/resourcepacks/ZippedResourcePack.php index d453396b7..0364ccd37 100644 --- a/src/pocketmine/resourcepacks/ZippedResourcePack.php +++ b/src/pocketmine/resourcepacks/ZippedResourcePack.php @@ -75,6 +75,7 @@ class ZippedResourcePack implements ResourcePack{ /** * @param string $zipPath Path to the resource pack zip + * @throws ResourcePackException */ public function __construct(string $zipPath){ $this->path = $zipPath; @@ -150,7 +151,7 @@ class ZippedResourcePack implements ResourcePack{ public function getPackChunk(int $start, int $length) : string{ fseek($this->fileResource, $start); if(feof($this->fileResource)){ - throw new \RuntimeException("Requested a resource pack chunk with invalid start offset"); + throw new \InvalidArgumentException("Requested a resource pack chunk with invalid start offset"); } return fread($this->fileResource, $length); } From 45329ddf67965ebf257580d4805935a141709c66 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Mar 2019 13:10:17 +0000 Subject: [PATCH 41/63] backport 07a9c35ee: RegionLoader: Use objects instead of arrays --- .../level/format/io/region/RegionLoader.php | 72 +++++++------- .../io/region/RegionLocationTableEntry.php | 98 +++++++++++++++++++ 2 files changed, 133 insertions(+), 37 deletions(-) create mode 100644 src/pocketmine/level/format/io/region/RegionLocationTableEntry.php diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index 7ee7864f2..519c1a2ab 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -27,7 +27,6 @@ use pocketmine\level\format\ChunkException; use pocketmine\level\format\io\exception\CorruptedChunkException; use pocketmine\utils\Binary; use pocketmine\utils\MainLogger; -use function array_fill; use function ceil; use function chr; use function fclose; @@ -40,6 +39,7 @@ use function fseek; use function ftruncate; use function fwrite; use function is_resource; +use function max; use function ord; use function pack; use function str_pad; @@ -72,7 +72,7 @@ class RegionLoader{ protected $filePointer; /** @var int */ protected $lastSector; - /** @var int[][] [offset in sectors, chunk size in sectors, timestamp] */ + /** @var RegionLocationTableEntry[] */ protected $locationTable = []; /** @var int */ public $lastUsed = 0; @@ -114,7 +114,7 @@ class RegionLoader{ } protected function isChunkGenerated(int $index) : bool{ - return !($this->locationTable[$index][0] === 0 or $this->locationTable[$index][1] === 0); + return !$this->locationTable[$index]->isNull(); } /** @@ -134,23 +134,25 @@ class RegionLoader{ return null; } - fseek($this->filePointer, $this->locationTable[$index][0] << 12); + fseek($this->filePointer, $this->locationTable[$index]->getFirstSector() << 12); + $prefix = fread($this->filePointer, 4); if($prefix === false or strlen($prefix) !== 4){ throw new CorruptedChunkException("Corrupted chunk header detected (unexpected end of file reading length prefix)"); } $length = Binary::readInt($prefix); - if($length <= 0 or $length > self::MAX_SECTOR_LENGTH){ //Not yet generated / corrupted - if($length >= self::MAX_SECTOR_LENGTH){ - throw new CorruptedChunkException("Corrupted chunk header detected (sector count $length larger than max " . self::MAX_SECTOR_LENGTH . ")"); - } + if($length <= 0){ //TODO: if we reached here, the locationTable probably needs updating return null; } + if($length > self::MAX_SECTOR_LENGTH){ //corrupted + throw new CorruptedChunkException("Length for chunk x=$x,z=$z ($length) is larger than maximum " . self::MAX_SECTOR_LENGTH); + } - if($length > ($this->locationTable[$index][1] << 12)){ //Invalid chunk, bigger than defined number of sectors - MainLogger::getLogger()->error("Chunk x=$x,z=$z length mismatch (expected " . ($this->locationTable[$index][1] << 12) . " sectors, got $length sectors)"); - $this->locationTable[$index][1] = $length >> 12; + if($length > ($this->locationTable[$index]->getSectorCount() << 12)){ //Invalid chunk, bigger than defined number of sectors + MainLogger::getLogger()->error("Chunk x=$x,z=$z length mismatch (expected " . ($this->locationTable[$index]->getSectorCount() << 12) . " sectors, got $length sectors)"); + $old = $this->locationTable[$index]; + $this->locationTable[$index] = new RegionLocationTableEntry($old->getFirstSector(), $length >> 12, time()); $this->writeLocationIndex($index); } @@ -193,26 +195,22 @@ class RegionLoader{ if($length + 4 > self::MAX_SECTOR_LENGTH){ throw new ChunkException("Chunk is too big! " . ($length + 4) . " > " . self::MAX_SECTOR_LENGTH); } - $sectors = (int) ceil(($length + 4) / 4096); + + $newSize = (int) ceil(($length + 4) / 4096); $index = self::getChunkOffset($x, $z); - $indexChanged = false; - if($this->locationTable[$index][1] < $sectors){ - $this->locationTable[$index][0] = $this->lastSector + 1; - $this->lastSector += $sectors; //The GC will clean this shift "later" - $indexChanged = true; - }elseif($this->locationTable[$index][1] != $sectors){ - $indexChanged = true; + $offset = $this->locationTable[$index]->getFirstSector(); + + if($this->locationTable[$index]->getSectorCount() < $newSize){ + $offset = $this->lastSector + 1; } - $this->locationTable[$index][1] = $sectors; - $this->locationTable[$index][2] = time(); + $this->locationTable[$index] = new RegionLocationTableEntry($offset, $newSize, time()); + $this->lastSector = max($this->lastSector, $this->locationTable[$index]->getLastSector()); - fseek($this->filePointer, $this->locationTable[$index][0] << 12); - fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $sectors << 12, "\x00", STR_PAD_RIGHT)); + fseek($this->filePointer, $offset << 12); + fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $newSize << 12, "\x00", STR_PAD_RIGHT)); - if($indexChanged){ - $this->writeLocationIndex($index); - } + $this->writeLocationIndex($index); } /** @@ -223,8 +221,7 @@ class RegionLoader{ */ public function removeChunk(int $x, int $z){ $index = self::getChunkOffset($x, $z); - $this->locationTable[$index][0] = 0; - $this->locationTable[$index][1] = 0; + $this->locationTable[$index] = new RegionLocationTableEntry(0, 0, 0); } /** @@ -284,6 +281,7 @@ class RegionLoader{ for($i = 0; $i < 1024; ++$i){ $index = $data[$i + 1]; $offset = $index >> 8; + $timestamp = $data[$i + 1025]; if($offset !== 0){ self::getChunkCoords($i, $x, $z); $fileOffset = $offset << 12; @@ -299,10 +297,8 @@ class RegionLoader{ } } - $this->locationTable[$i] = [$index >> 8, $index & 0xff, $data[1024 + $i + 1]]; - if(($this->locationTable[$i][0] + $this->locationTable[$i][1] - 1) > $this->lastSector){ - $this->lastSector = $this->locationTable[$i][0] + $this->locationTable[$i][1] - 1; - } + $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); + $this->lastSector = max($this->lastSector, $this->locationTable[$i]->getLastSector()); } fseek($this->filePointer, 0); @@ -312,10 +308,10 @@ class RegionLoader{ $write = []; for($i = 0; $i < 1024; ++$i){ - $write[] = (($this->locationTable[$i][0] << 8) | $this->locationTable[$i][1]); + $write[] = (($this->locationTable[$i]->getFirstSector() << 8) | $this->locationTable[$i]->getSectorCount()); } for($i = 0; $i < 1024; ++$i){ - $write[] = $this->locationTable[$i][2]; + $write[] = $this->locationTable[$i]->getTimestamp(); } fseek($this->filePointer, 0); fwrite($this->filePointer, pack("N*", ...$write), 4096 * 2); @@ -323,16 +319,18 @@ class RegionLoader{ protected function writeLocationIndex($index){ fseek($this->filePointer, $index << 2); - fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index][0] << 8) | $this->locationTable[$index][1]), 4); + fwrite($this->filePointer, Binary::writeInt(($this->locationTable[$index]->getFirstSector() << 8) | $this->locationTable[$index]->getSectorCount()), 4); fseek($this->filePointer, 4096 + ($index << 2)); - fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index][2]), 4); + fwrite($this->filePointer, Binary::writeInt($this->locationTable[$index]->getTimestamp()), 4); } protected function createBlank(){ fseek($this->filePointer, 0); ftruncate($this->filePointer, 8192); // this fills the file with the null byte $this->lastSector = 1; - $this->locationTable = array_fill(0, 1024, [0, 0, 0]); + for($i = 0; $i < 1024; ++$i){ + $this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0); + } } public function getX() : int{ diff --git a/src/pocketmine/level/format/io/region/RegionLocationTableEntry.php b/src/pocketmine/level/format/io/region/RegionLocationTableEntry.php new file mode 100644 index 000000000..f17ae5bdc --- /dev/null +++ b/src/pocketmine/level/format/io/region/RegionLocationTableEntry.php @@ -0,0 +1,98 @@ +firstSector = $firstSector; + if($sectorCount < 0 or $sectorCount > 255){ + throw new \InvalidArgumentException("Sector count must be in range 0...255, got $sectorCount"); + } + $this->sectorCount = $sectorCount; + $this->timestamp = $timestamp; + } + + /** + * @return int + */ + public function getFirstSector() : int{ + return $this->firstSector; + } + + /** + * @return int + */ + public function getLastSector() : int{ + return $this->firstSector + $this->sectorCount - 1; + } + + /** + * Returns an array of sector offsets reserved by this chunk. + * @return int[] + */ + public function getUsedSectors() : array{ + return range($this->getFirstSector(), $this->getLastSector()); + } + + /** + * @return int + */ + public function getSectorCount() : int{ + return $this->sectorCount; + } + + /** + * @return int + */ + public function getTimestamp() : int{ + return $this->timestamp; + } + + /** + * @return bool + */ + public function isNull() : bool{ + return $this->firstSector === 0 or $this->sectorCount === 0; + } +} From 783c13926ff515c95cfe2da3e1e2ed7284f76296 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Mar 2019 13:18:14 +0000 Subject: [PATCH 42/63] backport f2404804d: RegionLoader: clean up lastSector handling --- .../level/format/io/region/RegionLoader.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index 519c1a2ab..733c56993 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -60,6 +60,8 @@ class RegionLoader{ public const MAX_SECTOR_LENGTH = 255 << 12; //255 sectors (~0.996 MiB) public const REGION_HEADER_LENGTH = 8192; //4096 location table + 4096 timestamps + private const FIRST_SECTOR = 2; //location table occupies 0 and 1 + public static $COMPRESSION_LEVEL = 7; /** @var int */ @@ -71,7 +73,7 @@ class RegionLoader{ /** @var resource */ protected $filePointer; /** @var int */ - protected $lastSector; + protected $nextSector = self::FIRST_SECTOR; /** @var RegionLocationTableEntry[] */ protected $locationTable = []; /** @var int */ @@ -201,11 +203,11 @@ class RegionLoader{ $offset = $this->locationTable[$index]->getFirstSector(); if($this->locationTable[$index]->getSectorCount() < $newSize){ - $offset = $this->lastSector + 1; + $offset = $this->nextSector; } $this->locationTable[$index] = new RegionLocationTableEntry($offset, $newSize, time()); - $this->lastSector = max($this->lastSector, $this->locationTable[$index]->getLastSector()); + $this->bumpNextFreeSector($this->locationTable[$index]); fseek($this->filePointer, $offset << 12); fwrite($this->filePointer, str_pad(Binary::writeInt($length) . chr(self::COMPRESSION_ZLIB) . $chunkData, $newSize << 12, "\x00", STR_PAD_RIGHT)); @@ -268,7 +270,6 @@ class RegionLoader{ */ protected function loadLocationTable(){ fseek($this->filePointer, 0); - $this->lastSector = 1; $headerRaw = fread($this->filePointer, self::REGION_HEADER_LENGTH); if(($len = strlen($headerRaw)) !== self::REGION_HEADER_LENGTH){ @@ -298,7 +299,7 @@ class RegionLoader{ } $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); - $this->lastSector = max($this->lastSector, $this->locationTable[$i]->getLastSector()); + $this->bumpNextFreeSector($this->locationTable[$i]); } fseek($this->filePointer, 0); @@ -327,12 +328,15 @@ class RegionLoader{ protected function createBlank(){ fseek($this->filePointer, 0); ftruncate($this->filePointer, 8192); // this fills the file with the null byte - $this->lastSector = 1; for($i = 0; $i < 1024; ++$i){ $this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0); } } + private function bumpNextFreeSector(RegionLocationTableEntry $entry) : void{ + $this->nextSector = max($this->nextSector, $entry->getLastSector()) + 1; + } + public function getX() : int{ return $this->x; } From abdbb2bf0ef37c8737566a94726c6ce021b7c2f6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 5 Mar 2019 13:28:56 +0000 Subject: [PATCH 43/63] backport 3f6660027: RegionLoader: Extract location table validation to separate function --- .../level/format/io/region/RegionLoader.php | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index 733c56993..15d78fc6f 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -277,34 +277,56 @@ class RegionLoader{ } $data = unpack("N*", $headerRaw); - /** @var int[] $usedOffsets */ - $usedOffsets = []; + for($i = 0; $i < 1024; ++$i){ $index = $data[$i + 1]; $offset = $index >> 8; $timestamp = $data[$i + 1025]; - if($offset !== 0){ - self::getChunkCoords($i, $x, $z); - $fileOffset = $offset << 12; - fseek($this->filePointer, $fileOffset); - if(feof($this->filePointer)){ - throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset"); - }elseif(isset($usedOffsets[$offset])){ - self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ); - throw new CorruptedRegionException("Found two chunk offsets (chunk1: x=$existingX,z=$existingZ, chunk2: x=$x,z=$z) pointing to the file location $fileOffset"); - }else{ - $usedOffsets[$offset] = $i; - } + if($offset === 0){ + $this->locationTable[$i] = new RegionLocationTableEntry(0, 0, 0); + }else{ + $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); + $this->bumpNextFreeSector($this->locationTable[$i]); } - - $this->locationTable[$i] = new RegionLocationTableEntry($offset, $index & 0xff, $timestamp); - $this->bumpNextFreeSector($this->locationTable[$i]); } + $this->checkLocationTableValidity(); + fseek($this->filePointer, 0); } + /** + * @throws CorruptedRegionException + */ + private function checkLocationTableValidity() : void{ + /** @var int[] $usedOffsets */ + $usedOffsets = []; + + for($i = 0; $i < 1024; ++$i){ + $entry = $this->locationTable[$i]; + if($entry->isNull()){ + continue; + } + + self::getChunkCoords($i, $x, $z); + $offset = $entry->getFirstSector(); + $fileOffset = $offset << 12; + + //TODO: more validity checks + + fseek($this->filePointer, $fileOffset); + if(feof($this->filePointer)){ + throw new CorruptedRegionException("Region file location offset x=$x,z=$z points to invalid file location $fileOffset"); + } + if(isset($usedOffsets[$offset])){ + self::getChunkCoords($usedOffsets[$offset], $existingX, $existingZ); + throw new CorruptedRegionException("Found two chunk offsets (chunk1: x=$existingX,z=$existingZ, chunk2: x=$x,z=$z) pointing to the file location $fileOffset"); + } + $usedOffsets[$offset] = $i; + } + } + private function writeLocationTable(){ $write = []; From 447477c5fb56804613dccb5ff746dfa8af953080 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Thu, 14 Mar 2019 15:02:15 +0000 Subject: [PATCH 44/63] RegionLoader: Write location table changes when deleting chunks --- src/pocketmine/level/format/io/region/RegionLoader.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pocketmine/level/format/io/region/RegionLoader.php b/src/pocketmine/level/format/io/region/RegionLoader.php index 15d78fc6f..6c64a2489 100644 --- a/src/pocketmine/level/format/io/region/RegionLoader.php +++ b/src/pocketmine/level/format/io/region/RegionLoader.php @@ -224,6 +224,7 @@ class RegionLoader{ public function removeChunk(int $x, int $z){ $index = self::getChunkOffset($x, $z); $this->locationTable[$index] = new RegionLocationTableEntry(0, 0, 0); + $this->writeLocationIndex($index); } /** From cff2d37add390ba8d17ee931663f980dd86c8092 Mon Sep 17 00:00:00 2001 From: Frago9876543210 Date: Wed, 18 Sep 2019 13:10:42 +0300 Subject: [PATCH 45/63] backport ec0558597b6ca948228846b25751c2b1863cbf3f: CommandParameter: change byte1 field to "flags" (#3115) --- .../network/mcpe/protocol/AvailableCommandsPacket.php | 4 ++-- .../network/mcpe/protocol/types/CommandParameter.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index e61668c2c..60d56d187 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -227,7 +227,7 @@ class AvailableCommandsPacket extends DataPacket{ $parameter->paramName = $this->getString(); $parameter->paramType = $this->getLInt(); $parameter->isOptional = $this->getBool(); - $parameter->byte1 = $this->getByte(); + $parameter->flags = $this->getByte(); if($parameter->paramType & self::ARG_FLAG_ENUM){ $index = ($parameter->paramType & 0xffff); @@ -285,7 +285,7 @@ class AvailableCommandsPacket extends DataPacket{ $this->putLInt($type); $this->putBool($parameter->isOptional); - $this->putByte($parameter->byte1); + $this->putByte($parameter->flags); } } } diff --git a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php index 2c26ac9bf..b1a00137b 100644 --- a/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php +++ b/src/pocketmine/network/mcpe/protocol/types/CommandParameter.php @@ -31,7 +31,7 @@ class CommandParameter{ /** @var bool */ public $isOptional; /** @var int */ - public $byte1 = 0; //unknown, always zero except for in /gamerule command + public $flags = 0; //shows enum name if 1, always zero except for in /gamerule command /** @var CommandEnum|null */ public $enum; /** @var string|null */ From 7d5c3c9b46ac03a2b97a262759d466b2fc9c3605 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Wed, 12 Jun 2019 16:54:30 +0100 Subject: [PATCH 46/63] backport 4364d2a94: AvailableCommandsPacket: Clean up internals this is still disgusting, but it's a little more bearable now. --- .../mcpe/protocol/AvailableCommandsPacket.php | 190 ++++++++++-------- 1 file changed, 102 insertions(+), 88 deletions(-) diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 60d56d187..41224eb72 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -29,11 +29,6 @@ use pocketmine\network\mcpe\NetworkSession; use pocketmine\network\mcpe\protocol\types\CommandData; use pocketmine\network\mcpe\protocol\types\CommandEnum; use pocketmine\network\mcpe\protocol\types\CommandParameter; -use function array_flip; -use function array_keys; -use function array_map; -use function array_search; -use function array_values; use function count; use function dechex; @@ -83,30 +78,6 @@ class AvailableCommandsPacket extends DataPacket{ */ public const ARG_FLAG_POSTFIX = 0x1000000; - /** - * @var string[] - * A list of every single enum value for every single command in the packet, including alias names. - */ - public $enumValues = []; - /** @var int */ - private $enumValuesCount = 0; - - /** - * @var string[] - * A list of argument postfixes. Used for the /xp command's L. - */ - public $postfixes = []; - - /** - * @var CommandEnum[] - * List of command enums, from command aliases to argument enums. - */ - public $enums = []; - /** - * @var int[] string => int map of enum name to index - */ - private $enumMap = []; - /** * @var CommandData[] * List of command data, including name, description, alias indexes and parameters. @@ -121,20 +92,26 @@ class AvailableCommandsPacket extends DataPacket{ public $softEnums = []; protected function decodePayload(){ - for($i = 0, $this->enumValuesCount = $this->getUnsignedVarInt(); $i < $this->enumValuesCount; ++$i){ - $this->enumValues[] = $this->getString(); + /** @var string[] $enumValues */ + $enumValues = []; + for($i = 0, $enumValuesCount = $this->getUnsignedVarInt(); $i < $enumValuesCount; ++$i){ + $enumValues[] = $this->getString(); + } + + /** @var string[] $postfixes */ + $postfixes = []; + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $postfixes[] = $this->getString(); + } + + /** @var CommandEnum[] $enums */ + $enums = []; + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ + $enums[] = $this->getEnum($enumValues); } for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ - $this->postfixes[] = $this->getString(); - } - - for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ - $this->enums[] = $this->getEnum(); - } - - for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ - $this->commandData[] = $this->getCommandData(); + $this->commandData[] = $this->getCommandData($enums, $postfixes); } for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ @@ -142,17 +119,26 @@ class AvailableCommandsPacket extends DataPacket{ } } - protected function getEnum() : CommandEnum{ + /** + * @param string[] $enumValueList + * + * @return CommandEnum + * @throws \UnexpectedValueException + * @throws BinaryDataException + */ + protected function getEnum(array $enumValueList) : CommandEnum{ $retval = new CommandEnum(); $retval->enumName = $this->getString(); + $listSize = count($enumValueList); + for($i = 0, $count = $this->getUnsignedVarInt(); $i < $count; ++$i){ - $index = $this->getEnumValueIndex(); - if(!isset($this->enumValues[$index])){ + $index = $this->getEnumValueIndex($listSize); + if(!isset($enumValueList[$index])){ throw new \UnexpectedValueException("Invalid enum value index $index"); } //Get the enum value from the initial pile of mess - $retval->enumValues[] = $this->enumValues[$index]; + $retval->enumValues[] = $enumValueList[$index]; } return $retval; @@ -170,17 +156,21 @@ class AvailableCommandsPacket extends DataPacket{ return $retval; } - protected function putEnum(CommandEnum $enum){ + /** + * @param CommandEnum $enum + * @param string[] $enumValueMap + */ + protected function putEnum(CommandEnum $enum, array $enumValueMap) : void{ $this->putString($enum->enumName); $this->putUnsignedVarInt(count($enum->enumValues)); + $listSize = count($enumValueMap); foreach($enum->enumValues as $value){ - //Dumb bruteforce search. I hate this packet. - $index = array_search($value, $this->enumValues, true); - if($index === false){ + $index = $enumValueMap[$value] ?? -1; + if($index === -1){ throw new \InvalidStateException("Enum value '$value' not found"); } - $this->putEnumValueIndex($index); + $this->putEnumValueIndex($index, $listSize); } } @@ -193,33 +183,47 @@ class AvailableCommandsPacket extends DataPacket{ } } - protected function getEnumValueIndex() : int{ - if($this->enumValuesCount < 256){ + /** + * @param int $valueCount + * + * @return int + * @throws BinaryDataException + */ + protected function getEnumValueIndex(int $valueCount) : int{ + if($valueCount < 256){ return $this->getByte(); - }elseif($this->enumValuesCount < 65536){ + }elseif($valueCount < 65536){ return $this->getLShort(); }else{ return $this->getLInt(); } } - protected function putEnumValueIndex(int $index){ - if($this->enumValuesCount < 256){ + protected function putEnumValueIndex(int $index, int $valueCount) : void{ + if($valueCount < 256){ $this->putByte($index); - }elseif($this->enumValuesCount < 65536){ + }elseif($valueCount < 65536){ $this->putLShort($index); }else{ $this->putLInt($index); } } - protected function getCommandData() : CommandData{ + /** + * @param CommandEnum[] $enums + * @param string[] $postfixes + * + * @return CommandData + * @throws \UnexpectedValueException + * @throws BinaryDataException + */ + protected function getCommandData(array $enums, array $postfixes) : CommandData{ $retval = new CommandData(); $retval->commandName = $this->getString(); $retval->commandDescription = $this->getString(); $retval->flags = $this->getByte(); $retval->permission = $this->getByte(); - $retval->aliases = $this->enums[$this->getLInt()] ?? null; + $retval->aliases = $enums[$this->getLInt()] ?? null; for($overloadIndex = 0, $overloadCount = $this->getUnsignedVarInt(); $overloadIndex < $overloadCount; ++$overloadIndex){ for($paramIndex = 0, $paramCount = $this->getUnsignedVarInt(); $paramIndex < $paramCount; ++$paramIndex){ @@ -231,13 +235,13 @@ class AvailableCommandsPacket extends DataPacket{ if($parameter->paramType & self::ARG_FLAG_ENUM){ $index = ($parameter->paramType & 0xffff); - $parameter->enum = $this->enums[$index] ?? null; + $parameter->enum = $enums[$index] ?? null; if($parameter->enum === null){ throw new \UnexpectedValueException("deserializing $retval->commandName parameter $parameter->paramName: expected enum at $index, but got none"); } }elseif($parameter->paramType & self::ARG_FLAG_POSTFIX){ $index = ($parameter->paramType & 0xffff); - $parameter->postfix = $this->postfixes[$index] ?? null; + $parameter->postfix = $postfixes[$index] ?? null; if($parameter->postfix === null){ throw new \UnexpectedValueException("deserializing $retval->commandName parameter $parameter->paramName: expected postfix at $index, but got none"); } @@ -252,14 +256,19 @@ class AvailableCommandsPacket extends DataPacket{ return $retval; } - protected function putCommandData(CommandData $data){ + /** + * @param CommandData $data + * @param int[] $enumIndexes string enum name -> int index + * @param int[] $postfixIndexes + */ + protected function putCommandData(CommandData $data, array $enumIndexes, array $postfixIndexes) : void{ $this->putString($data->commandName); $this->putString($data->commandDescription); $this->putByte($data->flags); $this->putByte($data->permission); if($data->aliases !== null){ - $this->putLInt($this->enumMap[$data->aliases->enumName] ?? -1); + $this->putLInt($enumIndexes[$data->aliases->enumName] ?? -1); }else{ $this->putLInt(-1); } @@ -272,10 +281,10 @@ class AvailableCommandsPacket extends DataPacket{ $this->putString($parameter->paramName); if($parameter->enum !== null){ - $type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($this->enumMap[$parameter->enum->enumName] ?? -1); + $type = self::ARG_FLAG_ENUM | self::ARG_FLAG_VALID | ($enumIndexes[$parameter->enum->enumName] ?? -1); }elseif($parameter->postfix !== null){ - $key = array_search($parameter->postfix, $this->postfixes, true); - if($key === false){ + $key = $postfixIndexes[$parameter->postfix] ?? -1; + if($key === -1){ throw new \InvalidStateException("Postfix '$parameter->postfix' not in postfixes array"); } $type = self::ARG_FLAG_POSTFIX | $key; @@ -290,7 +299,7 @@ class AvailableCommandsPacket extends DataPacket{ } } - private function argTypeToString(int $argtype) : string{ + private function argTypeToString(int $argtype, array $postfixes) : string{ if($argtype & self::ARG_FLAG_VALID){ if($argtype & self::ARG_FLAG_ENUM){ return "stringenum (" . ($argtype & 0xffff) . ")"; @@ -319,7 +328,7 @@ class AvailableCommandsPacket extends DataPacket{ return "command"; } }elseif($argtype & self::ARG_FLAG_POSTFIX){ - $postfix = $this->postfixes[$argtype & 0xffff]; + $postfix = $postfixes[$argtype & 0xffff]; return "int (postfix $postfix)"; }else{ @@ -330,15 +339,22 @@ class AvailableCommandsPacket extends DataPacket{ } protected function encodePayload(){ - $enumValuesMap = []; - $postfixesMap = []; - $enumMap = []; + /** @var int[] $enumValueIndexes */ + $enumValueIndexes = []; + /** @var int[] $postfixIndexes */ + $postfixIndexes = []; + /** @var int[] $enumIndexes */ + $enumIndexes = []; + /** @var CommandEnum[] $enums */ + $enums = []; foreach($this->commandData as $commandData){ if($commandData->aliases !== null){ - $enumMap[$commandData->aliases->enumName] = $commandData->aliases; + if(!isset($enumIndexes[$commandData->aliases->enumName])){ + $enums[$enumIndexes[$commandData->aliases->enumName] = count($enumIndexes)] = $commandData->aliases; + } foreach($commandData->aliases->enumValues as $str){ - $enumValuesMap[$str] = true; + $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); //latest index } } @@ -349,41 +365,39 @@ class AvailableCommandsPacket extends DataPacket{ */ foreach($overload as $parameter){ if($parameter->enum !== null){ - $enumMap[$parameter->enum->enumName] = $parameter->enum; + if(!isset($enumIndexes[$parameter->enum->enumName])){ + $enums[$enumIndexes[$parameter->enum->enumName] = count($enumIndexes)] = $parameter->enum; + } foreach($parameter->enum->enumValues as $str){ - $enumValuesMap[$str] = true; + $enumValueIndexes[$str] = $enumValueIndexes[$str] ?? count($enumValueIndexes); } } if($parameter->postfix !== null){ - $postfixesMap[$parameter->postfix] = true; + $postfixIndexes[$parameter->postfix] = $postfixIndexes[$parameter->postfix] ?? count($postfixIndexes); } } } } - $this->enumValues = array_map('\strval', array_keys($enumValuesMap)); //stupid PHP key casting D: - $this->putUnsignedVarInt($this->enumValuesCount = count($this->enumValues)); - foreach($this->enumValues as $enumValue){ - $this->putString($enumValue); + $this->putUnsignedVarInt(count($enumValueIndexes)); + foreach($enumValueIndexes as $enumValue => $index){ + $this->putString((string) $enumValue); //stupid PHP key casting D: } - $this->postfixes = array_map('\strval', array_keys($postfixesMap)); - $this->putUnsignedVarInt(count($this->postfixes)); - foreach($this->postfixes as $postfix){ - $this->putString($postfix); + $this->putUnsignedVarInt(count($postfixIndexes)); + foreach($postfixIndexes as $postfix => $index){ + $this->putString((string) $postfix); //stupid PHP key casting D: } - $this->enums = array_values($enumMap); - $this->enumMap = array_flip(array_keys($enumMap)); - $this->putUnsignedVarInt(count($this->enums)); - foreach($this->enums as $enum){ - $this->putEnum($enum); + $this->putUnsignedVarInt(count($enums)); + foreach($enums as $enum){ + $this->putEnum($enum, $enumValueIndexes); } $this->putUnsignedVarInt(count($this->commandData)); foreach($this->commandData as $data){ - $this->putCommandData($data); + $this->putCommandData($data, $enumIndexes, $postfixIndexes); } $this->putUnsignedVarInt(count($this->softEnums)); From bb05cfb36c4c7decc23f6a981397a4ed65fd08e2 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 21 Oct 2019 15:21:22 +0100 Subject: [PATCH 47/63] Shears: fixed always-false hardness check thanks PHPStan --- src/pocketmine/item/Shears.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/item/Shears.php b/src/pocketmine/item/Shears.php index 04a5b9d55..f2dfb345f 100644 --- a/src/pocketmine/item/Shears.php +++ b/src/pocketmine/item/Shears.php @@ -48,7 +48,7 @@ class Shears extends Tool{ } public function onDestroyBlock(Block $block) : bool{ - if($block->getHardness() === 0 or $block->isCompatibleWithTool($this)){ + if($block->getHardness() === 0.0 or $block->isCompatibleWithTool($this)){ return $this->applyDamage(1); } return false; From f347345bb3e62b810e72bd21ffceb93f69db6968 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 21 Oct 2019 15:25:57 +0100 Subject: [PATCH 48/63] Human::getInventory(): explicitly declare return type the lack of this causes type inference bugs and documentation problems. thanks PHPStan --- src/pocketmine/entity/Human.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index b5fb32263..0a9def938 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -587,6 +587,9 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ return (int) min(100, 7 * $this->getXpLevel()); } + /** + * @return PlayerInventory + */ public function getInventory(){ return $this->inventory; } From 39cc590829dbdcce64f6ecb0953e69d60d93364a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 21 Oct 2019 22:26:48 +0100 Subject: [PATCH 49/63] Skin: accommodate JSON geometry containing comments, closes #3121 --- src/pocketmine/entity/Skin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/entity/Skin.php b/src/pocketmine/entity/Skin.php index 2c66dfaee..d5a1477ea 100644 --- a/src/pocketmine/entity/Skin.php +++ b/src/pocketmine/entity/Skin.php @@ -23,9 +23,9 @@ declare(strict_types=1); namespace pocketmine\entity; +use Ahc\Json\Comment as CommentedJsonDecoder; use function implode; use function in_array; -use function json_decode; use function json_encode; use function strlen; @@ -129,7 +129,7 @@ class Skin{ */ public function debloatGeometryData() : void{ if($this->geometryData !== ""){ - $this->geometryData = (string) json_encode(json_decode($this->geometryData)); + $this->geometryData = (string) json_encode((new CommentedJsonDecoder())->decode($this->geometryData)); } } } From c3872619cda36fa6c8fb940a08e974e4d74c2990 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 21 Oct 2019 15:28:20 +0100 Subject: [PATCH 50/63] Block: mark boundingBox as 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 5646c8af1..0ed6eb803 100644 --- a/src/pocketmine/block/Block.php +++ b/src/pocketmine/block/Block.php @@ -69,7 +69,7 @@ class Block extends Position implements BlockIds, Metadatable{ /** @var int|null */ protected $itemId; - /** @var AxisAlignedBB */ + /** @var AxisAlignedBB|null */ protected $boundingBox = null; From eda3d9b5e408180787c94b615e18bfaa5612d5ba Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:13:47 +0100 Subject: [PATCH 51/63] sync composer dependencies --- composer.lock | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/composer.lock b/composer.lock index 1aa668766..a3eea84d6 100644 --- a/composer.lock +++ b/composer.lock @@ -92,16 +92,16 @@ }, { "name": "pocketmine/binaryutils", - "version": "0.1.9", + "version": "0.1.10", "source": { "type": "git", "url": "https://github.com/pmmp/BinaryUtils.git", - "reference": "8b3b1160679398387cb896fd5d06018413437dfa" + "reference": "435f2ee265bce75ef1aa9563f9b60ff36d705e80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/8b3b1160679398387cb896fd5d06018413437dfa", - "reference": "8b3b1160679398387cb896fd5d06018413437dfa", + "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/435f2ee265bce75ef1aa9563f9b60ff36d705e80", + "reference": "435f2ee265bce75ef1aa9563f9b60ff36d705e80", "shasum": "" }, "require": { @@ -119,23 +119,23 @@ ], "description": "Classes and methods for conveniently handling binary data", "support": { - "source": "https://github.com/pmmp/BinaryUtils/tree/0.1.9", + "source": "https://github.com/pmmp/BinaryUtils/tree/0.1.10", "issues": "https://github.com/pmmp/BinaryUtils/issues" }, - "time": "2019-07-22T13:15:53+00:00" + "time": "2019-10-21T14:40:32+00:00" }, { "name": "pocketmine/math", - "version": "0.2.2", + "version": "0.2.3", "source": { "type": "git", "url": "https://github.com/pmmp/Math.git", - "reference": "b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c" + "reference": "68be8a79fd0169043ef514797c304517cb8a6071" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/Math/zipball/b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c", - "reference": "b755d3fb7025c4ddb7d9d6df0ba7e0b65125e51c", + "url": "https://api.github.com/repos/pmmp/Math/zipball/68be8a79fd0169043ef514797c304517cb8a6071", + "reference": "68be8a79fd0169043ef514797c304517cb8a6071", "shasum": "" }, "require": { @@ -153,23 +153,23 @@ ], "description": "PHP library containing math related code used in PocketMine-MP", "support": { - "source": "https://github.com/pmmp/Math/tree/0.2.2", + "source": "https://github.com/pmmp/Math/tree/0.2.3", "issues": "https://github.com/pmmp/Math/issues" }, - "time": "2019-01-04T15:42:36+00:00" + "time": "2019-10-21T14:35:10+00:00" }, { "name": "pocketmine/nbt", - "version": "0.2.10", + "version": "0.2.11", "source": { "type": "git", "url": "https://github.com/pmmp/NBT.git", - "reference": "2db27aebe7dc89772aaa8df53361eef801f60063" + "reference": "78784b93632c51f0fad0719b2d6ffe072529db6d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pmmp/NBT/zipball/2db27aebe7dc89772aaa8df53361eef801f60063", - "reference": "2db27aebe7dc89772aaa8df53361eef801f60063", + "url": "https://api.github.com/repos/pmmp/NBT/zipball/78784b93632c51f0fad0719b2d6ffe072529db6d", + "reference": "78784b93632c51f0fad0719b2d6ffe072529db6d", "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.10", + "source": "https://github.com/pmmp/NBT/tree/0.2.11", "issues": "https://github.com/pmmp/NBT/issues" }, - "time": "2019-07-22T15:22:23+00:00" + "time": "2019-10-21T14:50:43+00:00" }, { "name": "pocketmine/raklib", From f63857deed48149e60c525e8a7f1b0ae53138f8b Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:15:29 +0100 Subject: [PATCH 52/63] update build/php submodule to pmmp/php-build-scripts@1b3fe3120cac93ef8d821a1c62a3722576fcfd81 --- build/php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/php b/build/php index ffc465f4f..1b3fe3120 160000 --- a/build/php +++ b/build/php @@ -1 +1 @@ -Subproject commit ffc465f4f806269138fc210832500c51fdecd471 +Subproject commit 1b3fe3120cac93ef8d821a1c62a3722576fcfd81 From acaa0e33b0e378d7da9a5bf92bbba96494c2f557 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:16:44 +0100 Subject: [PATCH 53/63] update DevTools submodule to pmmp/PocketMine-DevTools@3fadb2c3f45a528a715733ba41c273289ef8ffb1 --- tests/plugins/PocketMine-DevTools | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugins/PocketMine-DevTools b/tests/plugins/PocketMine-DevTools index c0f0f9383..3fadb2c3f 160000 --- a/tests/plugins/PocketMine-DevTools +++ b/tests/plugins/PocketMine-DevTools @@ -1 +1 @@ -Subproject commit c0f0f9383d27d0efb2c1d04ea3678beb6a14d3af +Subproject commit 3fadb2c3f45a528a715733ba41c273289ef8ffb1 From 305c63ba4d19715b8f488136be26f7eeed3c6099 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:21:17 +0100 Subject: [PATCH 54/63] MainLogger: initialize shutdown field in the conventional manner this avoids uninitialized uses --- src/pocketmine/utils/MainLogger.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pocketmine/utils/MainLogger.php b/src/pocketmine/utils/MainLogger.php index 7f7615a08..9882392dc 100644 --- a/src/pocketmine/utils/MainLogger.php +++ b/src/pocketmine/utils/MainLogger.php @@ -61,7 +61,7 @@ class MainLogger extends \AttachableThreadedLogger{ /** @var \Threaded */ protected $logStream; /** @var bool */ - protected $shutdown; + protected $shutdown = false; /** @var bool */ protected $logDebug; /** @var MainLogger */ @@ -344,7 +344,6 @@ class MainLogger extends \AttachableThreadedLogger{ } public function run(){ - $this->shutdown = false; $logResource = fopen($this->logFile, "ab"); if(!is_resource($logResource)){ throw new \RuntimeException("Couldn't open log file"); From cc3285c8fe3706ec029015bcdbbd431b586a6c3a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:25:24 +0100 Subject: [PATCH 55/63] Chest: fixed type doc of doubleChestInventory field --- src/pocketmine/tile/Chest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/tile/Chest.php b/src/pocketmine/tile/Chest.php index 1eb109b0d..f8e57ea19 100644 --- a/src/pocketmine/tile/Chest.php +++ b/src/pocketmine/tile/Chest.php @@ -42,7 +42,7 @@ class Chest extends Spawnable implements InventoryHolder, Container, Nameable{ /** @var ChestInventory */ protected $inventory; - /** @var DoubleChestInventory */ + /** @var DoubleChestInventory|null */ protected $doubleInventory = null; /** @var int|null */ From e198c8fa8b053630277b632b1d5c6649772511c0 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:26:49 +0100 Subject: [PATCH 56/63] Task: mark taskHandler field as nullable --- src/pocketmine/scheduler/Task.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/scheduler/Task.php b/src/pocketmine/scheduler/Task.php index c5851b587..f2ad1d862 100644 --- a/src/pocketmine/scheduler/Task.php +++ b/src/pocketmine/scheduler/Task.php @@ -27,7 +27,7 @@ use pocketmine\utils\Utils; abstract class Task{ - /** @var TaskHandler */ + /** @var TaskHandler|null */ private $taskHandler = null; /** From 43ebb23085290ed41e4b5ccd46f327b71bbebda6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 10:42:22 +0100 Subject: [PATCH 57/63] Permission: remove dead code from loadPermission() --- src/pocketmine/permission/Permission.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/pocketmine/permission/Permission.php b/src/pocketmine/permission/Permission.php index 38a3cc132..d1eba9dce 100644 --- a/src/pocketmine/permission/Permission.php +++ b/src/pocketmine/permission/Permission.php @@ -112,12 +112,7 @@ class Permission{ $desc = null; $children = []; if(isset($data["default"])){ - $value = Permission::getByName($data["default"]); - if($value !== null){ - $default = $value; - }else{ - throw new \InvalidStateException("'default' key contained unknown value"); - } + $default = Permission::getByName($data["default"]); } if(isset($data["children"])){ From 77d8f133f1c775ecce2a33a02dc68d8c7da98e85 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 11:54:37 +0100 Subject: [PATCH 58/63] LevelChunkPacket: fixed broken type assert in withCache() --- src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php b/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php index e1d79f2f6..008d26bf3 100644 --- a/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php +++ b/src/pocketmine/network/mcpe/protocol/LevelChunkPacket.php @@ -57,7 +57,7 @@ class LevelChunkPacket extends DataPacket/* implements ClientboundPacket*/{ } public static function withCache(int $chunkX, int $chunkZ, int $subChunkCount, array $usedBlobHashes, string $extraPayload) : self{ - (static function(int ...$hashes){})($usedBlobHashes); + (static function(int ...$hashes){})(...$usedBlobHashes); $result = new self; $result->chunkX = $chunkX; $result->chunkZ = $chunkZ; From f0c36f3413f047afc7df6aa6b653c0ebed1164c1 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 11:57:04 +0100 Subject: [PATCH 59/63] ClientCacheMissResponsePacket: fix broken type assert in create() ouch! PhpStorm never saw these... --- .../network/mcpe/protocol/ClientCacheMissResponsePacket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/ClientCacheMissResponsePacket.php b/src/pocketmine/network/mcpe/protocol/ClientCacheMissResponsePacket.php index 456f29419..1118181d1 100644 --- a/src/pocketmine/network/mcpe/protocol/ClientCacheMissResponsePacket.php +++ b/src/pocketmine/network/mcpe/protocol/ClientCacheMissResponsePacket.php @@ -42,7 +42,7 @@ class ClientCacheMissResponsePacket extends DataPacket/* implements ClientboundP */ public static function create(array $blobs) : self{ //type check - (static function(ChunkCacheBlob ...$blobs){})($blobs); + (static function(ChunkCacheBlob ...$blobs){})(...$blobs); $result = new self; $result->blobs = $blobs; From da17ade575273ddfb628ce340f6afcb3923f6010 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 12:23:01 +0100 Subject: [PATCH 60/63] AvailableCommandsPacket: fixed wrong parameter type doc for putEnum() --- .../network/mcpe/protocol/AvailableCommandsPacket.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php index 41224eb72..89295717e 100644 --- a/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php +++ b/src/pocketmine/network/mcpe/protocol/AvailableCommandsPacket.php @@ -158,7 +158,7 @@ class AvailableCommandsPacket extends DataPacket{ /** * @param CommandEnum $enum - * @param string[] $enumValueMap + * @param int[] $enumValueMap string enum name -> int index */ protected function putEnum(CommandEnum $enum, array $enumValueMap) : void{ $this->putString($enum->enumName); From 29f002b32c2088a2521a688a843cfb9e1253e916 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 12:23:42 +0100 Subject: [PATCH 61/63] LightUpdate: fixed type doc for updateNodes field --- src/pocketmine/level/light/LightUpdate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/level/light/LightUpdate.php b/src/pocketmine/level/light/LightUpdate.php index 22c7fe18b..a2c4bc45e 100644 --- a/src/pocketmine/level/light/LightUpdate.php +++ b/src/pocketmine/level/light/LightUpdate.php @@ -34,7 +34,7 @@ abstract class LightUpdate{ /** @var ChunkManager */ protected $level; - /** @var int[] blockhash => new light level */ + /** @var int[][] blockhash => [x, y, z, new light level] */ protected $updateNodes = []; /** @var \SplQueue */ From d1b70bd4003b2a1e77c3c7eedbddcf9fc4ec0638 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 14:38:02 +0100 Subject: [PATCH 62/63] Release 3.9.6 --- changelogs/3.9.md | 26 ++++++++++++++++++++++++++ src/pocketmine/VersionInfo.php | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/changelogs/3.9.md b/changelogs/3.9.md index 9e91d7c04..0618aef71 100644 --- a/changelogs/3.9.md +++ b/changelogs/3.9.md @@ -74,3 +74,29 @@ Plugin developers should **only** update their required API to this version if y - Fixed some issues with multiple consecutive commas inside quotes in form responses. - Fixed server crash when the manifest json does not contain a json object in a resource pack. - Ender pearls no longer collide with blocks that do not have any collision boxes. + +# 3.9.6 +- Updated Composer dependencies to their latest versions. +- Prevent clients repeating the resource pack sequence. This fixes error spam with bugged 1.12 clients. +- `Internet::simpleCurl()` now includes the PocketMine-MP version in the user-agent string. +- Spawn protection is now disabled by default in the setup wizard. +- Default difficulty is now NORMAL(2) instead of EASY(1). +- Fixed crashing on corrupted world manifest and unsupported world formats. +- Fixed `/transferserver` being usable without appropriate permissions. +- `RegionLoader->removeChunk()` now writes the region header as appropriate. +- Fixed performance issue when loading large regions (bug in header validation). +- Fixed skin geometry being removed when the JSON contained comments. +- Added new constants to `EventPacket`. +- Added encode/decode for `StructureTemplateDataExportRequestPacket` and `StructureTemplateDataExportResponsePacket`. +- Fixed broken type asserts in `LevelChunkPacket::withCache()` and `ClientCacheMissResponsePacket::create()`. +- `types\CommandParameter` field `byte1` has been renamed to `flags`. +- Cleaned up public interface of `AvailableCommandsPacket`, removing fields which exposed details of the encoding scheme. +- Improved documentation for the following API methods: + - `pocketmine\item\Item`: + - `addCreativeItem()` + - `removeCreativeItem()` + - `clearCreativeItems()` + - `pocketmine\level\Explosion`: + - `explodeA()` + - `explodeB()` +- Fixed various cosmetic documentation inconsistencies in the core and dependencies. \ No newline at end of file diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 2ccede412..08f23277a 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -23,5 +23,5 @@ namespace pocketmine; const NAME = "PocketMine-MP"; const BASE_VERSION = "3.9.6"; -const IS_DEVELOPMENT_BUILD = true; +const IS_DEVELOPMENT_BUILD = false; const BUILD_NUMBER = 0; From 3d840e969dc8aa54b540cc66a458d4e84f2cb069 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 22 Oct 2019 14:38:02 +0100 Subject: [PATCH 63/63] 3.9.7 is next --- src/pocketmine/VersionInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pocketmine/VersionInfo.php b/src/pocketmine/VersionInfo.php index 08f23277a..fd7e7bd86 100644 --- a/src/pocketmine/VersionInfo.php +++ b/src/pocketmine/VersionInfo.php @@ -22,6 +22,6 @@ namespace pocketmine; const NAME = "PocketMine-MP"; -const BASE_VERSION = "3.9.6"; -const IS_DEVELOPMENT_BUILD = false; +const BASE_VERSION = "3.9.7"; +const IS_DEVELOPMENT_BUILD = true; const BUILD_NUMBER = 0;